Skip to content

Commit

Permalink
Merge pull request #3247 from opral/parjs-264
Browse files Browse the repository at this point in the history
Make paraglide files available via Virtual module
  • Loading branch information
samuelstroschein authored Dec 11, 2024
2 parents eda5329 + 2a81c4e commit aa496e4
Show file tree
Hide file tree
Showing 28 changed files with 512 additions and 199 deletions.
46 changes: 46 additions & 0 deletions .changeset/silly-wombats-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
"@inlang/paraglide-sveltekit": minor
"@inlang/paraglide-vite": minor
"@inlang/paraglide-unplugin": minor
"@inlang/paraglide-astro": minor
"@inlang/paraglide-webpack": minor
---

Add `experimentalUseVirtualModules` option to use the `$paraglide` virtual module instead of writing files to disk. Closes https://github.com/opral/inlang-paraglide-js/issues/264

- good for projects that can't have `allowJs: true` in their TypeScript config https://github.com/opral/inlang-paraglide-js/issues/238
- less clutter in the compiled output directory https://github.com/opral/inlang-paraglide-js/issues/189


```diff
import { paraglide } from "@inlang/paraglide-sveltekit/vite"
import { defineConfig } from "vite"

export default defineConfig({
plugins: [
paraglide({
project: "./project.inlang",
outdir: "./src/lib/paraglide",
+ experimentalUseVirtualModules: true,
}),
// ... other vite plugins
],
})
```

The compiled output will only emit the `runtime.d.ts` and `messages.d.ts` files.

