@vizejs/vite-plugin 0.327.0 → 0.332.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.
Files changed (2) hide show
  1. package/dist/index.mjs +109 -3
  2. package/package.json +3 -3
package/dist/index.mjs CHANGED
@@ -2425,6 +2425,114 @@ function shouldLoadCompiledVueSfcPath(state, realPath, hasNuxtComponentQuery = f
2425
2425
  return true;
2426
2426
  }
2427
2427
  //#endregion
2428
+ //#region src/plugin/ssr-modules.ts
2429
+ /**
2430
+ * Point a compiled SSR module at the `vue/server-renderer` subpath.
2431
+ *
2432
+ * The compiler emits `@vue/server-renderer`, which is not a dependency every
2433
+ * app declares; the subpath re-export always resolves alongside `vue` itself.
2434
+ */
2435
+ function normalizeVueServerRendererImport(code) {
2436
+ return code.replace(/\bfrom\s+(['"])@vue\/server-renderer\1/g, "from \"vue/server-renderer\"");
2437
+ }
2438
+ /**
2439
+ * Marks a module whose registration has already been appended.
2440
+ *
2441
+ * Idempotency cannot key on the helper identifiers: an SFC is free to declare
2442
+ * `__vize_useSSRContext` itself, and skipping registration for it would cost it
2443
+ * its initial stylesheet.
2444
+ */
2445
+ const REGISTRATION_MARKER = "/* @vize-ssr-modules-registered */";
2446
+ /**
2447
+ * Matches the `_sfc_main` component declaration the emitted module carries.
2448
+ *
2449
+ * A bare `\b_sfc_main\b` also matches the identifier inside a string literal or
2450
+ * a comment, and wrapping a component that was never declared is a
2451
+ * `ReferenceError` at render time.
2452
+ */
2453
+ const SFC_MAIN_DECLARATION = /\b(?:const|let|var)\s+_sfc_main\s*=/;
2454
+ /**
2455
+ * Register an SFC in `ssrContext.modules` during SSR, the way
2456
+ * `@vitejs/plugin-vue` does.
2457
+ *
2458
+ * After rendering, `vue-bundle-renderer` intersects `ssrContext.modules` with
2459
+ * the client manifest to decide which stylesheets belong in the document head.
2460
+ * A component that never registers itself contributes no `<link>`, so the
2461
+ * server-rendered markup arrives unstyled and only gains its styles once the
2462
+ * route chunk loads on the client — a flash of unstyled content that never
2463
+ * recovers when JavaScript is disabled (#3868).
2464
+ *
2465
+ * The key must be the module's path relative to the Vite root with POSIX
2466
+ * separators, because that is what the client manifest is keyed on.
2467
+ */
2468
+ function ssrModuleRegistrationCode(filePath, root, helpers = {}) {
2469
+ const moduleId = JSON.stringify(toManifestModuleId(filePath, root));
2470
+ const useSSRContext = helpers.useSSRContext ?? "__vize_useSSRContext";
2471
+ const sfcSetup = helpers.sfcSetup ?? "__vize_sfc_setup";
2472
+ return {
2473
+ prologue: `${REGISTRATION_MARKER}\nimport { useSSRContext as ${useSSRContext} } from "vue";`,
2474
+ epilogue: [
2475
+ `const ${sfcSetup} = _sfc_main.setup;`,
2476
+ `_sfc_main.setup = (props, ctx) => {`,
2477
+ ` const ssrContext = ${useSSRContext}();`,
2478
+ ` (ssrContext.modules || (ssrContext.modules = new Set())).add(${moduleId});`,
2479
+ ` return ${sfcSetup} ? ${sfcSetup}(props, ctx) : undefined;`,
2480
+ `};`
2481
+ ].join("\n")
2482
+ };
2483
+ }
2484
+ /**
2485
+ * The client-manifest key for `filePath`: relative to `root`, POSIX separators.
2486
+ *
2487
+ * A path outside the root keeps its absolute form rather than becoming a `../`
2488
+ * chain, matching how Vite keys modules it cannot root-relativize. Only a real
2489
+ * parent-directory step counts as outside: a filename that merely begins with
2490
+ * `..` still lives in the root and is keyed relative to it.
2491
+ */
2492
+ function toManifestModuleId(filePath, root) {
2493
+ const relative = path.relative(root, filePath).replace(/\\/g, "/");
2494
+ if (!relative || relative === ".." || relative.startsWith("../") || path.isAbsolute(relative)) return filePath.replace(/\\/g, "/");
2495
+ return relative;
2496
+ }
2497
+ /**
2498
+ * Wrap an emitted module with the registration.
2499
+ *
2500
+ * The wrapper is appended, so it closes over whatever `setup` the emitter's own
2501
+ * rewrites left in place, but its `import` is *prepended*. A trailing `import`
2502
+ * is legal ESM, yet it makes the module's last import statement its last line,
2503
+ * and Nuxt's auto-import injection then inserts nothing — a component relying on
2504
+ * an auto-imported composable loses that binding and throws `ReferenceError` at
2505
+ * render time (#3868). Leading the module with the import keeps the import
2506
+ * section where every downstream transform expects to find it.
2507
+ *
2508
+ * `useSSRContext()` throws outside a render, so this is a no-op unless `isSsr`.
2509
+ * Modules without an `_sfc_main` declaration — a render-function-only output, or
2510
+ * a boundary placeholder — have no component object to wrap and are returned
2511
+ * untouched.
2512
+ */
2513
+ function appendSsrModuleRegistration(code, filePath, root, isSsr) {
2514
+ if (!isSsr || !SFC_MAIN_DECLARATION.test(code)) return code;
2515
+ if (code.includes(REGISTRATION_MARKER)) return code;
2516
+ const { prologue, epilogue } = ssrModuleRegistrationCode(filePath, root, {
2517
+ useSSRContext: freeIdentifier("__vize_useSSRContext", code),
2518
+ sfcSetup: freeIdentifier("__vize_sfc_setup", code)
2519
+ });
2520
+ return `${prologue}\n${code}\n${epilogue}`;
2521
+ }
2522
+ /**
2523
+ * `base`, or `base` plus the smallest numeric suffix the module does not use.
2524
+ *
2525
+ * Re-declaring an identifier the SFC already bound is a `SyntaxError`, which
2526
+ * would take down the whole module rather than just its stylesheet.
2527
+ */
2528
+ function freeIdentifier(base, code) {
2529
+ if (!new RegExp(`\\b${base}\\b`).test(code)) return base;
2530
+ for (let suffix = 2;; suffix++) {
2531
+ const candidate = `${base}${suffix}`;
2532
+ if (!new RegExp(`\\b${candidate}\\b`).test(code)) return candidate;
2533
+ }
2534
+ }
2535
+ //#endregion
2428
2536
  //#region src/plugin/vite-transform.ts
2429
2537
  function createVirtualTypeScriptTransformer(viteApi) {
2430
2538
  return async (code, id) => {
@@ -2515,9 +2623,6 @@ function getBoundaryPlaceholderCode(realPath, ssr) {
2515
2623
  if (!ssr && boundaryKind === "server") return SERVER_PLACEHOLDER_CODE;
2516
2624
  return null;
2517
2625
  }
2518
- function normalizeVueServerRendererImport(code) {
2519
- return code.replace(/\bfrom\s+(['"])@vue\/server-renderer\1/g, "from \"vue/server-renderer\"");
2520
- }
2521
2626
  function findMacroArtifactModule(state, realPath, ssr, kind) {
2522
2627
  const cache = getEnvironmentCache(state, ssr);
2523
2628
  const extractCss = shouldExtractCssForRequest(state, ssr);
@@ -2578,6 +2683,7 @@ function loadCompiledSfcModule(state, realPath, isSsr, currentBase, loadOptions)
2578
2683
  rewritten.edit(rewriteDynamicTemplateImports(rewritten.code, state.dynamicImportAliasRules));
2579
2684
  rewritten.edit(rewriteStaticAssetUrls(rewritten.code, state.dynamicImportAliasRules));
2580
2685
  rewritten.edit(rewriteImportMetaGlobBase(rewritten.code, realPath, state.root));
2686
+ rewritten.edit(appendSsrModuleRegistration(rewritten.code, realPath, state.root, isSsr));
2581
2687
  return {
2582
2688
  code: rewritten.code,
2583
2689
  map: rewritten.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizejs/vite-plugin",
3
- "version": "0.327.0",
3
+ "version": "0.332.0",
4
4
  "description": "High-performance native Vite plugin for Vue SFC compilation powered by Vize",
5
5
  "keywords": [
6
6
  "compiler",
@@ -45,10 +45,10 @@
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "@vizejs/native": "0.327.0",
48
+ "@vizejs/native": "0.332.0",
49
49
  "oxc-parser": "0.133.0",
50
50
  "tinyglobby": "0.2.16",
51
- "vize": "0.327.0"
51
+ "vize": "0.332.0"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "25.9.2",