vinext 0.1.1 → 0.1.3

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 (266) hide show
  1. package/README.md +2 -5
  2. package/dist/build/client-build-config.d.ts +7 -1
  3. package/dist/build/client-build-config.js +9 -1
  4. package/dist/build/prerender.d.ts +9 -1
  5. package/dist/build/prerender.js +41 -12
  6. package/dist/build/run-prerender.d.ts +10 -2
  7. package/dist/build/run-prerender.js +15 -1
  8. package/dist/check.js +4 -3
  9. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  10. package/dist/client/app-nav-failure-handler.js +44 -0
  11. package/dist/client/navigation-runtime.d.ts +3 -2
  12. package/dist/client/vinext-next-data.d.ts +18 -1
  13. package/dist/client/window-next.d.ts +8 -5
  14. package/dist/client/window-next.js +12 -1
  15. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  16. package/dist/config/config-matchers.d.ts +11 -4
  17. package/dist/config/config-matchers.js +88 -16
  18. package/dist/config/next-config.d.ts +59 -4
  19. package/dist/config/next-config.js +149 -48
  20. package/dist/deploy.d.ts +30 -11
  21. package/dist/deploy.js +189 -101
  22. package/dist/entries/app-browser-entry.d.ts +9 -3
  23. package/dist/entries/app-browser-entry.js +21 -3
  24. package/dist/entries/app-rsc-entry.d.ts +2 -0
  25. package/dist/entries/app-rsc-entry.js +71 -6
  26. package/dist/entries/app-rsc-manifest.js +2 -0
  27. package/dist/entries/app-ssr-entry.js +1 -1
  28. package/dist/entries/pages-client-entry.js +54 -9
  29. package/dist/entries/pages-server-entry.js +48 -11
  30. package/dist/index.d.ts +0 -2
  31. package/dist/index.js +285 -139
  32. package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
  33. package/dist/plugins/dynamic-preload-metadata.js +415 -0
  34. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  35. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  36. package/dist/plugins/og-assets.js +2 -2
  37. package/dist/plugins/optimize-imports.d.ts +10 -5
  38. package/dist/plugins/optimize-imports.js +27 -21
  39. package/dist/plugins/postcss.js +7 -7
  40. package/dist/plugins/sass.d.ts +53 -24
  41. package/dist/plugins/sass.js +249 -1
  42. package/dist/plugins/typeof-window.d.ts +14 -0
  43. package/dist/plugins/typeof-window.js +150 -0
  44. package/dist/plugins/wasm-module-import.d.ts +15 -0
  45. package/dist/plugins/wasm-module-import.js +50 -0
  46. package/dist/routing/app-route-graph.d.ts +25 -2
  47. package/dist/routing/app-route-graph.js +91 -22
  48. package/dist/routing/file-matcher.d.ts +10 -1
  49. package/dist/routing/file-matcher.js +23 -2
  50. package/dist/routing/pages-router.js +3 -3
  51. package/dist/routing/utils.d.ts +35 -6
  52. package/dist/routing/utils.js +59 -7
  53. package/dist/server/api-handler.d.ts +6 -1
  54. package/dist/server/api-handler.js +21 -15
  55. package/dist/server/app-browser-action-result.d.ts +19 -6
  56. package/dist/server/app-browser-action-result.js +19 -10
  57. package/dist/server/app-browser-entry.js +269 -297
  58. package/dist/server/app-browser-error.d.ts +10 -3
  59. package/dist/server/app-browser-error.js +47 -6
  60. package/dist/server/app-browser-history-controller.d.ts +104 -0
  61. package/dist/server/app-browser-history-controller.js +210 -0
  62. package/dist/server/app-browser-hydration.d.ts +2 -0
  63. package/dist/server/app-browser-hydration.js +1 -0
  64. package/dist/server/app-browser-navigation-controller.d.ts +7 -4
  65. package/dist/server/app-browser-navigation-controller.js +33 -9
  66. package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
  67. package/dist/server/app-browser-rsc-redirect.js +30 -8
  68. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  69. package/dist/server/app-browser-server-action-navigation.js +9 -0
  70. package/dist/server/app-browser-state.js +4 -7
  71. package/dist/server/app-browser-stream.js +86 -43
  72. package/dist/server/app-browser-visible-commit.js +1 -1
  73. package/dist/server/app-elements-wire.d.ts +6 -1
  74. package/dist/server/app-elements-wire.js +14 -4
  75. package/dist/server/app-elements.d.ts +2 -2
  76. package/dist/server/app-elements.js +2 -2
  77. package/dist/server/app-fallback-renderer.d.ts +3 -1
  78. package/dist/server/app-fallback-renderer.js +6 -2
  79. package/dist/server/app-middleware.js +1 -0
  80. package/dist/server/app-optimistic-routing.js +24 -3
  81. package/dist/server/app-page-boundary-render.d.ts +3 -1
  82. package/dist/server/app-page-boundary-render.js +31 -16
  83. package/dist/server/app-page-cache-render.d.ts +53 -0
  84. package/dist/server/app-page-cache-render.js +91 -0
  85. package/dist/server/app-page-cache.d.ts +16 -2
  86. package/dist/server/app-page-cache.js +71 -8
  87. package/dist/server/app-page-dispatch.d.ts +34 -0
  88. package/dist/server/app-page-dispatch.js +167 -97
  89. package/dist/server/app-page-element-builder.d.ts +23 -2
  90. package/dist/server/app-page-element-builder.js +42 -10
  91. package/dist/server/app-page-execution.d.ts +7 -2
  92. package/dist/server/app-page-execution.js +53 -18
  93. package/dist/server/app-page-probe.d.ts +1 -0
  94. package/dist/server/app-page-probe.js +4 -0
  95. package/dist/server/app-page-render-observation.d.ts +3 -1
  96. package/dist/server/app-page-render-observation.js +17 -1
  97. package/dist/server/app-page-render.d.ts +13 -2
  98. package/dist/server/app-page-render.js +48 -17
  99. package/dist/server/app-page-request.d.ts +3 -0
  100. package/dist/server/app-page-request.js +5 -3
  101. package/dist/server/app-page-response.js +1 -1
  102. package/dist/server/app-page-route-wiring.d.ts +5 -1
  103. package/dist/server/app-page-route-wiring.js +21 -11
  104. package/dist/server/app-page-stream.d.ts +16 -9
  105. package/dist/server/app-page-stream.js +12 -9
  106. package/dist/server/app-pages-bridge.d.ts +18 -0
  107. package/dist/server/app-pages-bridge.js +22 -5
  108. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  109. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  110. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  111. package/dist/server/app-ppr-fallback-shell.js +8 -1
  112. package/dist/server/app-route-handler-dispatch.js +9 -2
  113. package/dist/server/app-route-handler-policy.d.ts +1 -0
  114. package/dist/server/app-route-handler-response.js +11 -10
  115. package/dist/server/app-route-handler-runtime.js +12 -1
  116. package/dist/server/app-router-entry.js +5 -0
  117. package/dist/server/app-rsc-cache-busting.js +2 -0
  118. package/dist/server/app-rsc-handler.d.ts +25 -0
  119. package/dist/server/app-rsc-handler.js +153 -53
  120. package/dist/server/app-rsc-response-finalizer.js +1 -1
  121. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  122. package/dist/server/app-rsc-route-matching.js +2 -0
  123. package/dist/server/app-segment-config.d.ts +9 -1
  124. package/dist/server/app-segment-config.js +12 -3
  125. package/dist/server/app-server-action-execution.d.ts +12 -0
  126. package/dist/server/app-server-action-execution.js +47 -15
  127. package/dist/server/app-ssr-entry.d.ts +2 -0
  128. package/dist/server/app-ssr-entry.js +81 -8
  129. package/dist/server/app-ssr-stream.js +9 -1
  130. package/dist/server/cache-control.js +4 -0
  131. package/dist/server/dev-lockfile.js +2 -1
  132. package/dist/server/dev-server.d.ts +2 -2
  133. package/dist/server/dev-server.js +287 -63
  134. package/dist/server/headers.d.ts +8 -1
  135. package/dist/server/headers.js +8 -1
  136. package/dist/server/hybrid-route-priority.d.ts +22 -0
  137. package/dist/server/hybrid-route-priority.js +33 -0
  138. package/dist/server/image-optimization.d.ts +18 -9
  139. package/dist/server/image-optimization.js +37 -23
  140. package/dist/server/implicit-tags.d.ts +2 -1
  141. package/dist/server/implicit-tags.js +4 -1
  142. package/dist/server/instrumentation-runtime.d.ts +6 -0
  143. package/dist/server/instrumentation-runtime.js +8 -0
  144. package/dist/server/isr-decision.d.ts +79 -0
  145. package/dist/server/isr-decision.js +70 -0
  146. package/dist/server/metadata-route-response.js +5 -3
  147. package/dist/server/middleware-runtime.d.ts +13 -0
  148. package/dist/server/middleware-runtime.js +11 -7
  149. package/dist/server/middleware.js +1 -0
  150. package/dist/server/navigation-planner.d.ts +186 -22
  151. package/dist/server/navigation-planner.js +302 -0
  152. package/dist/server/navigation-trace.d.ts +18 -1
  153. package/dist/server/navigation-trace.js +18 -1
  154. package/dist/server/normalize-path.d.ts +0 -8
  155. package/dist/server/normalize-path.js +3 -1
  156. package/dist/server/otel-tracer-extension.d.ts +45 -0
  157. package/dist/server/otel-tracer-extension.js +89 -0
  158. package/dist/server/pages-api-route.d.ts +20 -3
  159. package/dist/server/pages-api-route.js +19 -3
  160. package/dist/server/pages-asset-tags.d.ts +16 -4
  161. package/dist/server/pages-asset-tags.js +22 -12
  162. package/dist/server/pages-data-route.d.ts +8 -1
  163. package/dist/server/pages-data-route.js +16 -3
  164. package/dist/server/pages-get-initial-props.d.ts +54 -4
  165. package/dist/server/pages-get-initial-props.js +43 -1
  166. package/dist/server/pages-node-compat.d.ts +3 -11
  167. package/dist/server/pages-node-compat.js +175 -122
  168. package/dist/server/pages-page-data.d.ts +39 -2
  169. package/dist/server/pages-page-data.js +261 -46
  170. package/dist/server/pages-page-handler.d.ts +5 -2
  171. package/dist/server/pages-page-handler.js +78 -25
  172. package/dist/server/pages-page-response.d.ts +47 -2
  173. package/dist/server/pages-page-response.js +73 -9
  174. package/dist/server/pages-readiness.d.ts +1 -1
  175. package/dist/server/pages-request-pipeline.d.ts +16 -1
  176. package/dist/server/pages-request-pipeline.js +96 -38
  177. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  178. package/dist/server/pregenerated-concrete-paths.js +2 -19
  179. package/dist/server/prerender-manifest.d.ts +33 -0
  180. package/dist/server/prerender-manifest.js +54 -0
  181. package/dist/server/prerender-route-params.d.ts +1 -2
  182. package/dist/server/prod-server.d.ts +39 -1
  183. package/dist/server/prod-server.js +107 -37
  184. package/dist/server/request-pipeline.d.ts +3 -15
  185. package/dist/server/request-pipeline.js +58 -47
  186. package/dist/server/rsc-stream-hints.d.ts +5 -1
  187. package/dist/server/rsc-stream-hints.js +6 -1
  188. package/dist/server/seed-cache.js +10 -18
  189. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  190. package/dist/shims/app-router-scroll-state.js +14 -2
  191. package/dist/shims/app-router-scroll.d.ts +3 -0
  192. package/dist/shims/app-router-scroll.js +28 -18
  193. package/dist/shims/cache-runtime.js +12 -4
  194. package/dist/shims/cache.d.ts +1 -0
  195. package/dist/shims/cache.js +1 -1
  196. package/dist/shims/cdn-cache.d.ts +5 -5
  197. package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
  198. package/dist/shims/dynamic-preload-chunks.js +79 -0
  199. package/dist/shims/dynamic.d.ts +4 -0
  200. package/dist/shims/dynamic.js +4 -2
  201. package/dist/shims/error-boundary.d.ts +6 -4
  202. package/dist/shims/error-boundary.js +7 -0
  203. package/dist/shims/error.js +38 -11
  204. package/dist/shims/error.react-server.d.ts +9 -0
  205. package/dist/shims/error.react-server.js +6 -0
  206. package/dist/shims/fetch-cache.d.ts +11 -1
  207. package/dist/shims/fetch-cache.js +55 -20
  208. package/dist/shims/hash-scroll.js +6 -1
  209. package/dist/shims/head.js +6 -1
  210. package/dist/shims/headers.d.ts +16 -2
  211. package/dist/shims/headers.js +66 -5
  212. package/dist/shims/image-config.js +7 -1
  213. package/dist/shims/internal/als-registry.js +28 -1
  214. package/dist/shims/internal/app-route-detection.d.ts +6 -3
  215. package/dist/shims/internal/app-route-detection.js +18 -23
  216. package/dist/shims/internal/app-router-context.d.ts +5 -0
  217. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  218. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  219. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  220. package/dist/shims/internal/navigation-untracked.js +55 -0
  221. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  222. package/dist/shims/internal/pages-data-target.js +17 -8
  223. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  224. package/dist/shims/internal/pages-router-accessor.js +13 -0
  225. package/dist/shims/internal/router-context.d.ts +2 -1
  226. package/dist/shims/internal/router-context.js +3 -1
  227. package/dist/shims/link.js +12 -5
  228. package/dist/shims/metadata.d.ts +6 -2
  229. package/dist/shims/metadata.js +32 -14
  230. package/dist/shims/navigation.d.ts +14 -17
  231. package/dist/shims/navigation.js +93 -46
  232. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  233. package/dist/shims/ppr-fallback-shell.js +28 -7
  234. package/dist/shims/router.d.ts +13 -2
  235. package/dist/shims/router.js +434 -116
  236. package/dist/shims/script-nonce-context.d.ts +1 -1
  237. package/dist/shims/script-nonce-context.js +11 -3
  238. package/dist/shims/server.d.ts +33 -2
  239. package/dist/shims/server.js +75 -18
  240. package/dist/shims/slot.js +1 -1
  241. package/dist/shims/unified-request-context.js +2 -0
  242. package/dist/typegen.js +1 -0
  243. package/dist/utils/built-asset-url.d.ts +4 -0
  244. package/dist/utils/built-asset-url.js +11 -0
  245. package/dist/utils/client-build-manifest.js +15 -5
  246. package/dist/utils/client-runtime-metadata.d.ts +45 -0
  247. package/dist/utils/client-runtime-metadata.js +63 -0
  248. package/dist/utils/commonjs-loader.d.ts +16 -0
  249. package/dist/utils/commonjs-loader.js +100 -0
  250. package/dist/utils/deployment-id.d.ts +8 -0
  251. package/dist/utils/deployment-id.js +22 -0
  252. package/dist/utils/hash.d.ts +17 -1
  253. package/dist/utils/hash.js +36 -1
  254. package/dist/utils/html-limited-bots.d.ts +18 -1
  255. package/dist/utils/html-limited-bots.js +23 -1
  256. package/dist/utils/lazy-chunks.d.ts +27 -1
  257. package/dist/utils/lazy-chunks.js +65 -1
  258. package/dist/utils/manifest-paths.d.ts +20 -2
  259. package/dist/utils/manifest-paths.js +38 -3
  260. package/dist/utils/parse-cookie.d.ts +13 -0
  261. package/dist/utils/parse-cookie.js +52 -0
  262. package/dist/utils/path.d.ts +8 -1
  263. package/dist/utils/path.js +13 -1
  264. package/package.json +2 -2
  265. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  266. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -1,3 +1,5 @@