```diff
.
└── src/
└── paraglide/
- ├── messages/
- │ ├── de.js
- │ ├── en.js
- │ ├── fr.js
- │ └── ...
- ├── messages.js
+ ├── messages.d.ts
- └── runtime.js
+ ├── runtime.d.ts
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"allowJs": true,
"checkJs": true,
"outDir": "dist",
"skipLibCheck": true,
"strict": true,
"lib": ["ESNext", "DOM"]
}
Expand Down
3 changes: 2 additions & 1 deletion inlang/source-code/paraglide/paraglide-sveltekit/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ node_modules
.svelte-kit
dist
.vercel
src/meta.js
src/meta.js
paraglide.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
build
node_modules
.vercel
dist
dist
paraglide
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"dependencies": {
"@inlang/paraglide-sveltekit": "workspace:*"
},
"peerDependencies": {
"typescript": "^4||^5"
},
"devDependencies": {
"@inlang/paraglide-js": "workspace:*",
"@sveltejs/adapter-node": "^5.0.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// <reference types="../paraglide.d.ts" />
import type { AvailableLanguageTag } from "$lib/paraglide/runtime"
import type { ParaglideLocals } from "@inlang/paraglide-sveltekit"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default defineConfig({
paraglide({
project: "./project.inlang",
outdir: "./src/lib/paraglide",
experimentalUseVirtualModules: true,
}),
sveltekit(),
visualizer({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ export interface Config extends VitePluginUserConfig {
*/
export function resolveConfig(userConfig: UserConfig): Config {
const fullConfig: Config = {
project: userConfig.project,
outdir: userConfig.outdir,
silent: userConfig.silent,

...userConfig,
disablePreprocessor: userConfig.disablePreprocessor ?? false,
}

Expand Down
2 changes: 2 additions & 0 deletions inlang/source-code/paraglide/paraglide-unplugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
paraglide.d.ts
outdir
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"my_message": "Meine Nachricht"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"my_message": "My Message"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dbc30ac1d7287afeb3145164d6367a05f4990c71f9f057f0ac5baa5cd32b8ff0
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://inlang.com/schema/project-settings",
"sourceLanguageTag": "en",
"languageTags": ["en", "de"],
"modules": [
"../../plugins/inlang-message-format/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@latest/dist/index.js"
],
"plugin.inlang.messageFormat": {
"pathPattern": "./messages/{languageTag}.json"
},
"experimental": {
"aliases": true
}
}
59 changes: 59 additions & 0 deletions inlang/source-code/paraglide/paraglide-unplugin/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Logger } from "@inlang/paraglide-js/internal"
import path from "node:path"

export type UserConfig = {
/**
* Path to the inlang project from which to take modules
* @example `./project.inlang`
*/
project: string

/**
* Disable console messages
*/
silent?: boolean

/**
* If the `$paraglide` virtual module should be used instead of writing the output to disk.
*/
experimentalUseVirtualModules?: boolean

/**
* The output directory to place the compiled files in.
*
* If `useVirtualModule` is `true`, then the type-declarations for the virtual module will be placed here
*
* @example `./src/paraglide`
*/
outdir: string
}

export type PluginConfig = {
logger: Logger
/** Absolute path to the project.inlang folder */
projectPath: string
/** Absolute path to the directory in which to write the paraglide files*/
outdir: `${string}/`
useVirtualModules: boolean
}

/**
* Normalizes the input from the user & logs warnings if needed
*/
export function resolveConfig(options: UserConfig): PluginConfig {
const logger = new Logger({ silent: options.silent ?? false, prefix: true })

const outputDirectory = path.resolve(process.cwd(), options.outdir)

let normalizedOutdir = outputDirectory.replaceAll("\\", "/")
if (!normalizedOutdir.endsWith("/")) normalizedOutdir = normalizedOutdir + "/"

const normalizedPorjectPath = path.resolve(process.cwd(), options.project)

return {
logger,
projectPath: normalizedPorjectPath,
outdir: normalizedOutdir as `${string}/`,
useVirtualModules: options.experimentalUseVirtualModules ?? false,
}
}
50 changes: 50 additions & 0 deletions inlang/source-code/paraglide/paraglide-unplugin/src/dts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, it, expect } from "vitest"
import { generateDTSFiles } from "./dts.js"

describe("generateDTSFiles", () => {
it("works", () => {
const inputs = {
"runtime.js": `
/**
* The project's available language tags.
*
* @example
* if (availableLanguageTags.includes(userSelectedLanguageTag) === false){
* throw new Error("Language tag not available")
* }
*/
export const availableLanguageTags = /** @type {const} */ (["en","de"]);
/**
* @typedef {(typeof availableLanguageTags)[number]} AvailableLanguageTag
*/
`,
"messages.js": `
import * as runtime from "./runtime.js";
export const my_mesage = () => "Hello World";
`,
}

const dts = generateDTSFiles(inputs)

expect(dts).toMatchInlineSnapshot(`
{
"messages.d.ts": "/* eslint-disable */
export function my_mesage(): string;
",
"runtime.d.ts": "/* eslint-disable */
/**
* The project's available language tags.
*
* @example
* if (availableLanguageTags.includes(userSelectedLanguageTag) === false){
* throw new Error(\\"Language tag not available\\")
* }
*/
export const availableLanguageTags: readonly [\\"en\\", \\"de\\"];
export type AvailableLanguageTag = (typeof availableLanguageTags)[number];
",
}
`)
})
})
58 changes: 58 additions & 0 deletions inlang/source-code/paraglide/paraglide-unplugin/src/dts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { createProgram, createCompilerHost, type CompilerOptions } from "typescript"

/**
* Compiler options for paraglide JS
*/
const compilerOptions: CompilerOptions = {
allowJs: true,
checkJs: true,
declaration: true,
declarationDir: undefined,
declarationMap: false,
emitDeclarationOnly: true,
lib: undefined,
noEmit: false,
noEmitOnError: false,
skipLibCheck: true,
}

/**
* @param inputFiles The files in the `outdir`
* @returns .d.ts files for each file in the `outdir`
*/
export function generateDTSFiles(inputFiles: Record<string, string>): Record<string, string> {
/**
* Stores files that were emitted as `.d.ts` files during the output.
* @example
* ```js
* {
* "paraglide/runtime.d.ts": "export type AvailableLanguageTag = ...",
* "paragildes/messages.d.ts": "...",
* }
* ```
*/
const outputFiles: Record<string, string> = {}
const host = createCompilerHost(compilerOptions)

// intercept read/write methods of the compiler
host.writeFile = (path, contents) => (outputFiles[path] = contents)
host.readFile = (path) => inputFiles[path]

// A list of input paths for the compiler
const inputs = Object.keys(inputFiles).filter(
(file) => file.endsWith(".js") || (file.endsWith(".ts") && !file.endsWith(".d.ts")) // to be sure
)

// run the TS compiler
// this will cause `host.writeFile` to be called
// our output files are in `outputFiles` after this
const program = createProgram(inputs, compilerOptions, host)
program.emit()

const output: Record<string, string> = {}
for (const [path, content] of Object.entries(outputFiles)) {
output[path] = `/* eslint-disable */\n` + content
}

return output
}
67 changes: 0 additions & 67 deletions inlang/source-code/paraglide/paraglide-unplugin/src/index.test.ts

This file was deleted.

Loading

0 comments on commit aa496e4

Please sign in to comment.