vinext 1.2.1 → 1.3.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 (212) hide show
  1. package/README.md +12 -9
  2. package/dist/build/client-build-config.d.ts +64 -3
  3. package/dist/build/client-build-config.js +131 -4
  4. package/dist/build/client-reference-groups.d.ts +163 -0
  5. package/dist/build/client-reference-groups.js +534 -0
  6. package/dist/build/module-dependency-cache.d.ts +31 -0
  7. package/dist/build/module-dependency-cache.js +51 -1
  8. package/dist/build/next-client-runtime-manifests.d.ts +10 -1
  9. package/dist/build/next-client-runtime-manifests.js +19 -4
  10. package/dist/build/nitro-public-files.d.ts +24 -0
  11. package/dist/build/nitro-public-files.js +60 -0
  12. package/dist/build/pages-client-assets-module.js +1 -1
  13. package/dist/build/prerender-paths.js +5 -2
  14. package/dist/build/server-actions-encryption-key.d.ts +23 -0
  15. package/dist/build/server-actions-encryption-key.js +101 -0
  16. package/dist/build/ssr-manifest.d.ts +3 -0
  17. package/dist/build/ssr-manifest.js +10 -1
  18. package/dist/client/client-rewrite-params.d.ts +9 -0
  19. package/dist/client/client-rewrite-params.js +20 -0
  20. package/dist/client/dev-error-overlay.js +2 -1
  21. package/dist/client/navigation-runtime.d.ts +25 -2
  22. package/dist/client/navigation-runtime.js +42 -11
  23. package/dist/client/vinext-next-data.d.ts +0 -1
  24. package/dist/config/config-matchers.d.ts +15 -40
  25. package/dist/config/config-matchers.js +183 -255
  26. package/dist/config/config-source.d.ts +34 -0
  27. package/dist/config/config-source.js +141 -0
  28. package/dist/config/header-params.d.ts +29 -0
  29. package/dist/config/header-params.js +106 -0
  30. package/dist/config/next-config.d.ts +7 -5
  31. package/dist/config/next-config.js +120 -7
  32. package/dist/entries/app-browser-entry.d.ts +14 -1
  33. package/dist/entries/app-browser-entry.js +26 -36
  34. package/dist/entries/app-rsc-entry.d.ts +2 -0
  35. package/dist/entries/app-rsc-entry.js +92 -57
  36. package/dist/entries/app-rsc-manifest.d.ts +10 -0
  37. package/dist/entries/app-rsc-manifest.js +20 -1
  38. package/dist/entries/app-ssr-entry.d.ts +4 -1
  39. package/dist/entries/app-ssr-entry.js +9 -2
  40. package/dist/entries/pages-client-entry.d.ts +1 -0
  41. package/dist/entries/pages-client-entry.js +6 -6
  42. package/dist/entries/pages-server-entry.js +17 -14
  43. package/dist/index.d.ts +11 -0
  44. package/dist/index.js +239 -83
  45. package/dist/init.js +17 -0
  46. package/dist/plugins/optimize-imports.d.ts +25 -2
  47. package/dist/plugins/optimize-imports.js +106 -20
  48. package/dist/plugins/rsc-client-reference-loaders.d.ts +45 -1
  49. package/dist/plugins/rsc-client-reference-loaders.js +336 -18
  50. package/dist/plugins/use-cache-callable.d.ts +5 -0
  51. package/dist/plugins/use-cache-callable.js +30 -8
  52. package/dist/plugins/worker-image-imports.d.ts +1 -0
  53. package/dist/plugins/worker-image-imports.js +1 -1
  54. package/dist/routing/app-route-graph.d.ts +1 -1
  55. package/dist/routing/browser-route-manifest.d.ts +43 -0
  56. package/dist/routing/browser-route-manifest.js +195 -0
  57. package/dist/routing/hashed-route-patterns.d.ts +4 -0
  58. package/dist/routing/hashed-route-patterns.js +22 -0
  59. package/dist/routing/optimistic-route-trie.d.ts +27 -0
  60. package/dist/routing/optimistic-route-trie.js +102 -0
  61. package/dist/routing/route-validation.d.ts +6 -1
  62. package/dist/routing/route-validation.js +26 -10
  63. package/dist/server/app-action-forwarding.d.ts +8 -0
  64. package/dist/server/app-action-forwarding.js +15 -1
  65. package/dist/server/app-browser-entry.js +147 -60
  66. package/dist/server/app-browser-error.d.ts +3 -1
  67. package/dist/server/app-browser-error.js +7 -2
  68. package/dist/server/app-browser-interception-context.d.ts +2 -2
  69. package/dist/server/app-browser-mpa-navigation.d.ts +1 -0
  70. package/dist/server/app-browser-mpa-navigation.js +6 -5
  71. package/dist/server/app-browser-navigation-controller.d.ts +17 -6
  72. package/dist/server/app-browser-navigation-controller.js +88 -26
  73. package/dist/server/app-browser-state.d.ts +2 -2
  74. package/dist/server/app-browser-visible-commit.d.ts +4 -4
  75. package/dist/server/app-client-reference-preloader.d.ts +23 -0
  76. package/dist/server/app-client-reference-preloader.js +30 -7
  77. package/dist/server/app-fallback-renderer.js +2 -1
  78. package/dist/server/app-middleware.d.ts +6 -0
  79. package/dist/server/app-middleware.js +8 -10
  80. package/dist/server/app-optimistic-routing.d.ts +8 -10
  81. package/dist/server/app-optimistic-routing.js +4 -95
  82. package/dist/server/app-page-boundary-render.js +8 -1
  83. package/dist/server/app-page-cache-render.js +1 -0
  84. package/dist/server/app-page-dispatch.js +2 -0
  85. package/dist/server/app-page-render.js +3 -1
  86. package/dist/server/app-page-rsc-render-status.d.ts +1 -0
  87. package/dist/server/app-page-rsc-render-status.js +1 -0
  88. package/dist/server/app-page-search-params-observation.d.ts +1 -4
  89. package/dist/server/app-page-search-params-observation.js +8 -10
  90. package/dist/server/app-page-stream.d.ts +7 -0
  91. package/dist/server/app-page-stream.js +1 -0
  92. package/dist/server/app-pages-bridge.d.ts +2 -1
  93. package/dist/server/app-pages-bridge.js +11 -7
  94. package/dist/server/app-prerender-static-params.js +3 -2
  95. package/dist/server/app-render-dependency.js +42 -2
  96. package/dist/server/app-request-stage-independent-entry.js +2 -2
  97. package/dist/server/app-response-stage-entry.js +3 -3
  98. package/dist/server/app-route-handler-dispatch.js +3 -1
  99. package/dist/server/app-route-handler-execution.d.ts +2 -0
  100. package/dist/server/app-route-handler-execution.js +9 -2
  101. package/dist/server/app-route-handler-middleware-context.d.ts +2 -1
  102. package/dist/server/app-route-handler-middleware-context.js +3 -3
  103. package/dist/server/app-route-handler-response.d.ts +2 -1
  104. package/dist/server/app-route-handler-response.js +2 -2
  105. package/dist/server/app-route-handler-runtime.d.ts +2 -0
  106. package/dist/server/app-route-handler-runtime.js +20 -3
  107. package/dist/server/app-route-module-loader.js +7 -6
  108. package/dist/server/app-route-tree.d.ts +20 -0
  109. package/dist/server/app-route-tree.js +18 -0
  110. package/dist/server/app-router-entry.js +2 -2
  111. package/dist/server/app-rsc-combined-handler.js +8 -1
  112. package/dist/server/app-rsc-errors.d.ts +7 -0
  113. package/dist/server/app-rsc-errors.js +9 -2
  114. package/dist/server/app-rsc-handler.d.ts +4 -1
  115. package/dist/server/app-rsc-handler.js +146 -130
  116. package/dist/server/app-rsc-response-finalizer.d.ts +5 -0
  117. package/dist/server/app-rsc-response-finalizer.js +4 -1
  118. package/dist/server/app-rsc-response-stage.js +3 -1
  119. package/dist/server/app-rsc-route-matching.d.ts +1 -0
  120. package/dist/server/app-rsc-route-matching.js +1 -1
  121. package/dist/server/app-server-action-execution.d.ts +23 -6
  122. package/dist/server/app-server-action-execution.js +50 -56
  123. package/dist/server/app-ssr-entry.d.ts +6 -0
  124. package/dist/server/app-ssr-entry.js +16 -7
  125. package/dist/server/app-ssr-stream.d.ts +7 -0
  126. package/dist/server/app-ssr-stream.js +13 -1
  127. package/dist/server/config-headers.js +12 -3
  128. package/dist/server/isolate-shared-promise.d.ts +10 -0
  129. package/dist/server/isolate-shared-promise.js +33 -0
  130. package/dist/server/isr-cache.js +3 -2
  131. package/dist/server/middleware-matcher-pattern.d.ts +0 -1
  132. package/dist/server/middleware-matcher-pattern.js +11 -140
  133. package/dist/server/middleware-matcher.js +5 -6
  134. package/dist/server/middleware-response-headers.d.ts +31 -0
  135. package/dist/server/middleware-response-headers.js +57 -1
  136. package/dist/server/middleware-runtime.js +26 -13
  137. package/dist/server/navigation-planner.d.ts +2 -2
  138. package/dist/server/nitro-public-files-plugin.d.ts +38 -0
  139. package/dist/server/nitro-public-files-plugin.js +106 -0
  140. package/dist/server/nitro-public-files.d.ts +21 -0
  141. package/dist/server/nitro-public-files.js +39 -0
  142. package/dist/server/pages-asset-tags.d.ts +5 -0
  143. package/dist/server/pages-asset-tags.js +9 -2
  144. package/dist/server/pages-client-assets.d.ts +4 -1
  145. package/dist/server/pages-i18n.d.ts +18 -0
  146. package/dist/server/pages-i18n.js +18 -2
  147. package/dist/server/pages-node-compat.d.ts +5 -3
  148. package/dist/server/pages-node-compat.js +35 -16
  149. package/dist/server/pages-request-pipeline.d.ts +6 -1
  150. package/dist/server/pages-request-pipeline.js +31 -35
  151. package/dist/server/pages-request-stage-entry.js +16 -6
  152. package/dist/server/pages-response-stage-entry.js +1 -1
  153. package/dist/server/pages-revalidate.js +1 -0
  154. package/dist/server/pages-router-entry.js +1 -1
  155. package/dist/server/prod-server.d.ts +2 -2
  156. package/dist/server/prod-server.js +71 -33
  157. package/dist/server/proxy-trust.d.ts +6 -0
  158. package/dist/server/proxy-trust.js +12 -6
  159. package/dist/server/request-pipeline.d.ts +5 -0
  160. package/dist/server/request-pipeline.js +12 -1
  161. package/dist/server/server-reference-loader.js +10 -1
  162. package/dist/server/static-file-cache.js +15 -3
  163. package/dist/server/worker-utils.js +1 -1
  164. package/dist/shims/cache-handler.js +3 -2
  165. package/dist/shims/cache-request-state.d.ts +40 -3
  166. package/dist/shims/cache-request-state.js +70 -5
  167. package/dist/shims/cache-runtime.js +47 -19
  168. package/dist/shims/cache.d.ts +2 -2
  169. package/dist/shims/cache.js +17 -8
  170. package/dist/shims/cdn-purge-routes.d.ts +24 -0
  171. package/dist/shims/cdn-purge-routes.js +77 -0
  172. package/dist/shims/dynamic.js +17 -4
  173. package/dist/shims/form.js +8 -3
  174. package/dist/shims/image-props.d.ts +93 -0
  175. package/dist/shims/image-props.js +323 -0
  176. package/dist/shims/image.d.ts +4 -18
  177. package/dist/shims/image.js +4 -319
  178. package/dist/shims/internal/headers-state.d.ts +7 -0
  179. package/dist/shims/internal/headers-state.js +14 -2
  180. package/dist/shims/internal/hybrid-client-route-owner-direct.d.ts +4 -1
  181. package/dist/shims/internal/hybrid-client-route-owner-direct.js +31 -14
  182. package/dist/shims/internal/hybrid-client-route-owner.js +8 -8
  183. package/dist/shims/link.js +5 -3
  184. package/dist/shims/navigation.d.ts +1 -1
  185. package/dist/shims/navigation.js +17 -5
  186. package/dist/shims/og.js +35 -10
  187. package/dist/shims/request-context.d.ts +13 -0
  188. package/dist/shims/router.js +19 -40
  189. package/dist/shims/server.d.ts +31 -4
  190. package/dist/shims/server.js +58 -10
  191. package/dist/shims/thenable-params.d.ts +6 -1
  192. package/dist/shims/thenable-params.js +11 -2
  193. package/dist/shims/unified-request-context.d.ts +5 -0
  194. package/dist/shims/unified-request-context.js +2 -0
  195. package/dist/utils/asset-prefix.d.ts +7 -0
  196. package/dist/utils/asset-prefix.js +10 -1
  197. package/dist/utils/client-build-manifest.js +12 -5
  198. package/dist/utils/client-runtime-metadata.d.ts +1 -0
  199. package/dist/utils/client-runtime-metadata.js +15 -2
  200. package/dist/utils/lazy-chunks.d.ts +4 -0
  201. package/dist/utils/manifest-paths.d.ts +14 -0
  202. package/dist/utils/manifest-paths.js +22 -1
  203. package/dist/utils/path-to-regexp.d.ts +21 -0
  204. package/dist/{server/middleware-path-to-regexp.js → utils/path-to-regexp.js} +14 -11
  205. package/dist/utils/plugin-react-version.d.ts +15 -0
  206. package/dist/utils/plugin-react-version.js +64 -0
  207. package/dist/utils/public-routes.d.ts +2 -0
  208. package/dist/utils/public-routes.js +18 -7
  209. package/package.json +1 -1
  210. package/dist/server/middleware-path-to-regexp.d.ts +0 -13
  211. package/dist/utils/regex-safety.d.ts +0 -17
  212. package/dist/utils/regex-safety.js +0 -789