1
+ import { normalizePathSeparators } from "../utils/path.js";
2
+ import { escapeRegExp } from "../utils/regex.js";
1
3
  import { getAstName } from "./ast-utils.js";
2
4
  import { createRequire } from "node:module";
3
5
  import path from "node:path";
@@ -99,6 +101,12 @@ const DEFAULT_OPTIMIZE_PACKAGES = [
99
101
  "react-icons/wi",
100
102
  "radix-ui"
101
103
  ];
104
+ function createOptimizedImportSourceMatcher(packages) {
105
+ const pattern = [...packages].map(escapeRegExp).join("|");
106
+ if (!pattern) return () => false;
107
+ const importFromPattern = new RegExp(String.raw`(?:^|[;}\n\r])\s*import(?!\s*\()(?:(?!\bfrom\b)[\s\S])*?\bfrom\s*["'](?:${pattern})["']`, "m");
108
+ return (code) => code.includes("import") && code.includes("from") && importFromPattern.test(code);
109
+ }
102
110
  /**
103
111
  * Resolve a package.json exports value to a string entry path.
104
112
  * Prefers node → import → module → default conditions, recursing into nested objects.
@@ -185,12 +193,12 @@ async function resolvePackageEntry(packageName, projectRoot, preferReactServer)
185
193
  const dotExport = pkgJson.exports["."];
186
194
  if (dotExport) {
187
195
  const entryPath = resolveExportsValue(dotExport, preferReactServer);
188
- if (entryPath) return path.resolve(pkgDir, entryPath).split(path.sep).join("/");
196
+ if (entryPath) return normalizePathSeparators(path.resolve(pkgDir, entryPath));
189
197
  }
190
198
  }
191
199
  const entryField = pkgJson.module ?? pkgJson.main;
192
- if (typeof entryField === "string") return path.resolve(pkgDir, entryField).split(path.sep).join("/");
193
- return createRequire(path.join(projectRoot, "package.json")).resolve(packageName).split(path.sep).join("/");
200
+ if (typeof entryField === "string") return normalizePathSeparators(path.resolve(pkgDir, entryField));
201
+ return normalizePathSeparators(createRequire(path.join(projectRoot, "package.json")).resolve(packageName));
194
202
  } catch {
195
203
  return null;
196
204
  }
@@ -228,14 +236,14 @@ async function buildExportMapFromFile(filePath, readFile, cache, visited, initia
228
236
  const exportMap = /* @__PURE__ */ new Map();
