From 8886250da20a3f47472fc66db906241bc3530778 Mon Sep 17 00:00:00 2001 From: Mamadou Talla DIA Date: Sat, 26 Sep 2026 23:08:40 +0100 Subject: [PATCH 1/3] feat(config): add distDir and deprecate distdir --- .changeset/loud-flies-train.md | 7 +++++++ packages/runable/src/config/resolve.ts | 7 ++++--- packages/runable/src/config/types.ts | 14 ++++++++++++++ packages/runable/src/inspector/project.ts | 2 +- packages/runable/src/vite/build/production.ts | 12 ++++++------ packages/runable/src/vite/request.ts | 19 +++++++++++-------- 6 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 .changeset/loud-flies-train.md diff --git a/.changeset/loud-flies-train.md b/.changeset/loud-flies-train.md new file mode 100644 index 0000000..09c7c23 --- /dev/null +++ b/.changeset/loud-flies-train.md @@ -0,0 +1,7 @@ +--- +"runable": major +--- + +Add distDir as the canonical configuration option in @runable/core and deprecate distdir. + +distdir remains supported for backward compatibility and will be removed in the next major version. When both options are defined, distDir takes precedence. \ No newline at end of file diff --git a/packages/runable/src/config/resolve.ts b/packages/runable/src/config/resolve.ts index 7c33e3c..604e93a 100644 --- a/packages/runable/src/config/resolve.ts +++ b/packages/runable/src/config/resolve.ts @@ -22,8 +22,8 @@ export function resolveConfig(config: RunableConfig & { cwd: string }) { let _output = config.output ?? ".app"; _output = resolveDir(_output, _cwd); - let _distdir = config.distdir ?? ".output"; - _distdir = resolveDir(_distdir, _cwd); + let _distDir = config.distDir ?? config.distdir ?? ".output"; + _distDir = resolveDir(_distDir, _cwd); // `publicDir: false` disables the public dir — leave it as-is instead of resolving it. let _publicDir = config.publicDir ?? "public"; @@ -92,7 +92,8 @@ export function resolveConfig(config: RunableConfig & { cwd: string }) { appDir: _appDir, output: _output, - distdir: _distdir, + distdir: _distDir, + distDir: _distDir, publicDir: _publicDir, components: _components, diff --git a/packages/runable/src/config/types.ts b/packages/runable/src/config/types.ts index 8dfe59b..3427988 100644 --- a/packages/runable/src/config/types.ts +++ b/packages/runable/src/config/types.ts @@ -71,6 +71,12 @@ export interface RunableConfig { /** Build output mode/format. */ output?: string; + /** Build output directory. Defaults to `.output`. */ + distDir?: string; + + /** + * @deprecated Use `distDir` instead. This option will be removed in the next major version. + */ distdir?: string; /** Base URL the application is served from (routes/assets prefix). */ @@ -217,7 +223,15 @@ export type ResolvedConfig = { appDir: string; /** Resolved build output mode/format. */ output: string; + + /** Resolved build output directory. Defaults to `.output`. */ + distDir: string; + + /** + * @deprecated Use `distDir` instead. This option will be removed in the next major version. + */ distdir: string; + /** Resolved path to the directory of static assets served as-is, or `false` if disabled. */ publicDir: string | false; diff --git a/packages/runable/src/inspector/project.ts b/packages/runable/src/inspector/project.ts index 4c73ca8..9e7e813 100644 --- a/packages/runable/src/inspector/project.ts +++ b/packages/runable/src/inspector/project.ts @@ -25,7 +25,7 @@ export function resolveInspectorProject( paths: { appDir: toProjectRelative(rootDir, main.appDir), generatedDir: toProjectRelative(rootDir, main.output), - outputDir: toProjectRelative(rootDir, main.distdir), + outputDir: toProjectRelative(rootDir, main.distDir), publicDir: typeof main.publicDir === "string" ? toProjectRelative(rootDir, main.publicDir) diff --git a/packages/runable/src/vite/build/production.ts b/packages/runable/src/vite/build/production.ts index f795a52..8dc1f38 100644 --- a/packages/runable/src/vite/build/production.ts +++ b/packages/runable/src/vite/build/production.ts @@ -22,7 +22,7 @@ function toPublicAssetPath(fileName: string): string { export async function buildProduction() { const config = useConfig(); const viteConfig = buildViteConfig(); - const distdir = config.distdir; + const distDir = config.distDir; // `html` is the generated client index.html; `switcher` (SSR-only) is the // built path to the server entry, filled in further down. const manifest = { switcher: "", html: "" }; @@ -31,7 +31,7 @@ export async function buildProduction() { // below don't leak into one another. const clientConfig = merge(cloneDeep(viteConfig), { build: { - outDir: join(distdir, "client"), + outDir: join(distDir, "client"), emptyOutDir: true, minify: true, // manifest: true, @@ -49,7 +49,7 @@ export async function buildProduction() { const servrConfig = merge(cloneDeep(viteConfig), { build: { - outDir: join(distdir, "server"), + outDir: join(distDir, "server"), minify: true, manifest: true, // Building for SSR (rather than a plain library/app build) uses the @@ -104,7 +104,7 @@ export async function buildProduction() { ` ${css.join("\n ")}\n `, ); - atomicWriteFile(join(distdir, "client/index.html"), htmlContent); + atomicWriteFile(join(distDir, "client/index.html"), htmlContent); manifest.html = htmlContent; } @@ -119,7 +119,7 @@ export async function buildProduction() { // Vite's own build manifest (entry -> emitted file map), produced // because `manifest: true` was set on `servrConfig` above. const vManifest = JSON.parse( - await readFile(join(distdir, "server", ".vite/manifest.json"), "utf8"), + await readFile(join(distDir, "server", ".vite/manifest.json"), "utf8"), ) as Manifest; // Find the emitted file for the switcher entry so it can be @@ -138,7 +138,7 @@ export async function buildProduction() { // Write the runtime manifest (server switcher path + client HTML) that the // production server reads to serve requests without rebuilding. atomicWriteFile( - join(distdir, "manifest.js"), + join(distDir, "manifest.js"), `export default ${JSON.stringify(manifest, null, 4)}`, ); } diff --git a/packages/runable/src/vite/request.ts b/packages/runable/src/vite/request.ts index bd8f87c..39666c0 100644 --- a/packages/runable/src/vite/request.ts +++ b/packages/runable/src/vite/request.ts @@ -53,11 +53,11 @@ const CONTENT_TYPES: Record = { /** Reads a generated client asset in production, or returns undefined for an application route. */ export async function readProductionAsset({ - distdir, + distDir, url, method = "GET", }: { - distdir: string; + distDir: string; url: string; method?: string; }): Promise { @@ -65,12 +65,14 @@ export async function readProductionAsset({ let pathname: string; try { - pathname = decodeURIComponent(new URL(url, "http://runable.local").pathname); + pathname = decodeURIComponent( + new URL(url, "http://runable.local").pathname, + ); } catch { return; } - const clientDir = resolve(distdir, "client"); + const clientDir = resolve(distDir, "client"); const file = resolve(clientDir, pathname.replace(/^\/+/, "")); if (file === clientDir || !file.startsWith(`${clientDir}${sep}`)) return; @@ -81,7 +83,8 @@ export async function readProductionAsset({ return { content: method === "HEAD" ? null : await readFile(file), status: 200, - type: CONTENT_TYPES[extname(file).toLowerCase()] ?? + type: + CONTENT_TYPES[extname(file).toLowerCase()] ?? "application/octet-stream", headers: { "Content-Length": info.size, @@ -115,7 +118,7 @@ async function viteRequest({ if (!vite && isRunableProduction()) { const asset = await readProductionAsset({ - distdir: config.distdir, + distDir: config.distDir, url, method, }); @@ -130,7 +133,7 @@ async function viteRequest({ template = await vite.transformIndexHtml(url, template); } else { const manifestModule = (await import( - join(config.distdir, "manifest.js") + join(config.distDir, "manifest.js") )) as { default?: Record } & Record; const manifest = (manifestModule.default ?? manifestModule) as Record< string, @@ -159,7 +162,7 @@ async function viteRequest({ const serverEntry = isAbsolute(entryLoader) ? entryLoader - : join(config.distdir, "server", entryLoader); + : join(config.distDir, "server", entryLoader); render = (await import(serverEntry)).render; } From 90106bafb80764c4f145b8aa2be3f364b93d28fc Mon Sep 17 00:00:00 2001 From: Mamadou Talla DIA Date: Sat, 26 Sep 2026 23:14:32 +0100 Subject: [PATCH 2/3] feat(config): replace `distdir` with `distDir` in the documentation --- website/content/docs/en/getting-started/configuration.md | 6 +++--- website/content/docs/en/guide/cli/build.md | 2 +- website/content/docs/en/guide/production-build.md | 4 ++-- website/content/docs/en/integrations/index.md | 2 +- website/content/docs/en/structure/gitignore.md | 2 +- website/content/docs/en/structure/output.md | 2 +- website/content/docs/en/structure/runable-config.md | 2 +- website/content/docs/fr/getting-started/configuration.md | 6 +++--- website/content/docs/fr/guide/production-build.md | 4 ++-- website/content/docs/fr/integrations/index.md | 2 +- website/content/docs/fr/structure/gitignore.md | 2 +- website/content/docs/fr/structure/output.md | 2 +- website/content/docs/fr/structure/runable-config.md | 2 +- 13 files changed, 19 insertions(+), 19 deletions(-) diff --git a/website/content/docs/en/getting-started/configuration.md b/website/content/docs/en/getting-started/configuration.md index 1cd1929..3ef30a9 100644 --- a/website/content/docs/en/getting-started/configuration.md +++ b/website/content/docs/en/getting-started/configuration.md @@ -26,7 +26,7 @@ Without additional options, Runable uses this structure: | --- | --- | --- | --- | | `appDir` | `string` | `app` | Root of Vue sources | | `output` | `string` | `.app` | Files generated for development and typing | -| `distdir` | `string` | `.output` | Production build | +| `distDir` | `string` | `.output` | Production build | | `publicDir` | `string \| false` | `public` | Assets served as-is | | `ssr` | `boolean` | `true` | Enables server rendering | | `pages` | `string \| array` | `app/pages` | Page files | @@ -52,7 +52,7 @@ import { defineConfig } from "runable"; export default defineConfig({ appDir: "frontend", output: ".runable", - distdir: "dist", + distDir: "dist", publicDir: "static", }); ``` @@ -205,7 +205,7 @@ import { defineConfig } from "runable"; export default defineConfig({ appDir: "app", output: ".app", - distdir: ".output", + distDir: ".output", publicDir: "public", ssr: true, diff --git a/website/content/docs/en/guide/cli/build.md b/website/content/docs/en/guide/cli/build.md index 307ae28..2c066e4 100644 --- a/website/content/docs/en/guide/cli/build.md +++ b/website/content/docs/en/guide/cli/build.md @@ -7,7 +7,7 @@ description: Produce the production client and server bundles Runable serves fro runable build ``` -`runable build` produces the production bundle: always the client (HTML template and hashed assets), and a server bundle too when `ssr` is enabled. Output goes to `distdir` — `.output/` by default — alongside a `manifest.js` connecting the running server to the built client and, for SSR, the compiled server entry. +`runable build` produces the production bundle: always the client (HTML template and hashed assets), and a server bundle too when `ssr` is enabled. Output goes to `distDir` — `.output/` by default — alongside a `manifest.js` connecting the running server to the built client and, for SSR, the compiled server entry. For the full output layout, how to start a built application, and a deployment checklist, see Production build and `.output/` — this page only covers the command itself. diff --git a/website/content/docs/en/guide/production-build.md b/website/content/docs/en/guide/production-build.md index f0afc13..4cd0f9d 100644 --- a/website/content/docs/en/guide/production-build.md +++ b/website/content/docs/en/guide/production-build.md @@ -40,7 +40,7 @@ Install `tsx` as a development dependency when your server and script remain in ## Understand the output -With the default `distdir`, Runable writes to `.output/`: +With the default `distDir`, Runable writes to `.output/`: ```text .output/ @@ -90,6 +90,6 @@ variant: warning title: Build before startup --- -The production server expects `.output/manifest.js`. If it is missing, run the build or check `distdir`. +The production server expects `.output/manifest.js`. If it is missing, run the build or check `distDir`. :: diff --git a/website/content/docs/en/integrations/index.md b/website/content/docs/en/integrations/index.md index f5a0284..a6fb667 100644 --- a/website/content/docs/en/integrations/index.md +++ b/website/content/docs/en/integrations/index.md @@ -5,7 +5,7 @@ description: Connect Runable to Express, Fastify, Hono, Koa, NestJS, AdonisJS, B An adapter connects requests from your backend to the Runable rendering engine. It initializes the application once, lets Vite serve development assets when the runtime allows it, then produces the Vue response. -In production, every official adapter also serves generated files from `distdir/client` before falling back to Vue rendering. You do not need to register an additional static-file plugin for `.output/client`. +In production, every official adapter also serves generated files from `distDir/client` before falling back to Vue rendering. You do not need to register an additional static-file plugin for `.output/client`. ## Available adapters diff --git a/website/content/docs/en/structure/gitignore.md b/website/content/docs/en/structure/gitignore.md index 1112629..3ce54a5 100644 --- a/website/content/docs/en/structure/gitignore.md +++ b/website/content/docs/en/structure/gitignore.md @@ -18,6 +18,6 @@ node_modules/ .DS_Store ``` -Adjust `.output/` and `.app/` if you changed `distdir` or `output` in `runable.config.ts`. +Adjust `.output/` and `.app/` if you changed `distDir` or `output` in `runable.config.ts`. Commit sources, configuration, `package.json`, the lockfile, and `.env.example`. Generated directories must be reproducible with `pnpm install`, `runable prepare`, and `runable build`. diff --git a/website/content/docs/en/structure/output.md b/website/content/docs/en/structure/output.md index 7f5198b..7ec57ee 100644 --- a/website/content/docs/en/structure/output.md +++ b/website/content/docs/en/structure/output.md @@ -21,7 +21,7 @@ With `ssr: false`, Runable does not produce a server bundle. The `client/` direc ```ts // runable.config.ts export default defineConfig({ - distdir: "dist", + distDir: "dist", }); ``` diff --git a/website/content/docs/en/structure/runable-config.md b/website/content/docs/en/structure/runable-config.md index b45cc5f..3c57f0d 100644 --- a/website/content/docs/en/structure/runable-config.md +++ b/website/content/docs/en/structure/runable-config.md @@ -25,7 +25,7 @@ Relative paths are resolved from the configuration directory. Main conventions u | --- | --- | | `appDir` | `app` | | `output` | `.app` | -| `distdir` | `.output` | +| `distDir` | `.output` | | `publicDir` | `public` | | `ssr` | `true` | diff --git a/website/content/docs/fr/getting-started/configuration.md b/website/content/docs/fr/getting-started/configuration.md index 0c1d68e..4e8c5c7 100644 --- a/website/content/docs/fr/getting-started/configuration.md +++ b/website/content/docs/fr/getting-started/configuration.md @@ -26,7 +26,7 @@ Sans option supplémentaire, Runable utilise cette structure : | --- | --- | --- | --- | | `appDir` | `string` | `app` | Racine des sources Vue | | `output` | `string` | `.app` | Fichiers générés pour le développement et le typage | -| `distdir` | `string` | `.output` | Build de production | +| `distDir` | `string` | `.output` | Build de production | | `publicDir` | `string \| false` | `public` | Assets servis tels quels | | `ssr` | `boolean` | `true` | Active le rendu serveur | | `pages` | `string \| array` | `app/pages` | Fichiers de pages | @@ -52,7 +52,7 @@ import { defineConfig } from "runable"; export default defineConfig({ appDir: "frontend", output: ".runable", - distdir: "dist", + distDir: "dist", publicDir: "static", }); ``` @@ -214,7 +214,7 @@ import { defineConfig } from "runable"; export default defineConfig({ appDir: "app", output: ".app", - distdir: ".output", + distDir: ".output", publicDir: "public", ssr: true, diff --git a/website/content/docs/fr/guide/production-build.md b/website/content/docs/fr/guide/production-build.md index c682028..9b97bf5 100644 --- a/website/content/docs/fr/guide/production-build.md +++ b/website/content/docs/fr/guide/production-build.md @@ -30,7 +30,7 @@ Installez `tsx` en dépendance de développement si votre serveur et votre scrip ## Comprendre la sortie -Avec le `distdir` par défaut, Runable écrit dans `.output/` : +Avec le `distDir` par défaut, Runable écrit dans `.output/` : ```text .output/ @@ -80,6 +80,6 @@ variant: warning title: Le build doit précéder le démarrage --- -Le serveur de production attend `.output/manifest.js`. Si ce fichier manque, lancez le build ou vérifiez la valeur de `distdir`. +Le serveur de production attend `.output/manifest.js`. Si ce fichier manque, lancez le build ou vérifiez la valeur de `distDir`. :: diff --git a/website/content/docs/fr/integrations/index.md b/website/content/docs/fr/integrations/index.md index 575f9c2..7cb634d 100644 --- a/website/content/docs/fr/integrations/index.md +++ b/website/content/docs/fr/integrations/index.md @@ -5,7 +5,7 @@ description: Branchez Runable à Express, Fastify, Hono, Koa, NestJS, AdonisJS, Un adaptateur relie les requêtes de votre backend au moteur de rendu Runable. Il initialise l'application une seule fois, laisse Vite servir ses ressources en développement lorsque le runtime le permet, puis produit la réponse Vue. -En production, chaque adaptateur officiel sert également les fichiers générés depuis `distdir/client` avant de déléguer le reste au rendu Vue. Il n'est pas nécessaire d'enregistrer un plugin de fichiers statiques supplémentaire pour `.output/client`. +En production, chaque adaptateur officiel sert également les fichiers générés depuis `distDir/client` avant de déléguer le reste au rendu Vue. Il n'est pas nécessaire d'enregistrer un plugin de fichiers statiques supplémentaire pour `.output/client`. ## Adaptateurs disponibles diff --git a/website/content/docs/fr/structure/gitignore.md b/website/content/docs/fr/structure/gitignore.md index 6c3aaad..ba244ff 100644 --- a/website/content/docs/fr/structure/gitignore.md +++ b/website/content/docs/fr/structure/gitignore.md @@ -18,7 +18,7 @@ node_modules/ .DS_Store ``` -Adaptez `.output/` et `.app/` si vous avez changé `distdir` ou `output` dans `runable.config.ts`. +Adaptez `.output/` et `.app/` si vous avez changé `distDir` ou `output` dans `runable.config.ts`. Versionnez les sources, la configuration, `package.json`, le lockfile et `.env.example`. Les dossiers générés doivent pouvoir être recréés avec `pnpm install`, `runable prepare` et `runable build`. diff --git a/website/content/docs/fr/structure/output.md b/website/content/docs/fr/structure/output.md index 194b7ec..5d62cd4 100644 --- a/website/content/docs/fr/structure/output.md +++ b/website/content/docs/fr/structure/output.md @@ -21,7 +21,7 @@ Avec `ssr: false`, Runable ne produit pas le bundle serveur. Le dossier `client/ ```ts // runable.config.ts export default defineConfig({ - distdir: "dist", + distDir: "dist", }); ``` diff --git a/website/content/docs/fr/structure/runable-config.md b/website/content/docs/fr/structure/runable-config.md index 2be505e..807fe71 100644 --- a/website/content/docs/fr/structure/runable-config.md +++ b/website/content/docs/fr/structure/runable-config.md @@ -25,7 +25,7 @@ Les chemins relatifs sont résolus depuis le dossier de la configuration. Les co | --- | --- | | `appDir` | `app` | | `output` | `.app` | -| `distdir` | `.output` | +| `distDir` | `.output` | | `publicDir` | `public` | | `ssr` | `true` | From a2ff40b339954782c2b73f0cce347c0c5c3d43a6 Mon Sep 17 00:00:00 2001 From: Mamadou Talla DIA Date: Sat, 26 Sep 2026 23:20:54 +0100 Subject: [PATCH 3/3] fix(changeset): update version from major to minor for distDir deprecation --- .changeset/loud-flies-train.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/loud-flies-train.md b/.changeset/loud-flies-train.md index 09c7c23..0fc70cf 100644 --- a/.changeset/loud-flies-train.md +++ b/.changeset/loud-flies-train.md @@ -1,5 +1,5 @@ --- -"runable": major +"runable": minor --- Add distDir as the canonical configuration option in @runable/core and deprecate distdir.