package/dist/init.js CHANGED
@@ -2,6 +2,7 @@ import path, { toSlash } from "./deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/
2
2
  import { detectPackageManager, detectPackageManagerName, detectProject, ensureESModule, findViteConfigPath, hasViteConfig, renameCJSConfigs } from "./utils/project.js";
3
3
  import { compactResourceName, cssModulesConfigSource, findConfigKeepingWorkerName, setupCloudflarePlatform, updateViteConfigForCssModules, usesCommonJsViteConfig, validateCloudflarePlatformSetup } from "./init-cloudflare.js";
4
4
  import { getReactUpgradeDeps } from "./utils/react-version.js";
5
+ import { getPluginReactUpgradeDeps } from "./utils/plugin-react-version.js";
5
6
  import fs from "node:fs";
6
7
  import { spawn, spawnSync } from "node:child_process";
7
8
  //#region src/init.ts
@@ -598,6 +599,22 @@ async function init(options) {
598
599
  }
599
600
  }
600
601
  }
602
+ const pluginReactUpgrade = getPluginReactUpgradeDeps(root);
603
+ if (pluginReactUpgrade.length > 0) {
604
+ console.log(` ${terminalStyle.cyan(terminalStyle.bold("Upgrading devDependencies:"))}`);
605
+ console.log(formatList(pluginReactUpgrade.map((dep) => dep.replace(/@latest$/, "")), " "));
606
+ try {
607
+ if (shouldInstall) {
608
+ if (isApproveBuildsError(await installDeps(root, pluginReactUpgrade, exec))) dependencyInstallNeedsApproval = true;
609
+ } else {
610
+ const added = addDependencyEntries(root, pluginReactUpgrade, { dev: true });
611
+ devDependencyEntriesAdded.push(...added);
612
+ }
613
+ } catch (error) {
614
+ if (pmName !== "pnpm" || !isApproveBuildsError(error)) throw error;
615
+ dependencyInstallNeedsApproval = true;
616
+ }
617
+ }
601
618
  if (missingDependencies.length > 0) {
602
619
  console.log(` ${terminalStyle.cyan(terminalStyle.bold("Installing dependencies:"))}`);
603
620
  console.log(formatList(missingDependencies, " "));
@@ -5,16 +5,39 @@ type BarrelExportEntry = {
5
5
  source: string;
6
6
  isNamespace: boolean;
7
7
  originalName?: string;
8
+ /**
9
+ * The outermost module on the way to `source` that RSC replaces with
10
+ * references or wrappers because of its directive. RSC must import the name
11
+ * from it instead.
12
+ */
13
+ rscBoundary?: string;
14
+ /**
15
+ * The same for SSR, where only "use server" and "use cache" modules are
16
+ * replaced with references.
17
+ */
18
+ ssrBoundary?: string;
8
19
  };
9
20
  type BarrelExportMap = Map<string, BarrelExportEntry>;
10
21
  /**
11
22
  * Packages whose barrel imports are automatically optimized.
12
23
  * Matches Next.js's built-in optimizePackageImports defaults plus vinext-specific
13
- * compatibility entries for radix-ui and @chakra-ui/react.
24
+ * compatibility entries for radix-ui, @chakra-ui/react, and @heroui/react.
14
25
  * @see https://github.com/vercel/next.js/blob/9c31bbdaa/packages/next/src/server/config.ts#L1301
15
26
  */
16
27
  export declare const DEFAULT_OPTIMIZE_PACKAGES: string[];
17
- export declare function createOptimizedImportSourceMatcher(packages: Iterable<string>): (code: string) => boolean;
28
+ /**
29
+ * Packages whose subpath imports (`pkg/Sub`) are also optimized, in the RSC
30
+ * environment only. Their subpath entries are themselves barrels: heroui's
31
+ * Toast imports `UNSTABLE_ToastQueue` from "react-aria-components/Toast", whose
32
+ * other exports call createContext() at module scope and import "client-only"
33
+ * (https://github.com/cloudflare/vinext/issues/4007). Like Next.js's default
34
+ * Turbopack build, this drops the side-effect-free entry's "client-only"
35
+ * import: server-safe exports work, and client components still fail when
36
+ * their own modules are evaluated. SSR and the client keep the package's own
37
+ * module graph, so context modules are never instantiated twice there.
38
+ */
39
+ export declare const SUBPATH_OPTIMIZE_PACKAGES: string[];
40
+ export declare function createOptimizedImportSourceMatcher(packages: Iterable<string>, subpathPackages?: Iterable<string>): (code: string) => boolean;
18
41
  /**
19
42
  * Build a map of exported names → source sub-module for a barrel package.
20
43
  *
@@ -21,7 +21,7 @@ async function readFileSafe(filepath) {
21
21
  /**
22
22
  * Packages whose barrel imports are automatically optimized.
23
23
  * Matches Next.js's built-in optimizePackageImports defaults plus vinext-specific
24
- * compatibility entries for radix-ui and @chakra-ui/react.
24
+ * compatibility entries for radix-ui, @chakra-ui/react, and @heroui/react.
25
25
  * @see https://github.com/vercel/next.js/blob/9c31bbdaa/packages/next/src/server/config.ts#L1301
26
26
  */
27
27
  const DEFAULT_OPTIMIZE_PACKAGES = [
@@ -101,10 +101,40 @@ const DEFAULT_OPTIMIZE_PACKAGES = [
101
101
  "react-icons/ti",
102
102
  "react-icons/vsc",
103
103
  "react-icons/wi",
104
- "radix-ui"
104
+ "radix-ui",
105
+ "@heroui/react"
105
106
  ];
106
- function createOptimizedImportSourceMatcher(packages) {
107
- const pattern = [...packages].map(escapeRegExp).join("|");
107
+ /**
108
+ * Packages whose subpath imports (`pkg/Sub`) are also optimized, in the RSC
109
+ * environment only. Their subpath entries are themselves barrels: heroui's
110
+ * Toast imports `UNSTABLE_ToastQueue` from "react-aria-components/Toast", whose
111
+ * other exports call createContext() at module scope and import "client-only"
112
+ * (https://github.com/cloudflare/vinext/issues/4007). Like Next.js's default
113
+ * Turbopack build, this drops the side-effect-free entry's "client-only"
114
+ * import: server-safe exports work, and client components still fail when
115
+ * their own modules are evaluated. SSR and the client keep the package's own
116
+ * module graph, so context modules are never instantiated twice there.
117
+ */
118
+ const SUBPATH_OPTIMIZE_PACKAGES = ["react-aria-components"];
119
+ function isOptimizedSubpath(source, subpathPackages) {
120
+ for (const pkg of subpathPackages) if (source.length > pkg.length + 1 && source.startsWith(`${pkg}/`)) return true;
121
+ return false;
122
+ }
123
+ /**
124
+ * Return the directive that marks a module as an RSC boundary, if any.
125
+ * Re-exports must not be followed through such a module: importing its leaves
126
+ * directly would bypass the client reference, server reference, or cache wrapper.
127
+ */
128
+ function findBoundaryDirective(ast) {
129
+ for (const statement of ast.body) {
130
+ if (statement.type !== "ExpressionStatement" || typeof statement.directive !== "string") return null;
131
+ const directive = statement.directive;
132
+ if (directive === "use client" || directive === "use server" || directive.startsWith("use cache")) return directive;
133
+ }
134
+ return null;
135
+ }
136
+ function createOptimizedImportSourceMatcher(packages, subpathPackages = []) {
137
+ const pattern = [...[...packages].map(escapeRegExp), ...[...subpathPackages].map((pkg) => String.raw`${escapeRegExp(pkg)}/[^"'\s]+`)].join("|");
108
138
  if (!pattern) return () => false;
109
139
  const importFromPattern = new RegExp(String.raw`(?:^|[;}\n\r])\s*import(?!\s*\()(?:(?!\bfrom\b)[\s\S])*?\bfrom\s*["'](?:${pattern})["']`, "m");
110
140
  const quotedSourcePattern = new RegExp(String.raw`["'](?:${pattern})["']`);
@@ -238,6 +268,7 @@ async function buildExportMapFromFile(filePath, readFile, cache, visited, initia
238
268
  return /* @__PURE__ */ new Map();
239
269
  }
240
270
  const exportMap = /* @__PURE__ */ new Map();
271
+ const boundaryDirective = findBoundaryDirective(ast);
241
272
  const importBindings = /* @__PURE__ */ new Map();
242
273
  const localDeclarations = /* @__PURE__ */ new Set();
243
274
  const fileDir = path.dirname(filePath);
@@ -379,6 +410,14 @@ async function buildExportMapFromFile(filePath, readFile, cache, visited, initia
379
410
  break;
380
411
  }
381
412
  }
413
+ if (boundaryDirective) {
414
+ const isSsrBoundary = boundaryDirective !== "use client";
415
+ for (const [name, entry] of exportMap) exportMap.set(name, {
416
+ ...entry,
417
+ rscBoundary: filePath,
418
+ ssrBoundary: isSsrBoundary ? filePath : entry.ssrBoundary
419
+ });
420
+ }
382
421
  cache.set(filePath, exportMap);
383
422
  return exportMap;
384
423
  }
@@ -407,6 +446,15 @@ async function buildBarrelExportMap(entryPath, readFile, cache) {
407
446
  return await buildExportMapFromFile(entryPath, readFile, exportMapCache, /* @__PURE__ */ new Set(), content);
408
447
  }
409
448
  /**
449
+ * Resolve a specifier with Vite's resolver, returning the id only when it is a
450
+ * file in the module graph (not external or virtual).
451
+ */
452
+ async function resolveFileId(ctx, source, importer) {
453
+ const resolved = await ctx.resolve(source, importer, { skipSelf: true });
454
+ if (!resolved || resolved.external || !path.isAbsolute(resolved.id)) return null;
455
+ return resolved.id;
456
+ }
457
+ /**
410
458
  * Creates the vinext:optimize-imports Vite plugin.
411
459
  *
412
460
  * @param nextConfig - Resolved Next.js config (may be undefined before config hook runs).
@@ -420,6 +468,7 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
420
468
  const entryPathCache = /* @__PURE__ */ new Map();
421
469
  let optimizedPackages = /* @__PURE__ */ new Set();
422
470
  let hasOptimizedImportSource = () => false;
471
+ let hasOptimizedRscImportSource = () => false;
423
472
  const registeredBarrels = /* @__PURE__ */ new Set();
424
473
  return {
425
474
  name: "vinext:optimize-imports",
@@ -427,6 +476,7 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
427
476
  const nextConfig = getNextConfig();
428
477
  optimizedPackages = /* @__PURE__ */ new Set([...DEFAULT_OPTIMIZE_PACKAGES, ...nextConfig?.optimizePackageImports ?? []]);
429
478
  hasOptimizedImportSource = createOptimizedImportSourceMatcher(optimizedPackages);
479
+ hasOptimizedRscImportSource = createOptimizedImportSourceMatcher(optimizedPackages, SUBPATH_OPTIMIZE_PACKAGES);
430
480
  entryPathCache.clear();
431
481
  barrelCaches.exportMapCache.clear();
432
482
  barrelCaches.subpkgOrigin.clear();
@@ -434,56 +484,77 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
434
484
  },
435
485
  async resolveId(source) {
436
486
  if (this.environment?.name === "client") return;
437
- const envName = this.environment?.name ?? "ssr";
438
- const barrelEntry = barrelCaches.subpkgOrigin.get(envName)?.get(source) ?? barrelCaches.subpkgOrigin.get(envName === "rsc" ? "ssr" : "rsc")?.get(source);
487
+ const envKey = this.environment?.name === "rsc" ? "rsc" : "ssr";
488
+ const barrelEntry = barrelCaches.subpkgOrigin.get(envKey)?.get(source);
439
489
  if (!barrelEntry) return;
440
490
  return await this.resolve(source, barrelEntry, { skipSelf: true }) ?? void 0;
441
491
  },
442
492
  transform: {
443
493
  filter: {
444
494
  id: {
445
- include: /\.(tsx?|jsx?|mjs)$/,
495
+ include: /\.(tsx?|jsx?|mjs)(?:\?v=\w+)?$/,
446
496
  exclude: VIRTUAL_MODULE_ID_RE
447
497
  },
448
498
  code: /\bimport\b[\s\S]*\bfrom\b/
449
499
  },
450
- async handler(code) {
500
+ async handler(code, id) {
451
501
  const env = this.environment;
452
502
  if (env?.name === "client") return null;
453
503
  const preferReactServer = env?.name === "rsc";
454
504
  const packages = optimizedPackages;
455
- if (!hasOptimizedImportSource(code)) return null;
505
+ if (!(preferReactServer ? hasOptimizedRscImportSource : hasOptimizedImportSource)(code)) return null;
456
506
  let ast;
457
507
  try {
458
508
  ast = parseProgram(code);
459
509
  } catch {
460
510
  return null;
461
511
  }
512
+ if (preferReactServer && findBoundaryDirective(ast) === "use client") return null;
462
513
  const s = new MagicString(code);
463
514
  let hasChanges = false;
464
515
  const root = getRoot();
465
516
  for (const node of ast.body) {
466
517
  if (node.type !== "ImportDeclaration") continue;
467
518
  const importSource = typeof node.source?.value === "string" ? node.source.value : null;
468
- if (!importSource || !packages.has(importSource)) continue;
469
- const cacheKey = `${preferReactServer ? "rsc" : "ssr"}:${importSource}`;
470
- let barrelEntry = entryPathCache.get(cacheKey);
471
- if (barrelEntry === void 0) {
472
- barrelEntry = await resolvePackageEntry(importSource, root, preferReactServer);
473
- entryPathCache.set(cacheKey, barrelEntry ?? null);
519
+ if (!importSource) continue;
520
+ const isSubpath = !packages.has(importSource) && preferReactServer && isOptimizedSubpath(importSource, SUBPATH_OPTIMIZE_PACKAGES);
521
+ if (!isSubpath && !packages.has(importSource)) continue;
522
+ let barrelEntry;
523
+ if (isSubpath) {
524
+ barrelEntry = await resolveFileId(this, importSource, id);
525
+ if (barrelEntry) barrelEntry = barrelEntry.replace(/\?.*$/, "");
526
+ } else {
527
+ const cacheKey = `${preferReactServer ? "rsc" : "ssr"}:${importSource}`;
528
+ barrelEntry = entryPathCache.get(cacheKey);
529
+ if (barrelEntry === void 0) {
530
+ barrelEntry = await resolvePackageEntry(importSource, root, preferReactServer);
531
+ entryPathCache.set(cacheKey, barrelEntry ?? null);
532
+ }
474
533
  }
475
534
  const exportMap = await buildBarrelExportMap(barrelEntry, readFileSafe, barrelCaches.exportMapCache);
476
535
  if (!exportMap || !barrelEntry) continue;
536
+ const getEntry = (name) => {
537
+ const entry = exportMap.get(name);
538
+ const boundary = preferReactServer ? entry?.rscBoundary : entry?.ssrBoundary;
539
+ return boundary ? {
540
+ source: boundary,
541
+ isNamespace: false,
542
+ originalName: name
543
+ } : entry;
544
+ };
477
545
  const envKey = preferReactServer ? "rsc" : "ssr";
478
546
  const registeredKey = `${envKey}:${barrelEntry}`;
479
- if (!registeredBarrels.has(registeredKey)) {
547
+ if (!isSubpath && !registeredBarrels.has(registeredKey)) {
480
548
  registeredBarrels.add(registeredKey);
481
549
  let envOriginMap = barrelCaches.subpkgOrigin.get(envKey);
482
550
  if (!envOriginMap) {
483
551
  envOriginMap = /* @__PURE__ */ new Map();
484
552
  barrelCaches.subpkgOrigin.set(envKey, envOriginMap);
485
553
  }
486
- for (const entry of exportMap.values()) if (!entry.source.startsWith("/") && !entry.source.startsWith(".") && !envOriginMap.has(entry.source)) envOriginMap.set(entry.source, barrelEntry);
554
+ for (const name of exportMap.keys()) {
555
+ const source = getEntry(name).source;
556
+ if (!source.startsWith("/") && !source.startsWith(".") && !envOriginMap.has(source)) envOriginMap.set(source, barrelEntry);
557
+ }
487
558
  }
488
559
  const specifiers = [];
489
560
  let allResolved = true;
@@ -528,11 +599,26 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
528
599
  }
529
600
  continue;
530
601
  }
602
+ if (isSubpath && specifiers.every(({ imported }) => getEntry(imported)?.source === barrelEntry)) continue;
603
+ const resolvedPackageSources = /* @__PURE__ */ new Map();
604
+ if (isSubpath) {
605
+ for (const { imported } of specifiers) {
606
+ const source = getEntry(imported)?.source;
607
+ if (!source || path.isAbsolute(source) || resolvedPackageSources.has(source)) continue;
608
+ const resolvedId = await resolveFileId(this, source, barrelEntry);
609
+ if (!resolvedId) {
610
+ allResolved = false;
611
+ break;
612
+ }
613
+ resolvedPackageSources.set(source, resolvedId);
614
+ }
615
+ if (!allResolved) continue;
616
+ }
531
617
  const bySource = /* @__PURE__ */ new Map();
532
618
  for (const { local, imported } of specifiers) {
533
- const entry = exportMap.get(imported);
619
+ const entry = getEntry(imported);
534
620
  if (!entry) continue;
535
- const resolvedSource = entry.source;
621
+ const resolvedSource = resolvedPackageSources.get(entry.source) ?? entry.source;
536
622
  const key = `${resolvedSource}::${entry.isNamespace}`;
537
623
  let group = bySource.get(key);
538
624
  if (!group) {
@@ -569,4 +655,4 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
569
655
  };
570
656
  }
571
657
  //#endregion
572
- export { DEFAULT_OPTIMIZE_PACKAGES, buildBarrelExportMap, createOptimizeImportsPlugin, createOptimizedImportSourceMatcher };
658
+ export { DEFAULT_OPTIMIZE_PACKAGES, SUBPATH_OPTIMIZE_PACKAGES, buildBarrelExportMap, createOptimizeImportsPlugin, createOptimizedImportSourceMatcher };
@@ -1,4 +1,48 @@
1
+ import { AppRoute } from "../routing/app-route-graph.js";
1
2
  import { Plugin } from "vite";
2
3
  //#region src/plugins/rsc-client-reference-loaders.d.ts
3
- export declare function createRscClientReferenceLoadersPlugin(): Plugin;
4
+ export type RscClientReferenceRouteOptions = {
5
+ /** Maps route file paths to the module ids used by the RSC module graph. */
6
+ canonicalizeModuleId: (id: string) => string;
7
+ /** App Router routes of the current build, or null outside App Router builds. */
8
+ getRoutes: () => readonly AppRoute[] | null;
9
+ /**
10
+ * Files any route's render can show: global-error, and the root boundaries
11
+ * that routes without their own not-found, forbidden or unauthorized use.
12
+ */
13
+ getAlwaysRenderedFiles: () => readonly string[];
14
+ /**
15
+ * The files a render without a route (a route-miss 404) shows: the root
16
+ * layouts and boundaries, and global-not-found.
17
+ */
18
+ getRoutelessFiles: () => readonly string[];
19
+ /** Route-independent roots such as global-error and global-not-found. */
20
+ getSharedRoots: () => readonly string[];
21
+ };
22
+ export type RscClientReferenceGroupingOptions = {
23
+ /** Modules that live in chunks every page loads anyway (React, vinext runtime). */
24
+ isAlwaysLoadedClientModule: (id: string) => boolean;
25
+ /** vinext's own client chunk groups. Any other chunk group disables grouping. */
26
+ ownClientChunkGroups: ReadonlySet<unknown>;
27
+ };
28
+ /**
29
+ * Replaces @vitejs/plugin-rsc's client-reference facades with per-reference
30
+ * loaders. With `routes`, the SSR build also exports the client references
31
+ * each App Router route preloads. With `grouping`, production client builds
32
+ * additionally load references that the same App Router routes reach through
33
+ * one shared route group module (see build/client-reference-groups.ts), so a
34
+ * page fetches one chunk per route group instead of one per `"use client"`
35
+ * module.
36
+ */
37
+ export declare function createRscClientReferenceLoadersPlugin(options?: {
38
+ routes?: RscClientReferenceRouteOptions;
39
+ grouping?: RscClientReferenceGroupingOptions;
40
+ }): Plugin;
41
+ /**
42
+ * Exports a null preload plan from the client-references virtual module when
43
+ * the app registers @vitejs/plugin-rsc itself (`rsc: false`), where vinext
44
+ * doesn't add the loaders plugin above. The App Router SSR entry imports the
45
+ * plan, and null makes it preload every client reference.
46
+ */
47
+ export declare function createRouteClientReferencesFallbackPlugin(): Plugin;
4
48
  //#endregion