229
237
  const importBindings = /* @__PURE__ */ new Map();
230
238
  const localDeclarations = /* @__PURE__ */ new Set();
231
- const fileDir = path.dirname(filePath);
239
+ const fileDir = path.posix.dirname(filePath);
232
240
  /**
233
241
  * Normalize a source specifier: resolve relative paths to absolute so that
234
242
  * entries in the export map always store absolute paths for file references.
235
243
  * Bare package specifiers (e.g. "@radix-ui/react-slot") are returned unchanged.
236
244
  */
237
245
  function normalizeSource(source) {
238
- return source.startsWith(".") ? path.resolve(fileDir, source).split(path.sep).join("/") : source;
246
+ return source.startsWith(".") ? path.posix.join(fileDir, source) : source;
239
247
  }
240
248
  function recordLocalDeclaration(node) {
241
249
  if (!node) return;
@@ -297,7 +305,7 @@ async function buildExportMapFromFile(filePath, readFile, cache, visited, initia
297
305
  isNamespace: true
298
306
  });
299
307
  } else if (rawSource.startsWith(".")) {
300
- const subPath = path.resolve(fileDir, rawSource).split(path.sep).join("/");
308
+ const subPath = path.posix.join(fileDir, rawSource);
301
309
  const candidates = [
302
310
  subPath,
303
311
  `${subPath}.js`,
@@ -386,12 +394,15 @@ async function buildExportMapFromFile(filePath, readFile, cache, visited, initia
386
394
  * Handles: `export * as X from`, `export { A } from`, `import * as X; export { X }`,
387
395
  * and `export * from "./sub"` (recursively resolves wildcard re-exports).
388
396
  *
389
- * Returns null if the entry cannot be resolved, the file cannot be read, or
390
- * the file has a parse error. Returns an empty map if the file is valid but
391
- * exports nothing.
397
+ * Returns null if `entryPath` is empty, the file cannot be read, or the file
398
+ * has a parse error. Returns an empty map if the file is valid but exports
399
+ * nothing.
400
+ *
401
+ * @param entryPath - Pre-resolved absolute path to the barrel entry file (the
402
+ * caller owns entry resolution + its caching), or null when it could not be
403
+ * resolved.
392
404
  */
393
- async function buildBarrelExportMap(packageName, resolveEntry, readFile, cache) {
394
- const entryPath = resolveEntry(packageName);
405
+ async function buildBarrelExportMap(entryPath, readFile, cache) {
395
406
  if (!entryPath) return null;
396
407
  const exportMapCache = cache ?? /* @__PURE__ */ new Map();
397
408
  const cached = exportMapCache.get(entryPath);
@@ -413,14 +424,14 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
413
424
  };
414
425
  const entryPathCache = /* @__PURE__ */ new Map();
415
426
  let optimizedPackages = /* @__PURE__ */ new Set();
416
- let quotedPackages = [];
427
+ let hasOptimizedImportSource = () => false;
417
428
  const registeredBarrels = /* @__PURE__ */ new Set();
418
429
  return {
419
430
  name: "vinext:optimize-imports",
420
431
  buildStart() {
421
432
  const nextConfig = getNextConfig();
422
433
  optimizedPackages = new Set([...DEFAULT_OPTIMIZE_PACKAGES, ...nextConfig?.optimizePackageImports ?? []]);
423
- quotedPackages = [...optimizedPackages].flatMap((pkg) => [`"${pkg}"`, `'${pkg}'`]);
434
+ hasOptimizedImportSource = createOptimizedImportSourceMatcher(optimizedPackages);
424
435
  entryPathCache.clear();
425
436
  barrelCaches.exportMapCache.clear();
426
437
  barrelCaches.subpkgOrigin.clear();
@@ -441,12 +452,7 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
441
452
  const preferReactServer = env?.name === "rsc";
442
453
  if (id.startsWith("\0")) return null;
443
454
  const packages = optimizedPackages;
444
- let hasBarrelImport = false;
445
- for (const quoted of quotedPackages) if (code.includes(quoted)) {
446
- hasBarrelImport = true;
447
- break;
448
- }
449
- if (!hasBarrelImport) return null;
455
+ if (!hasOptimizedImportSource(code)) return null;
450
456
  let ast;
451
457
  try {
452
458
  ast = parseAst(code);
@@ -466,7 +472,7 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
466
472
  barrelEntry = await resolvePackageEntry(importSource, root, preferReactServer);
467
473
  entryPathCache.set(cacheKey, barrelEntry ?? null);
468
474
  }
469
- const exportMap = await buildBarrelExportMap(importSource, () => barrelEntry ?? null, readFileSafe, barrelCaches.exportMapCache);
475
+ const exportMap = await buildBarrelExportMap(barrelEntry, readFileSafe, barrelCaches.exportMapCache);
470
476
  if (!exportMap || !barrelEntry) continue;
471
477
  const envKey = preferReactServer ? "rsc" : "ssr";
472
478
  const registeredKey = `${envKey}:${barrelEntry}`;
@@ -572,4 +578,4 @@ function createOptimizeImportsPlugin(getNextConfig, getRoot) {
572
578
  };
573
579
  }
574
580
  //#endregion
575
- export { DEFAULT_OPTIMIZE_PACKAGES, buildBarrelExportMap, createOptimizeImportsPlugin };
581
+ export { DEFAULT_OPTIMIZE_PACKAGES, buildBarrelExportMap, createOptimizeImportsPlugin, createOptimizedImportSourceMatcher };
@@ -1,8 +1,11 @@
1
+ import { importExportWithCommonJsFallback } from "../utils/commonjs-loader.js";
1
2
  import { createRequire } from "node:module";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
- import { pathToFileURL } from "node:url";
5
5
  //#region src/plugins/postcss.ts
6
+ async function loadPluginExport(resolvedPath) {
7
+ return importExportWithCommonJsFallback(resolvedPath);
8
+ }
6
9
  /**
7
10
  * PostCSS config file names to search for, in priority order.
8
11
  * Matches the same search order as postcss-load-config / lilconfig.
@@ -65,8 +68,7 @@ async function resolvePostcssStringPluginsUncached(projectRoot) {
65
68
  if (configPath.endsWith(".postcssrc")) {
66
69
  if (fs.readFileSync(configPath, "utf-8").trim().startsWith("{")) return;
67
70
  }
68
- const mod = await import(pathToFileURL(configPath).href);
69
- config = mod.default ?? mod;
71
+ config = await importExportWithCommonJsFallback(configPath);
70
72
  } catch {
71
73
  return;
72
74
  }
@@ -76,14 +78,12 @@ async function resolvePostcssStringPluginsUncached(projectRoot) {
76
78
  try {
77
79
  return { plugins: await Promise.all(config.plugins.filter(Boolean).map(async (plugin) => {
78
80
  if (typeof plugin === "string") {
79
- const mod = await import(pathToFileURL(req.resolve(plugin)).href);
80
- const fn = mod.default ?? mod;
81
+ const fn = await loadPluginExport(req.resolve(plugin));
81
82
  return typeof fn === "function" ? fn() : fn;
82
83
  }
83
84
  if (Array.isArray(plugin) && typeof plugin[0] === "string") {
84
85
  const [name, options] = plugin;
85
- const mod = await import(pathToFileURL(req.resolve(name)).href);
86
- const fn = mod.default ?? mod;
86
+ const fn = await loadPluginExport(req.resolve(name));
87
87
  return typeof fn === "function" ? fn(options) : fn;
88
88
  }
89
89
  return plugin;
@@ -1,33 +1,62 @@
1
+ import { ResolvedConfig } from "vite";
2
+
1
3
  //#region src/plugins/sass.d.ts
2
- /**
3
- * Map a Next.js `sassOptions` object onto Vite's
4
- * `css.preprocessorOptions.scss` / `.sass` shape.
5
- *
6
- * Next.js (webpack + sass-loader) accepts:
7
- * - `additionalData` (or legacy `prependData`) — prepended to every source
8
- * - `includePaths` — directories searched by `@import`
9
- * - `loadPaths` — modern Sass equivalent of `includePaths`
10
- * - `implementation` — Sass implementation package name (e.g. `sass-embedded`)
11
- * - other Sass options that get forwarded as-is
12
- *
13
- * Reference (Next.js source — destructures the same keys before forwarding
14
- * the rest to sass-loader):
15
- * .nextjs-ref/packages/next/src/build/webpack/config/blocks/css/index.ts#L150-L180
16
- * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/webpack/config/blocks/css/index.ts
17
- *
18
- * Vite expects:
19
- * - `additionalData` (string or function) on the preprocessor options
20
- * - modern Sass options (`loadPaths`, `importers`, `implementation`, …)
21
- * flattened next to `additionalData`
22
- *
23
- * @see https://vite.dev/config/shared-options.html#css-preprocessoroptions
24
- */
25
4
  type AdditionalData = string | ((source: string, filename: string) => string | Promise<string>);
26
5
  type VitePreprocessorOptions = {
27
6
  additionalData?: AdditionalData;
28
7
  loadPaths?: string[];
29
8
  [key: string]: any;
30
9
  };
10
+ /**
11
+ * Create a Sass `FileImporter` that resolves webpack-style tilde (`~`) imports.
12
+ *
13
+ * Next.js (via sass-loader's `webpackImporter`) supports two tilde forms:
14
+ *
15
+ * 1. `~pkg/path` — resolves `pkg/path` from `node_modules`. Used for
16
+ * third-party SCSS/CSS, e.g. `@import '~nprogress/nprogress.css'`.
17
+ *
18
+ * 2. `~/path` — resolves relative to the **project root** (the `~` acts as
19
+ * an alias for the root). Used with Turbopack's `resolveAlias: { '~*': '*' }`
20
+ * convention, e.g. `@use '~/styles/variables' as *`.
21
+ *
22
+ * Vite's built-in Sass resolver does not strip the `~` prefix, so any SCSS
23
+ * that uses tilde imports fails with "Can't find stylesheet to import" errors.
24
+ * This `FileImporter` runs before Vite's internal importer (added at the end
25
+ * of `importers[]` in the vite:css plugin) and canonicalises tilde URLs so
26
+ * Sass can load them from the filesystem.
27
+ *
28
+ * The returned object implements the modern Sass `FileImporter` interface:
29
+ * `findFileUrl` returns a `file://` URL and Sass automatically handles partial
30
+ * resolution (`_variables.scss` for `variables`), index files, and extensions.
31
+ *
32
+ * @param root - Absolute path to the Vite project root (used as the base for
33
+ * `~/path` resolution and for locating `node_modules`).
34
+ */
35
+ declare function createSassTildeImporter(root: string): {
36
+ findFileUrl(url: string): URL | null;
37
+ };
31
38
  declare function buildSassPreprocessorOptions(sassOptions: Record<string, unknown> | null | undefined): VitePreprocessorOptions | undefined;
39
+ /**
40
+ * Create a per-build binding of {@link SassAwareFileSystemLoader}.
41
+ *
42
+ * Returns:
43
+ * - `Loader` — a class to inject as postcss-modules' `css.modules.Loader`
44
+ * option. postcss-modules instantiates it with the fixed
45
+ * `(root, plugins, fileResolve)` signature, so the resolved Vite config is
46
+ * captured in this factory's closure rather than passed to the constructor.
47
+ * - `setResolvedConfig` — called from vinext's `configResolved` hook to bind
48
+ * that build's resolved config.
49
+ *
50
+ * One binding is created per vinext plugin instance, so concurrent or
51
+ * back-to-back builds in a single process never observe another build's
52
+ * config (root, sass options, `generateScopedName`, logger, …).
53
+ */
54
+ declare function createSassAwareFileSystemLoader(): {
55
+ Loader: new (root: string, plugins: unknown[], fileResolve?: (newPath: string, relativeTo: string) => Promise<string>) => {
56
+ fetch(newPath: string, relativeTo: string, trace?: string): Promise<Record<string, string>>;
57
+ readonly finalSource: string;
58
+ };
59
+ setResolvedConfig: (config: ResolvedConfig) => void;
60
+ };
32
61
  //#endregion
33
- export { buildSassPreprocessorOptions };
62
+ export { buildSassPreprocessorOptions, createSassAwareFileSystemLoader, createSassTildeImporter };
@@ -1,4 +1,80 @@
1
+ import { createRequire } from "node:module";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { preprocessCSS } from "vite";
5
+ import { pathToFileURL } from "node:url";
1
6
  //#region src/plugins/sass.ts
7
+ /**
8
+ * Map a Next.js `sassOptions` object onto Vite's
9
+ * `css.preprocessorOptions.scss` / `.sass` shape.
10
+ *
11
+ * Next.js (webpack + sass-loader) accepts:
12
+ * - `additionalData` (or legacy `prependData`) — prepended to every source
13
+ * - `includePaths` — directories searched by `@import`
14
+ * - `loadPaths` — modern Sass equivalent of `includePaths`
15
+ * - `implementation` — Sass implementation package name (e.g. `sass-embedded`)
16
+ * - other Sass options that get forwarded as-is
17
+ *
18
+ * Reference (Next.js source — destructures the same keys before forwarding
19
+ * the rest to sass-loader):
20
+ * .nextjs-ref/packages/next/src/build/webpack/config/blocks/css/index.ts#L150-L180
21
+ * https://github.com/vercel/next.js/blob/canary/packages/next/src/build/webpack/config/blocks/css/index.ts
22
+ *
23
+ * Vite expects:
24
+ * - `additionalData` (string or function) on the preprocessor options
25
+ * - modern Sass options (`loadPaths`, `importers`, `implementation`, …)
26
+ * flattened next to `additionalData`
27
+ *
28
+ * @see https://vite.dev/config/shared-options.html#css-preprocessoroptions
29
+ */
30
+ /**
31
+ * Create a Sass `FileImporter` that resolves webpack-style tilde (`~`) imports.
32
+ *
33
+ * Next.js (via sass-loader's `webpackImporter`) supports two tilde forms:
34
+ *
35
+ * 1. `~pkg/path` — resolves `pkg/path` from `node_modules`. Used for
36
+ * third-party SCSS/CSS, e.g. `@import '~nprogress/nprogress.css'`.
37
+ *
38
+ * 2. `~/path` — resolves relative to the **project root** (the `~` acts as
39
+ * an alias for the root). Used with Turbopack's `resolveAlias: { '~*': '*' }`
40
+ * convention, e.g. `@use '~/styles/variables' as *`.
41
+ *
42
+ * Vite's built-in Sass resolver does not strip the `~` prefix, so any SCSS
43
+ * that uses tilde imports fails with "Can't find stylesheet to import" errors.
44
+ * This `FileImporter` runs before Vite's internal importer (added at the end
45
+ * of `importers[]` in the vite:css plugin) and canonicalises tilde URLs so
46
+ * Sass can load them from the filesystem.
47
+ *
48
+ * The returned object implements the modern Sass `FileImporter` interface:
49
+ * `findFileUrl` returns a `file://` URL and Sass automatically handles partial
50
+ * resolution (`_variables.scss` for `variables`), index files, and extensions.
51
+ *
52
+ * @param root - Absolute path to the Vite project root (used as the base for
53
+ * `~/path` resolution and for locating `node_modules`).
54
+ */
55
+ function createSassTildeImporter(root) {
56
+ const rootBaseUrl = pathToFileURL(root.endsWith("/") ? root : root + "/");
57
+ const nodeModulesBaseUrl = pathToFileURL(path.join(root, "node_modules") + "/");
58
+ return { findFileUrl(url) {
59
+ if (!url.startsWith("~")) return null;
60
+ const stripped = url.slice(1);
61
+ if (stripped.startsWith("/")) return new URL(stripped.slice(1), rootBaseUrl);
62
+ if (!stripped) return null;
63
+ const simpleResolved = new URL(stripped, nodeModulesBaseUrl);
64
+ const pkgName = stripped.startsWith("@") ? stripped.split("/").slice(0, 2).join("/") : stripped.split("/")[0] ?? "";
65
+ const directPkgDir = path.join(root, "node_modules", pkgName);
66
+ if (pkgName && fs.existsSync(directPkgDir)) return simpleResolved;
67
+ const req = createRequire(path.join(root, "package.json"));
68
+ try {
69
+ const pkgJsonPath = req.resolve(`${pkgName}/package.json`);
70
+ const pkgDir = path.dirname(pkgJsonPath);
71
+ const afterPkg = stripped.startsWith("@") ? stripped.split("/").slice(2).join("/") : stripped.split("/").slice(1).join("/");
72
+ return pathToFileURL(afterPkg ? path.join(pkgDir, afterPkg) : pkgDir);
73
+ } catch {
74
+ return null;
75
+ }
76
+ } };
77
+ }
2
78
  function buildSassPreprocessorOptions(sassOptions) {
3
79
  if (!sassOptions || typeof sassOptions !== "object") return void 0;
4
80
  const { prependData, additionalData, includePaths, loadPaths, ...rest } = sassOptions;
@@ -16,5 +92,177 @@ function buildSassPreprocessorOptions(sassOptions) {
16
92
  if (Object.keys(out).length === 0) return void 0;
17
93
  return out;
18
94
  }
95
+ /**
96
+ * Sort key comparator used by postcss-modules' FileSystemLoader to determine
97
+ * the order in which dependency CSS is prepended to the output.
98
+ * Mirrors the original `traceKeySorter` from postcss-modules source.
99
+ */
100
+ function traceKeySorter(a, b) {
101
+ if (a.length < b.length) return a < b.substring(0, a.length) ? -1 : 1;
102
+ if (a.length > b.length) return a.substring(0, b.length) <= b ? -1 : 1;
103
+ return a < b ? -1 : 1;
104
+ }
105
+ /**
106
+ * Mirrors Vite's internal `cssModuleRE` (`/\.module\.(css|less|sass|scss|…)/`).
107
+ *
108
+ * postcss-modules treats *every* `composes: x from './file'` dependency as a
109
+ * CSS module regardless of its filename, but Vite's pipeline only applies
110
+ * CSS-module scoping to `*.module.*` files. When a dependency is not named
111
+ * `*.module.*` (e.g. `composes: x from './plain.css'`), we hand
112
+ * `preprocessCSS` a virtual `*.module.*` filename (same directory, so Sass
113
+ * imports and relative resolution are unaffected) so the dependency's classes
114
+ * are scoped and its export tokens extracted — matching what postcss-modules'
115
+ * built-in `FileSystemLoader` did.
116
+ */
117
+ const CSS_MODULE_RE = /\.module\.\w+$/;
118
+ /**
119
+ * Sass-aware replacement for postcss-modules' `FileSystemLoader`.
120
+ *
121
+ * Implements the same constructor + `fetch` + `finalSource` interface that
122
+ * postcss-modules calls when resolving `composes: className from 'file'`
123
+ * dependencies.
124
+ *
125
+ * For every dependency file, Vite's `preprocessCSS` is used so that:
126
+ * - `.scss`/`.sass` files are compiled through Sass *before* CSS-module
127
+ * scoping runs (fixing the "Invalid empty selector" LightningCSS crash).
128
+ * - `.module.css` and `.module.scss` files have their class names scoped and
129
+ * export tokens extracted in exactly the same way as the top-level file.
130
+ *
131
+ * Failure handling: a missing Sass implementation is downgraded to a logged
132
+ * warning and an empty token map so the build continues (class composition
133
+ * will be incomplete); any other preprocessing error (e.g. a syntax error in
134
+ * the composed dependency) propagates and fails the build, matching the
135
+ * built-in `FileSystemLoader`. When no resolved config has been bound —
136
+ * only reachable if the Loader is used outside vinext's `configResolved`
137
+ * wiring — the Loader silently returns an empty token map.
138
+ *
139
+ * Recursion boundary: nested `composes` chains are handled by delegating to
140
+ * `preprocessCSS`, which re-applies postcss-modules (and therefore this
141
+ * Loader) for each dependency — every composed subtree gets its own inner
142
+ * Loader instance rather than sharing this instance's `tokensByFile`/
143
+ * `sources` state. Two intentional consequences, versus the built-in
144
+ * single-loader recursion:
145
+ * - A dependency reached from two sibling `composes` branches is inlined
146
+ * once per subtree; the duplicate identical rules are collapsed by
147
+ * LightningCSS during minification (bloat-free in practice, but the
148
+ * pre-minification CSS differs from the built-in loader's single pass).
149
+ * - Circular `composes` chains are not short-circuited across the
150
+ * `preprocessCSS` boundary (the built-in loader's shared cache caught
151
+ * them). Cycles are invalid CSS-module inputs — webpack/Next.js errors on
152
+ * them too — so no cycle bookkeeping is layered on here.
153
+ *
154
+ * Not exported directly: postcss-modules constructs the Loader itself with a
155
+ * fixed `(root, plugins, fileResolve)` signature, so the resolved Vite config
156
+ * cannot be a constructor argument. `createSassAwareFileSystemLoader` returns
157
+ * a subclass with the config bound per factory call (i.e. per vinext plugin
158
+ * instance) instead of a module-level singleton, so multiple builds in one
159
+ * process (monorepos, programmatic multi-build runners) each preprocess
160
+ * `composes` dependencies with their own root/sass options/scoped-name
161
+ * generator.
162
+ */
163
+ var SassAwareFileSystemLoader = class {
164
+ root;
165
+ fileResolve;
166
+ sources;
167
+ traces;
168
+ importNr;
169
+ tokensByFile;
170
+ constructor(root, _plugins, fileResolve) {
171
+ if (root === "/" && process.platform === "win32") {
172
+ const cwdDrive = process.cwd().slice(0, 3);
173
+ if (!/^[A-Za-z]:\\$/.test(cwdDrive)) throw new Error(`Failed to obtain root from "${process.cwd()}".`);
174
+ root = cwdDrive;
175
+ }
176
+ this.root = root;
177
+ this.fileResolve = fileResolve;
178
+ this.sources = {};
179
+ this.traces = {};
180
+ this.importNr = 0;
181
+ this.tokensByFile = {};
182
+ }
183
+ /**
184
+ * The resolved Vite config used to preprocess `composes` dependencies.
185
+ * The base implementation has no config (`fetch` silently returns empty
186
+ * tokens); `createSassAwareFileSystemLoader` overrides this with the
187
+ * config bound to that factory call.
188
+ */
189
+ getResolvedConfig() {
190
+ return null;
191
+ }
192
+ async fetch(_newPath, relativeTo, _trace) {
193
+ const newPath = _newPath.replace(/^["']|["']$/g, "");
194
+ const trace = _trace ?? String.fromCharCode(this.importNr++);
195
+ const useFileResolve = typeof this.fileResolve === "function";
196
+ const fileResolvedPath = useFileResolve ? await this.fileResolve(newPath, relativeTo) : void 0;
197
+ if (fileResolvedPath !== void 0 && !path.isAbsolute(fileResolvedPath)) throw new Error("The returned path from the \"fileResolve\" option must be absolute.");
198
+ const relativeDir = path.dirname(relativeTo);
199
+ const fileRelativePath = fileResolvedPath ?? (() => {
200
+ let resolved = path.resolve(path.resolve(this.root, relativeDir), newPath);
201
+ if (!useFileResolve && newPath[0] !== "." && !path.isAbsolute(newPath)) try {
202
+ resolved = createRequire(import.meta.url).resolve(newPath);
203
+ } catch {}
204
+ return resolved;
205
+ })();
206
+ const cached = this.tokensByFile[fileRelativePath];
207
+ if (cached) return cached;
208
+ const config = this.getResolvedConfig();
209
+ const rawSource = await fs.promises.readFile(fileRelativePath, "utf-8");
210
+ if (config) try {
211
+ const ext = path.extname(fileRelativePath);
212
+ const result = await preprocessCSS(rawSource, CSS_MODULE_RE.test(fileRelativePath) ? fileRelativePath : ext === "" ? `${fileRelativePath}.module.css` : `${fileRelativePath.slice(0, -ext.length)}.module${ext}`, config);
213
+ const exportTokens = result.modules ?? {};
214
+ this.sources[fileRelativePath] = result.code;
215
+ this.traces[trace] = fileRelativePath;
216
+ this.tokensByFile[fileRelativePath] = exportTokens;
217
+ return exportTokens;
218
+ } catch (error) {
219
+ const message = error instanceof Error ? error.message : String(error);
220
+ if (!message.includes("Preprocessor dependency")) throw error;
221
+ config.logger.warn(`[vinext] Failed to preprocess \`composes\` dependency ${fileRelativePath}: ${message}. Classes composed from this file will be missing from the build output.`);
222
+ }
223
+ this.sources[fileRelativePath] = "";
224
+ this.traces[trace] = fileRelativePath;
225
+ this.tokensByFile[fileRelativePath] = {};
226
+ return {};
227
+ }
228
+ get finalSource() {
229
+ const { traces, sources } = this;
230
+ const written = /* @__PURE__ */ new Set();
231
+ return Object.keys(traces).sort(traceKeySorter).map((key) => {
232
+ const filename = traces[key];
233
+ if (!filename || written.has(filename)) return null;
234
+ written.add(filename);
235
+ return sources[filename];
236
+ }).join("");
237
+ }
238
+ };
239
+ /**
240
+ * Create a per-build binding of {@link SassAwareFileSystemLoader}.
241
+ *
242
+ * Returns:
243
+ * - `Loader` — a class to inject as postcss-modules' `css.modules.Loader`
244
+ * option. postcss-modules instantiates it with the fixed
245
+ * `(root, plugins, fileResolve)` signature, so the resolved Vite config is
246
+ * captured in this factory's closure rather than passed to the constructor.
247
+ * - `setResolvedConfig` — called from vinext's `configResolved` hook to bind
248
+ * that build's resolved config.
249
+ *
250
+ * One binding is created per vinext plugin instance, so concurrent or
251
+ * back-to-back builds in a single process never observe another build's
252
+ * config (root, sass options, `generateScopedName`, logger, …).
253
+ */
254
+ function createSassAwareFileSystemLoader() {
255
+ let resolvedConfig = null;
256
+ return {
257
+ Loader: class extends SassAwareFileSystemLoader {
258
+ getResolvedConfig() {
259
+ return resolvedConfig;
260
+ }
261
+ },
262
+ setResolvedConfig(config) {
263
+ resolvedConfig = config;
264
+ }
265
+ };
266
+ }
19
267
  //#endregion
20
- export { buildSassPreprocessorOptions };
268
+ export { buildSassPreprocessorOptions, createSassAwareFileSystemLoader, createSassTildeImporter };
@@ -0,0 +1,14 @@
1
+ //#region src/plugins/typeof-window.d.ts
2
+ type WindowType = "object" | "undefined";
3
+ type EnvironmentLike = {
4
+ config: {
5
+ consumer: "client" | "server";
6
+ };
7
+ };
8
+ declare function getTypeofWindowReplacement(environment: EnvironmentLike): WindowType;
9
+ declare function replaceTypeofWindow(code: string, replacement: WindowType): {
10
+ code: string;
11
+ map: import("magic-string").SourceMap;
12
+ } | null;
13
+ //#endregion
14
+ export { getTypeofWindowReplacement, replaceTypeofWindow };