@pyreon/zero 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/server.js +1 -1
- package/lib/types/config.d.ts +32 -0
- package/lib/types/index.d.ts +32 -0
- package/lib/types/server.d.ts +32 -0
- package/lib/{vite-plugin-xjWZwudX.js → vite-plugin-y0NmCLJA.js} +25 -3
- package/package.json +10 -10
- package/src/types.ts +32 -0
- package/src/vite-plugin.ts +63 -11
package/lib/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as render404Page, a as detectLocaleFromHeader, c as vercelAdapter, d as netlifyAdapter, f as cloudflareAdapter, g as createServer, h as resolveConfig, i as createLocaleContext, l as staticAdapter, m as defineConfig, o as i18nRouting, p as bunAdapter, r as zeroPlugin, s as resolveAdapter, t as getZeroPluginConfig, u as nodeAdapter, v as createApp } from "./vite-plugin-
|
|
1
|
+
import { _ as render404Page, a as detectLocaleFromHeader, c as vercelAdapter, d as netlifyAdapter, f as cloudflareAdapter, g as createServer, h as resolveConfig, i as createLocaleContext, l as staticAdapter, m as defineConfig, o as i18nRouting, p as bunAdapter, r as zeroPlugin, s as resolveAdapter, t as getZeroPluginConfig, u as nodeAdapter, v as createApp } from "./vite-plugin-y0NmCLJA.js";
|
|
2
2
|
import { i as generateRouteModule, o as parseFileRoutes, r as generateMiddlewareModule, s as scanRouteFiles, t as filePathToUrlPath } from "./fs-router-MewHc5SB.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { join, resolve } from "node:path";
|
package/lib/types/config.d.ts
CHANGED
|
@@ -210,6 +210,38 @@ interface ZeroConfig {
|
|
|
210
210
|
currentPath: string;
|
|
211
211
|
elapsed: number;
|
|
212
212
|
}) => void | Promise<void>;
|
|
213
|
+
/**
|
|
214
|
+
* Route-level code splitting in SSG mode. Default `true`.
|
|
215
|
+
*
|
|
216
|
+
* When `true` (default), each route file becomes its own dynamic-import
|
|
217
|
+
* chunk via `lazy(() => import("..."))` — only the route the user
|
|
218
|
+
* lands on plus its dependencies ship in the initial bundle, the
|
|
219
|
+
* rest fetch on navigation. Matches the SSR/SPA-mode behaviour zero
|
|
220
|
+
* has always had; brings parity to SSG.
|
|
221
|
+
*
|
|
222
|
+
* When `false`, every route is bundled statically into the main
|
|
223
|
+
* client chunk (the pre-2026-Q3 SSG behaviour). Useful for tiny
|
|
224
|
+
* sites (2-5 pages) where the single-chunk-then-instant-nav trade
|
|
225
|
+
* is preferable — the chunk-fetch cost on navigation is gone, and
|
|
226
|
+
* the marginal bytes are negligible.
|
|
227
|
+
*
|
|
228
|
+
* Crossover point: ~5-8 routes. Below that, single-chunk is fine.
|
|
229
|
+
* Above that, lazy() shrinks the initial bundle by a meaningful
|
|
230
|
+
* amount (a 50-route docs site might drop from 200 KB to 80 KB on
|
|
231
|
+
* first paint).
|
|
232
|
+
*
|
|
233
|
+
* Underlying mechanism is the same 3-tier generator zero already
|
|
234
|
+
* uses for SSR/SPA mode (`fs-router.ts:generateRouteEntry`): lazy
|
|
235
|
+
* component + inlined metadata when possible, lazy + lazy-thunked
|
|
236
|
+
* function exports when not, namespace-import fallback for cases
|
|
237
|
+
* the literal-extractor can't reach.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ssg: {
|
|
241
|
+
* splitChunks: false, // bundle-everything for a 3-page marketing site
|
|
242
|
+
* }
|
|
243
|
+
*/
|
|
244
|
+
splitChunks?: boolean;
|
|
213
245
|
};
|
|
214
246
|
/** ISR config — only used when mode is "isr". */
|
|
215
247
|
isr?: ISRConfig;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -628,6 +628,38 @@ interface ZeroConfig {
|
|
|
628
628
|
currentPath: string;
|
|
629
629
|
elapsed: number;
|
|
630
630
|
}) => void | Promise<void>;
|
|
631
|
+
/**
|
|
632
|
+
* Route-level code splitting in SSG mode. Default `true`.
|
|
633
|
+
*
|
|
634
|
+
* When `true` (default), each route file becomes its own dynamic-import
|
|
635
|
+
* chunk via `lazy(() => import("..."))` — only the route the user
|
|
636
|
+
* lands on plus its dependencies ship in the initial bundle, the
|
|
637
|
+
* rest fetch on navigation. Matches the SSR/SPA-mode behaviour zero
|
|
638
|
+
* has always had; brings parity to SSG.
|
|
639
|
+
*
|
|
640
|
+
* When `false`, every route is bundled statically into the main
|
|
641
|
+
* client chunk (the pre-2026-Q3 SSG behaviour). Useful for tiny
|
|
642
|
+
* sites (2-5 pages) where the single-chunk-then-instant-nav trade
|
|
643
|
+
* is preferable — the chunk-fetch cost on navigation is gone, and
|
|
644
|
+
* the marginal bytes are negligible.
|
|
645
|
+
*
|
|
646
|
+
* Crossover point: ~5-8 routes. Below that, single-chunk is fine.
|
|
647
|
+
* Above that, lazy() shrinks the initial bundle by a meaningful
|
|
648
|
+
* amount (a 50-route docs site might drop from 200 KB to 80 KB on
|
|
649
|
+
* first paint).
|
|
650
|
+
*
|
|
651
|
+
* Underlying mechanism is the same 3-tier generator zero already
|
|
652
|
+
* uses for SSR/SPA mode (`fs-router.ts:generateRouteEntry`): lazy
|
|
653
|
+
* component + inlined metadata when possible, lazy + lazy-thunked
|
|
654
|
+
* function exports when not, namespace-import fallback for cases
|
|
655
|
+
* the literal-extractor can't reach.
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* ssg: {
|
|
659
|
+
* splitChunks: false, // bundle-everything for a 3-page marketing site
|
|
660
|
+
* }
|
|
661
|
+
*/
|
|
662
|
+
splitChunks?: boolean;
|
|
631
663
|
};
|
|
632
664
|
/** ISR config — only used when mode is "isr". */
|
|
633
665
|
isr?: ISRConfig;
|
package/lib/types/server.d.ts
CHANGED
|
@@ -331,6 +331,38 @@ interface ZeroConfig {
|
|
|
331
331
|
currentPath: string;
|
|
332
332
|
elapsed: number;
|
|
333
333
|
}) => void | Promise<void>;
|
|
334
|
+
/**
|
|
335
|
+
* Route-level code splitting in SSG mode. Default `true`.
|
|
336
|
+
*
|
|
337
|
+
* When `true` (default), each route file becomes its own dynamic-import
|
|
338
|
+
* chunk via `lazy(() => import("..."))` — only the route the user
|
|
339
|
+
* lands on plus its dependencies ship in the initial bundle, the
|
|
340
|
+
* rest fetch on navigation. Matches the SSR/SPA-mode behaviour zero
|
|
341
|
+
* has always had; brings parity to SSG.
|
|
342
|
+
*
|
|
343
|
+
* When `false`, every route is bundled statically into the main
|
|
344
|
+
* client chunk (the pre-2026-Q3 SSG behaviour). Useful for tiny
|
|
345
|
+
* sites (2-5 pages) where the single-chunk-then-instant-nav trade
|
|
346
|
+
* is preferable — the chunk-fetch cost on navigation is gone, and
|
|
347
|
+
* the marginal bytes are negligible.
|
|
348
|
+
*
|
|
349
|
+
* Crossover point: ~5-8 routes. Below that, single-chunk is fine.
|
|
350
|
+
* Above that, lazy() shrinks the initial bundle by a meaningful
|
|
351
|
+
* amount (a 50-route docs site might drop from 200 KB to 80 KB on
|
|
352
|
+
* first paint).
|
|
353
|
+
*
|
|
354
|
+
* Underlying mechanism is the same 3-tier generator zero already
|
|
355
|
+
* uses for SSR/SPA mode (`fs-router.ts:generateRouteEntry`): lazy
|
|
356
|
+
* component + inlined metadata when possible, lazy + lazy-thunked
|
|
357
|
+
* function exports when not, namespace-import fallback for cases
|
|
358
|
+
* the literal-extractor can't reach.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ssg: {
|
|
362
|
+
* splitChunks: false, // bundle-everything for a 3-page marketing site
|
|
363
|
+
* }
|
|
364
|
+
*/
|
|
365
|
+
splitChunks?: boolean;
|
|
334
366
|
};
|
|
335
367
|
/** ISR config — only used when mode is "isr". */
|
|
336
368
|
isr?: ISRConfig;
|
|
@@ -2073,6 +2073,7 @@ function ssgPlugin(userConfig = {}) {
|
|
|
2073
2073
|
//#endregion
|
|
2074
2074
|
//#region src/vite-plugin.ts
|
|
2075
2075
|
var vite_plugin_exports = /* @__PURE__ */ __exportAll({
|
|
2076
|
+
argvHasPortFlag: () => argvHasPortFlag,
|
|
2076
2077
|
getZeroPluginConfig: () => getZeroPluginConfig,
|
|
2077
2078
|
zeroPlugin: () => zeroPlugin
|
|
2078
2079
|
});
|
|
@@ -2129,6 +2130,25 @@ function getZeroPluginConfig(plugin) {
|
|
|
2129
2130
|
return zeroPluginConfigMap.get(plugin);
|
|
2130
2131
|
}
|
|
2131
2132
|
/**
|
|
2133
|
+
* Detects `--port` / `--port=N` / `-p N` / `-p=N` in `process.argv`.
|
|
2134
|
+
* Used by the plugin's `config()` hook to decide whether to apply the
|
|
2135
|
+
* default port — when the CLI was invoked with `--port`, the plugin
|
|
2136
|
+
* must skip its default so the CLI flag wins (see the comment at the
|
|
2137
|
+
* port-handling block in `zeroPlugin()` for the full precedence model).
|
|
2138
|
+
*
|
|
2139
|
+
* Exported for testing only (the plugin uses it internally).
|
|
2140
|
+
*
|
|
2141
|
+
* @internal
|
|
2142
|
+
*/
|
|
2143
|
+
function argvHasPortFlag(argv = process.argv) {
|
|
2144
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2145
|
+
const a = argv[i];
|
|
2146
|
+
if (a === "--port" || a === "-p") return true;
|
|
2147
|
+
if (a !== void 0 && (a.startsWith("--port=") || a.startsWith("-p="))) return true;
|
|
2148
|
+
}
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
/**
|
|
2132
2152
|
* Zero Vite plugin — adds file-based routing and zero-config conventions
|
|
2133
2153
|
* on top of @pyreon/vite-plugin.
|
|
2134
2154
|
*
|
|
@@ -2160,7 +2180,9 @@ function zeroPlugin(userConfig = {}) {
|
|
|
2160
2180
|
async load(id) {
|
|
2161
2181
|
if (id === RESOLVED_VIRTUAL_ROUTES_ID) try {
|
|
2162
2182
|
const baseRoutes = await scanRouteFilesWithExports(routesDir, config.mode);
|
|
2163
|
-
|
|
2183
|
+
const routes = config.i18n ? expandRoutesForLocales(baseRoutes, config.i18n) : baseRoutes;
|
|
2184
|
+
const ssgSplitDisabled = config.mode === "ssg" && config.ssg?.splitChunks === false;
|
|
2185
|
+
return generateRouteModuleFromRoutes(routes, routesDir, { staticImports: ssgSplitDisabled });
|
|
2164
2186
|
} catch (_err) {
|
|
2165
2187
|
return `export const routes = []`;
|
|
2166
2188
|
}
|
|
@@ -2289,7 +2311,7 @@ function zeroPlugin(userConfig = {}) {
|
|
|
2289
2311
|
...runtimeServerAlias ? { alias: { "@pyreon/runtime-server": runtimeServerAlias } } : {}
|
|
2290
2312
|
} },
|
|
2291
2313
|
optimizeDeps: { exclude: pyreonExclude },
|
|
2292
|
-
...userConfig.port
|
|
2314
|
+
...userConfig.port === void 0 && argvHasPortFlag() ? {} : { server: { port: config.port } },
|
|
2293
2315
|
base: config.base,
|
|
2294
2316
|
define: {
|
|
2295
2317
|
__ZERO_MODE__: JSON.stringify(config.mode),
|
|
@@ -2451,4 +2473,4 @@ function flattenRoutePatterns(routes) {
|
|
|
2451
2473
|
|
|
2452
2474
|
//#endregion
|
|
2453
2475
|
export { render404Page as _, detectLocaleFromHeader as a, vercelAdapter as c, netlifyAdapter as d, cloudflareAdapter as f, createServer as g, resolveConfig as h, createLocaleContext as i, staticAdapter as l, defineConfig as m, vite_plugin_exports as n, i18nRouting as o, bunAdapter as p, zeroPlugin as r, resolveAdapter as s, getZeroPluginConfig as t, nodeAdapter as u, createApp as v };
|
|
2454
|
-
//# sourceMappingURL=vite-plugin-
|
|
2476
|
+
//# sourceMappingURL=vite-plugin-y0NmCLJA.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/zero",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Pyreon Zero — zero-config full-stack framework powered by Pyreon and Vite",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Vit Bokisch",
|
|
@@ -168,15 +168,15 @@
|
|
|
168
168
|
"lint": "oxlint ."
|
|
169
169
|
},
|
|
170
170
|
"dependencies": {
|
|
171
|
-
"@pyreon/core": "^0.
|
|
172
|
-
"@pyreon/head": "^0.
|
|
173
|
-
"@pyreon/meta": "^0.
|
|
174
|
-
"@pyreon/reactivity": "^0.
|
|
175
|
-
"@pyreon/router": "^0.
|
|
176
|
-
"@pyreon/runtime-dom": "^0.
|
|
177
|
-
"@pyreon/runtime-server": "^0.
|
|
178
|
-
"@pyreon/server": "^0.
|
|
179
|
-
"@pyreon/vite-plugin": "^0.
|
|
171
|
+
"@pyreon/core": "^0.18.0",
|
|
172
|
+
"@pyreon/head": "^0.18.0",
|
|
173
|
+
"@pyreon/meta": "^0.18.0",
|
|
174
|
+
"@pyreon/reactivity": "^0.18.0",
|
|
175
|
+
"@pyreon/router": "^0.18.0",
|
|
176
|
+
"@pyreon/runtime-dom": "^0.18.0",
|
|
177
|
+
"@pyreon/runtime-server": "^0.18.0",
|
|
178
|
+
"@pyreon/server": "^0.18.0",
|
|
179
|
+
"@pyreon/vite-plugin": "^0.18.0",
|
|
180
180
|
"vite": "^8.0.0"
|
|
181
181
|
},
|
|
182
182
|
"devDependencies": {
|
package/src/types.ts
CHANGED
|
@@ -254,6 +254,38 @@ export interface ZeroConfig {
|
|
|
254
254
|
currentPath: string
|
|
255
255
|
elapsed: number
|
|
256
256
|
}) => void | Promise<void>
|
|
257
|
+
/**
|
|
258
|
+
* Route-level code splitting in SSG mode. Default `true`.
|
|
259
|
+
*
|
|
260
|
+
* When `true` (default), each route file becomes its own dynamic-import
|
|
261
|
+
* chunk via `lazy(() => import("..."))` — only the route the user
|
|
262
|
+
* lands on plus its dependencies ship in the initial bundle, the
|
|
263
|
+
* rest fetch on navigation. Matches the SSR/SPA-mode behaviour zero
|
|
264
|
+
* has always had; brings parity to SSG.
|
|
265
|
+
*
|
|
266
|
+
* When `false`, every route is bundled statically into the main
|
|
267
|
+
* client chunk (the pre-2026-Q3 SSG behaviour). Useful for tiny
|
|
268
|
+
* sites (2-5 pages) where the single-chunk-then-instant-nav trade
|
|
269
|
+
* is preferable — the chunk-fetch cost on navigation is gone, and
|
|
270
|
+
* the marginal bytes are negligible.
|
|
271
|
+
*
|
|
272
|
+
* Crossover point: ~5-8 routes. Below that, single-chunk is fine.
|
|
273
|
+
* Above that, lazy() shrinks the initial bundle by a meaningful
|
|
274
|
+
* amount (a 50-route docs site might drop from 200 KB to 80 KB on
|
|
275
|
+
* first paint).
|
|
276
|
+
*
|
|
277
|
+
* Underlying mechanism is the same 3-tier generator zero already
|
|
278
|
+
* uses for SSR/SPA mode (`fs-router.ts:generateRouteEntry`): lazy
|
|
279
|
+
* component + inlined metadata when possible, lazy + lazy-thunked
|
|
280
|
+
* function exports when not, namespace-import fallback for cases
|
|
281
|
+
* the literal-extractor can't reach.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* ssg: {
|
|
285
|
+
* splitChunks: false, // bundle-everything for a 3-page marketing site
|
|
286
|
+
* }
|
|
287
|
+
*/
|
|
288
|
+
splitChunks?: boolean
|
|
257
289
|
}
|
|
258
290
|
|
|
259
291
|
/** ISR config — only used when mode is "isr". */
|
package/src/vite-plugin.ts
CHANGED
|
@@ -90,6 +90,27 @@ export function getZeroPluginConfig(plugin: Plugin): ZeroConfig | undefined {
|
|
|
90
90
|
return zeroPluginConfigMap.get(plugin);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Detects `--port` / `--port=N` / `-p N` / `-p=N` in `process.argv`.
|
|
95
|
+
* Used by the plugin's `config()` hook to decide whether to apply the
|
|
96
|
+
* default port — when the CLI was invoked with `--port`, the plugin
|
|
97
|
+
* must skip its default so the CLI flag wins (see the comment at the
|
|
98
|
+
* port-handling block in `zeroPlugin()` for the full precedence model).
|
|
99
|
+
*
|
|
100
|
+
* Exported for testing only (the plugin uses it internally).
|
|
101
|
+
*
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
export function argvHasPortFlag(argv: readonly string[] = process.argv): boolean {
|
|
105
|
+
for (let i = 0; i < argv.length; i++) {
|
|
106
|
+
const a = argv[i];
|
|
107
|
+
if (a === "--port" || a === "-p") return true;
|
|
108
|
+
if (a !== undefined && (a.startsWith("--port=") || a.startsWith("-p=")))
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
93
114
|
/**
|
|
94
115
|
* Zero Vite plugin — adds file-based routing and zero-config conventions
|
|
95
116
|
* on top of @pyreon/vite-plugin.
|
|
@@ -138,8 +159,23 @@ export function zeroPlugin(userConfig: ZeroConfig = {}): Plugin[] {
|
|
|
138
159
|
const routes = config.i18n
|
|
139
160
|
? expandRoutesForLocales(baseRoutes, config.i18n)
|
|
140
161
|
: baseRoutes;
|
|
162
|
+
// SSG mode: lazy() route splitting by default (parity with
|
|
163
|
+
// SSR/SPA). Opt-out via `ssg.splitChunks: false` for tiny
|
|
164
|
+
// sites that prefer single-chunk + instant navigation.
|
|
165
|
+
//
|
|
166
|
+
// Pre-2026-Q3: SSG was hardcoded to `staticImports: true`
|
|
167
|
+
// (bundle everything). Trade-off was instant post-hydration
|
|
168
|
+
// nav, but the initial bundle grew linearly with route
|
|
169
|
+
// count — a 50-route docs site shipped all 50 route
|
|
170
|
+
// components on first paint. Lazy splitting (now the
|
|
171
|
+
// default for SSG) fixes that: only the landing route +
|
|
172
|
+
// deps load up front, the rest fetch on navigation. See
|
|
173
|
+
// `ssg.splitChunks` JSDoc in types.ts for the crossover-
|
|
174
|
+
// point rationale.
|
|
175
|
+
const ssgSplitDisabled =
|
|
176
|
+
config.mode === "ssg" && config.ssg?.splitChunks === false;
|
|
141
177
|
return generateRouteModuleFromRoutes(routes, routesDir, {
|
|
142
|
-
staticImports:
|
|
178
|
+
staticImports: ssgSplitDisabled,
|
|
143
179
|
});
|
|
144
180
|
} catch (_err) {
|
|
145
181
|
return `export const routes = []`;
|
|
@@ -389,16 +425,32 @@ export function zeroPlugin(userConfig: ZeroConfig = {}): Plugin[] {
|
|
|
389
425
|
optimizeDeps: {
|
|
390
426
|
exclude: pyreonExclude,
|
|
391
427
|
},
|
|
392
|
-
//
|
|
393
|
-
// `zero
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
// `
|
|
398
|
-
//
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
428
|
+
// Port handling — the zero-canonical default is 3000 (matches
|
|
429
|
+
// `zero dev` / `zero preview` / the runtime adapter, and
|
|
430
|
+
// matches Next.js / Remix / Astro convention).
|
|
431
|
+
//
|
|
432
|
+
// Apply the default UNLESS Vite's CLI was invoked with
|
|
433
|
+
// `--port`/`-p` (in which case the CLI flag must win — see
|
|
434
|
+
// memory: vite cli port doesnt override plugin). PR #579
|
|
435
|
+
// proved this empirically: returning `server: { port: 3000 }`
|
|
436
|
+
// unconditionally clobbered `vite --port 517N --strictPort`
|
|
437
|
+
// in the e2e playwright config and every webServer timed
|
|
438
|
+
// out. argv detection here lets the CLI win at the source.
|
|
439
|
+
//
|
|
440
|
+
// Precedence (CLI > user vite.config > zero({port}) > 3000):
|
|
441
|
+
// 1. `vite --port N` → argvHasPortFlag() === true → plugin
|
|
442
|
+
// omits `server.port` entirely → CLI value wins
|
|
443
|
+
// 2. User `vite.config.ts server: { port: N }` → user
|
|
444
|
+
// config beats plugin in Vite's merge order
|
|
445
|
+
// 3. `zero({ port: N })` → resolved into `config.port`
|
|
446
|
+
// 4. Default 3000 — when no other source set a port
|
|
447
|
+
//
|
|
448
|
+
// `process.argv` is populated by the time Vite invokes the
|
|
449
|
+
// plugin's config() hook (Vite calls plugins synchronously
|
|
450
|
+
// during CLI bootstrap before applying inline overrides).
|
|
451
|
+
...(userConfig.port === undefined && argvHasPortFlag()
|
|
452
|
+
? {}
|
|
453
|
+
: { server: { port: config.port } }),
|
|
402
454
|
// Propagate `zero({ base })` to Vite's `base` config — that's
|
|
403
455
|
// what controls asset URL rewriting in the built HTML/JS
|
|
404
456
|
// (`<script src="/blog/assets/…">`). Pre-fix this was a
|