vinext 0.1.1 → 0.1.2
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/README.md +2 -5
- package/dist/build/client-build-config.d.ts +7 -1
- package/dist/build/client-build-config.js +9 -1
- package/dist/check.js +4 -3
- package/dist/client/navigation-runtime.d.ts +3 -2
- package/dist/client/window-next.d.ts +6 -4
- package/dist/config/config-matchers.d.ts +11 -4
- package/dist/config/config-matchers.js +15 -2
- package/dist/config/next-config.d.ts +13 -0
- package/dist/config/next-config.js +2 -0
- package/dist/deploy.js +9 -2
- package/dist/entries/app-rsc-entry.js +7 -1
- package/dist/entries/pages-client-entry.js +1 -1
- package/dist/entries/pages-server-entry.js +7 -6
- package/dist/index.d.ts +0 -2
- package/dist/index.js +86 -78
- package/dist/plugins/dynamic-preload-metadata.d.ts +13 -0
- package/dist/plugins/dynamic-preload-metadata.js +415 -0
- package/dist/plugins/og-assets.js +2 -2
- package/dist/plugins/optimize-imports.d.ts +8 -4
- package/dist/plugins/optimize-imports.js +16 -12
- package/dist/plugins/sass.d.ts +53 -24
- package/dist/plugins/sass.js +249 -1
- package/dist/plugins/wasm-module-import.d.ts +15 -0
- package/dist/plugins/wasm-module-import.js +50 -0
- package/dist/routing/app-route-graph.d.ts +23 -1
- package/dist/routing/app-route-graph.js +47 -8
- package/dist/routing/file-matcher.js +1 -1
- package/dist/server/app-browser-entry.js +108 -213
- package/dist/server/app-browser-error.d.ts +4 -1
- package/dist/server/app-browser-error.js +7 -1
- package/dist/server/app-browser-history-controller.d.ts +104 -0
- package/dist/server/app-browser-history-controller.js +210 -0
- package/dist/server/app-browser-navigation-controller.d.ts +3 -2
- package/dist/server/app-browser-navigation-controller.js +10 -7
- package/dist/server/app-browser-rsc-redirect.d.ts +11 -2
- package/dist/server/app-browser-rsc-redirect.js +30 -8
- package/dist/server/app-browser-state.js +4 -7
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-middleware.js +1 -0
- package/dist/server/app-optimistic-routing.js +22 -1
- package/dist/server/app-page-boundary-render.d.ts +2 -1
- package/dist/server/app-page-boundary-render.js +4 -2
- package/dist/server/app-page-cache.js +9 -7
- package/dist/server/app-page-dispatch.d.ts +8 -0
- package/dist/server/app-page-dispatch.js +18 -5
- package/dist/server/app-page-element-builder.d.ts +22 -2
- package/dist/server/app-page-element-builder.js +37 -8
- package/dist/server/app-page-execution.d.ts +1 -1
- package/dist/server/app-page-execution.js +32 -17
- package/dist/server/app-page-render.d.ts +1 -1
- package/dist/server/app-page-render.js +7 -14
- package/dist/server/app-page-request.d.ts +1 -0
- package/dist/server/app-page-request.js +3 -2
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +8 -7
- package/dist/server/app-page-stream.d.ts +1 -6
- package/dist/server/app-page-stream.js +1 -4
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.js +12 -1
- package/dist/server/app-rsc-handler.js +1 -1
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-server-action-execution.d.ts +11 -0
- package/dist/server/app-server-action-execution.js +5 -2
- package/dist/server/app-ssr-entry.js +2 -2
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.js +43 -12
- package/dist/server/headers.d.ts +8 -1
- package/dist/server/headers.js +8 -1
- package/dist/server/instrumentation-runtime.d.ts +6 -0
- package/dist/server/instrumentation-runtime.js +8 -0
- package/dist/server/isr-decision.d.ts +79 -0
- package/dist/server/isr-decision.js +70 -0
- package/dist/server/metadata-route-response.js +5 -3
- package/dist/server/middleware-runtime.d.ts +13 -0
- package/dist/server/middleware-runtime.js +11 -7
- package/dist/server/middleware.js +1 -0
- package/dist/server/navigation-planner.d.ts +62 -1
- package/dist/server/navigation-planner.js +188 -0
- package/dist/server/navigation-trace.d.ts +11 -1
- package/dist/server/navigation-trace.js +11 -1
- package/dist/server/normalize-path.d.ts +0 -8
- package/dist/server/normalize-path.js +3 -1
- package/dist/server/otel-tracer-extension.d.ts +45 -0
- package/dist/server/otel-tracer-extension.js +89 -0
- package/dist/server/pages-api-route.d.ts +14 -3
- package/dist/server/pages-api-route.js +6 -1
- package/dist/server/pages-asset-tags.d.ts +15 -4
- package/dist/server/pages-asset-tags.js +18 -12
- package/dist/server/pages-data-route.js +5 -1
- package/dist/server/pages-node-compat.d.ts +3 -11
- package/dist/server/pages-node-compat.js +174 -121
- package/dist/server/pages-page-data.d.ts +28 -0
- package/dist/server/pages-page-data.js +61 -17
- package/dist/server/pages-page-handler.d.ts +1 -0
- package/dist/server/pages-page-handler.js +22 -6
- package/dist/server/pages-page-response.d.ts +45 -1
- package/dist/server/pages-page-response.js +66 -5
- package/dist/server/pages-readiness.d.ts +1 -1
- package/dist/server/pages-request-pipeline.d.ts +15 -1
- package/dist/server/pages-request-pipeline.js +23 -2
- package/dist/server/prod-server.d.ts +39 -1
- package/dist/server/prod-server.js +98 -34
- package/dist/shims/cache-runtime.js +9 -2
- package/dist/shims/dynamic-preload-chunks.d.ts +8 -0
- package/dist/shims/dynamic-preload-chunks.js +77 -0
- package/dist/shims/dynamic.d.ts +4 -0
- package/dist/shims/dynamic.js +4 -2
- package/dist/shims/error-boundary.d.ts +4 -4
- package/dist/shims/error.js +37 -11
- package/dist/shims/fetch-cache.d.ts +9 -1
- package/dist/shims/fetch-cache.js +11 -1
- package/dist/shims/head.js +6 -1
- package/dist/shims/headers.d.ts +16 -2
- package/dist/shims/headers.js +37 -1
- package/dist/shims/image-config.js +7 -1
- package/dist/shims/internal/app-route-detection.d.ts +6 -3
- package/dist/shims/internal/app-route-detection.js +10 -6
- package/dist/shims/internal/app-router-context.d.ts +5 -0
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +7 -16
- package/dist/shims/navigation.js +33 -16
- package/dist/shims/router.js +28 -1
- package/dist/shims/script-nonce-context.d.ts +1 -1
- package/dist/shims/script-nonce-context.js +11 -3
- package/dist/shims/server.d.ts +17 -1
- package/dist/shims/server.js +31 -6
- package/dist/shims/slot.js +1 -1
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -0
- package/dist/utils/client-build-manifest.js +15 -5
- package/dist/utils/client-runtime-metadata.d.ts +45 -0
- package/dist/utils/client-runtime-metadata.js +63 -0
- package/dist/utils/hash.d.ts +17 -1
- package/dist/utils/hash.js +36 -1
- package/dist/utils/lazy-chunks.d.ts +27 -1
- package/dist/utils/lazy-chunks.js +65 -1
- package/dist/utils/manifest-paths.d.ts +20 -2
- package/dist/utils/manifest-paths.js +38 -3
- package/dist/utils/path.d.ts +2 -1
- package/dist/utils/path.js +5 -1
- package/package.json +2 -2
package/dist/plugins/sass.js
CHANGED
|
@@ -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,15 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/wasm-module-import.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* vinext:wasm-module-import — handle `import x from '*.wasm?module'`.
|
|
6
|
+
*
|
|
7
|
+
* Resolutions marked external by Vite or a target adapter are preserved. For
|
|
8
|
+
* non-external resolutions, this plugin reads the WASM file, inlines it as
|
|
9
|
+
* base64, and exports a compiled WebAssembly.Module.
|
|
10
|
+
*
|
|
11
|
+
* Fixes #1351.
|
|
12
|
+
*/
|
|
13
|
+
declare function createWasmModuleImportPlugin(): Plugin;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { createWasmModuleImportPlugin };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { stripViteModuleQuery } from "../utils/path.js";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
//#region src/plugins/wasm-module-import.ts
|
|
4
|
+
/**
|
|
5
|
+
* vinext:wasm-module-import — handle `import x from '*.wasm?module'`.
|
|
6
|
+
*
|
|
7
|
+
* Resolutions marked external by Vite or a target adapter are preserved. For
|
|
8
|
+
* non-external resolutions, this plugin reads the WASM file, inlines it as
|
|
9
|
+
* base64, and exports a compiled WebAssembly.Module.
|
|
10
|
+
*
|
|
11
|
+
* Fixes #1351.
|
|
12
|
+
*/
|
|
13
|
+
function createWasmModuleImportPlugin() {
|
|
14
|
+
return {
|
|
15
|
+
name: "vinext:wasm-module-import",
|
|
16
|
+
enforce: "pre",
|
|
17
|
+
resolveId: {
|
|
18
|
+
filter: { id: /\.wasm\?module$/ },
|
|
19
|
+
async handler(source, importer) {
|
|
20
|
+
if (this.environment?.name === "client") return null;
|
|
21
|
+
if ((importer ? (importer.startsWith("\0") ? importer.slice(1) : importer).split("?")[0] : "").includes("@vercel/og")) return null;
|
|
22
|
+
const resolved = await this.resolve(source, importer, { skipSelf: true });
|
|
23
|
+
if (!resolved) return null;
|
|
24
|
+
if (resolved.external) return resolved;
|
|
25
|
+
return `\0vinext-wasm-module:${stripViteModuleQuery(resolved.id)}`;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
load: {
|
|
29
|
+
filter: { id: /^\u0000vinext-wasm-module:/ },
|
|
30
|
+
handler(id) {
|
|
31
|
+
const filePath = id.replace(/^\u0000vinext-wasm-module:/, "");
|
|
32
|
+
this.addWatchFile(filePath);
|
|
33
|
+
let bytes;
|
|
34
|
+
try {
|
|
35
|
+
bytes = fs.readFileSync(filePath);
|
|
36
|
+
} catch {
|
|
37
|
+
return this.error(`[vinext] Could not read WASM file: ${filePath}`);
|
|
38
|
+
}
|
|
39
|
+
const base64 = bytes.toString("base64");
|
|
40
|
+
return [
|
|
41
|
+
`const _b64 = ${JSON.stringify(base64)};`,
|
|
42
|
+
`const _buf = Uint8Array.from(atob(_b64), c => c.charCodeAt(0));`,
|
|
43
|
+
`export default await WebAssembly.compile(_buf.buffer);`
|
|
44
|
+
].join("\n");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { createWasmModuleImportPlugin };
|
|
@@ -276,6 +276,28 @@ declare function buildAppRouteGraph(appDir: string, matcher: ValidFileMatcher):
|
|
|
276
276
|
routeManifest: RouteManifest;
|
|
277
277
|
}>;
|
|
278
278
|
declare function computeRootParamNames(routeSegments: readonly string[], layoutTreePositions: readonly number[]): string[];
|
|
279
|
+
/**
|
|
280
|
+
* Find the best route to attach a sibling intercept to, given the directory
|
|
281
|
+
* that contains the interception marker.
|
|
282
|
+
*
|
|
283
|
+
* 1. Exact hit: a route whose page/handler lives directly in `dir`.
|
|
284
|
+
* 2. Subtree hit: shallowest route whose page lives anywhere under `dir`
|
|
285
|
+
* (handles catch-all routes like `/templates/:catchAll+`).
|
|
286
|
+
* 3. Ancestor walk: walk up the directory tree toward `appDir` looking for
|
|
287
|
+
* any of the above. This handles the case where the marker directory has
|
|
288
|
+
* no sibling pages at all (e.g. `deep/path/(...)target` with no
|
|
289
|
+
* `deep/path/page.tsx`).
|
|
290
|
+
*
|
|
291
|
+
* All comparisons happen in forward-slash space: `appDir` is forward-slash
|
|
292
|
+
* (normalized once in the config hook), but `dir` and route file paths
|
|
293
|
+
* descend through native `path.join`/`path.dirname`, which reintroduce
|
|
294
|
+
* backslashes on Windows. Without normalizing, the `current === appDir`
|
|
295
|
+
* termination never fires there and the walk overshoots the app root.
|
|
296
|
+
* `routesByDir` keys must be forward-slash dirnames of the route file paths.
|
|
297
|
+
*
|
|
298
|
+
* Exported for tests.
|
|
299
|
+
*/
|
|
300
|
+
declare function findOwnerRouteForDir(dir: string, appDir: string, routes: readonly AppRouteGraphRoute[], routesByDir: Map<string, AppRouteGraphRoute>): AppRouteGraphRoute | null;
|
|
279
301
|
/**
|
|
280
302
|
* Convert filesystem path segments to URL route parts, skipping invisible segments
|
|
281
303
|
* (route groups, @slots, ".") and converting dynamic segment syntax to Express-style
|
|
@@ -310,4 +332,4 @@ declare function computeAppRouteStaticSiblings(allRoutes: readonly {
|
|
|
310
332
|
patternParts?: readonly string[] | null;
|
|
311
333
|
}): string[];
|
|
312
334
|
//#endregion
|
|
313
|
-
export { AppRoute, AppRouteGraphRoute, AppRouteSemanticIds, GraphVersion, RootBoundaryId, RouteManifest, RouteManifestInterception, RouteManifestRootBoundary, RouteManifestRoute, RouteManifestSlotBinding, StaticSegmentGraph, buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, isInvisibleSegment };
|
|
335
|
+
export { AppRoute, AppRouteGraphRoute, AppRouteSemanticIds, GraphVersion, RootBoundaryId, RouteManifest, RouteManifestInterception, RouteManifestRootBoundary, RouteManifestRoute, RouteManifestSlotBinding, StaticSegmentGraph, buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, findOwnerRouteForDir, isInvisibleSegment };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizePathSeparators } from "../utils/path.js";
|
|
1
2
|
import { compareRoutes, decodeRouteSegment, isInvisibleSegment } from "./utils.js";
|
|
2
3
|
import { findFileWithExts, scanWithExtensions } from "./file-matcher.js";
|
|
3
4
|
import { validateRoutePatterns } from "./route-validation.js";
|
|
@@ -485,7 +486,7 @@ function discoverSlotSubRoutes(routes, matcher, ghostParents = []) {
|
|
|
485
486
|
const existingRoute = routesByPattern.get(pattern);
|
|
486
487
|
if (existingRoute) {
|
|
487
488
|
if (existingRoute.routePath && !existingRoute.pagePath) throw new Error(`You cannot have two routes that resolve to the same path ("${pattern}").`);
|
|
488
|
-
applySlotSubPages(existingRoute, slotPages, rawSegments);
|
|
489
|
+
if (urlParts.length > 0) applySlotSubPages(existingRoute, slotPages, rawSegments);
|
|
489
490
|
continue;
|
|
490
491
|
}
|
|
491
492
|
const syntheticParts = [...parentRoute.patternParts, ...urlParts];
|
|
@@ -1026,6 +1027,34 @@ function patternsStructurallyEquivalent(a, b) {
|
|
|
1026
1027
|
return true;
|
|
1027
1028
|
}
|
|
1028
1029
|
/**
|
|
1030
|
+
* Find a page file at the root URL level of a parallel slot directory, including
|
|
1031
|
+
* through transparent route-group subdirectories (e.g. `@slot/(group)/page.tsx`
|
|
1032
|
+
* is equivalent to `@slot/page.tsx` since `(group)` is invisible in the URL).
|
|
1033
|
+
*
|
|
1034
|
+
* Returns the absolute page path, or null if no root-level page is found.
|
|
1035
|
+
*
|
|
1036
|
+
* Only descends into route-group directories (those whose name starts with `(`
|
|
1037
|
+
* and ends with `)`). Dynamic segments, regular named dirs, and `@slot` dirs
|
|
1038
|
+
* are not transparent and are therefore not searched.
|
|
1039
|
+
*/
|
|
1040
|
+
function findSlotRootPage(slotDir, matcher) {
|
|
1041
|
+
const directPage = findFile(slotDir, "page", matcher);
|
|
1042
|
+
if (directPage) return directPage;
|
|
1043
|
+
let entries;
|
|
1044
|
+
try {
|
|
1045
|
+
entries = fs.readdirSync(slotDir, { withFileTypes: true });
|
|
1046
|
+
} catch {
|
|
1047
|
+
return null;
|
|
1048
|
+
}
|
|
1049
|
+
for (const entry of entries) {
|
|
1050
|
+
if (!entry.isDirectory()) continue;
|
|
1051
|
+
if (!entry.name.startsWith("(") || !entry.name.endsWith(")")) continue;
|
|
1052
|
+
const found = findSlotRootPage(path.join(slotDir, entry.name), matcher);
|
|
1053
|
+
if (found) return found;
|
|
1054
|
+
}
|
|
1055
|
+
return null;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1029
1058
|
* Discover parallel route slots (@team, @analytics, etc.) in a directory.
|
|
1030
1059
|
* Returns a ParallelSlot for each @-prefixed subdirectory that has a page or default component.
|
|
1031
1060
|
*/
|
|
@@ -1038,7 +1067,7 @@ function discoverParallelSlots(dir, appDir, matcher) {
|
|
|
1038
1067
|
if (entry.name === "@children") continue;
|
|
1039
1068
|
const slotName = entry.name.slice(1);
|
|
1040
1069
|
const slotDir = path.join(dir, entry.name);
|
|
1041
|
-
const pagePath =
|
|
1070
|
+
const pagePath = findSlotRootPage(slotDir, matcher);
|
|
1042
1071
|
const defaultPath = findFile(slotDir, "default", matcher);
|
|
1043
1072
|
const interceptingRoutes = discoverInterceptingRoutes(slotDir, dir, appDir, matcher);
|
|
1044
1073
|
if (!pagePath && !defaultPath && interceptingRoutes.length === 0) continue;
|
|
@@ -1127,7 +1156,7 @@ function discoverSiblingInterceptingRoutes(routes, appDir, matcher) {
|
|
|
1127
1156
|
for (const route of routes) {
|
|
1128
1157
|
const filePath = route.pagePath ?? route.routePath;
|
|
1129
1158
|
if (!filePath) continue;
|
|
1130
|
-
const routeDir = path.dirname(filePath);
|
|
1159
|
+
const routeDir = normalizePathSeparators(path.dirname(filePath));
|
|
1131
1160
|
if (!routesByDir.has(routeDir)) routesByDir.set(routeDir, route);
|
|
1132
1161
|
}
|
|
1133
1162
|
function walk(dir) {
|
|
@@ -1171,22 +1200,32 @@ function discoverSiblingInterceptingRoutes(routes, appDir, matcher) {
|
|
|
1171
1200
|
* any of the above. This handles the case where the marker directory has
|
|
1172
1201
|
* no sibling pages at all (e.g. `deep/path/(...)target` with no
|
|
1173
1202
|
* `deep/path/page.tsx`).
|
|
1203
|
+
*
|
|
1204
|
+
* All comparisons happen in forward-slash space: `appDir` is forward-slash
|
|
1205
|
+
* (normalized once in the config hook), but `dir` and route file paths
|
|
1206
|
+
* descend through native `path.join`/`path.dirname`, which reintroduce
|
|
1207
|
+
* backslashes on Windows. Without normalizing, the `current === appDir`
|
|
1208
|
+
* termination never fires there and the walk overshoots the app root.
|
|
1209
|
+
* `routesByDir` keys must be forward-slash dirnames of the route file paths.
|
|
1210
|
+
*
|
|
1211
|
+
* Exported for tests.
|
|
1174
1212
|
*/
|
|
1175
1213
|
function findOwnerRouteForDir(dir, appDir, routes, routesByDir) {
|
|
1176
|
-
|
|
1214
|
+
const appRoot = normalizePathSeparators(appDir);
|
|
1215
|
+
let current = normalizePathSeparators(dir);
|
|
1177
1216
|
while (true) {
|
|
1178
1217
|
const exact = routesByDir.get(current);
|
|
1179
1218
|
if (exact) return exact;
|
|
1180
|
-
const currentWithSep = current +
|
|
1219
|
+
const currentWithSep = current + "/";
|
|
1181
1220
|
let best = null;
|
|
1182
1221
|
for (const route of routes) {
|
|
1183
1222
|
const filePath = route.pagePath ?? route.routePath;
|
|
1184
1223
|
if (!filePath) continue;
|
|
1185
|
-
if (!filePath.startsWith(currentWithSep)) continue;
|
|
1224
|
+
if (!normalizePathSeparators(filePath).startsWith(currentWithSep)) continue;
|
|
1186
1225
|
if (!best || route.patternParts.length < best.patternParts.length) best = route;
|
|
1187
1226
|
}
|
|
1188
1227
|
if (best) return best;
|
|
1189
|
-
if (current ===
|
|
1228
|
+
if (current === appRoot) break;
|
|
1190
1229
|
const parent = path.dirname(current);
|
|
1191
1230
|
if (parent === current) break;
|
|
1192
1231
|
current = parent;
|
|
@@ -1446,4 +1485,4 @@ function computeAppRouteStaticSiblings(allRoutes, matchedRoute) {
|
|
|
1446
1485
|
return Array.from(siblings);
|
|
1447
1486
|
}
|
|
1448
1487
|
//#endregion
|
|
1449
|
-
export { buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, isInvisibleSegment };
|
|
1488
|
+
export { buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, findOwnerRouteForDir, isInvisibleSegment };
|
|
@@ -69,7 +69,7 @@ function findFileWithExtensions(basePath, matcher) {
|
|
|
69
69
|
*/
|
|
70
70
|
function findFileWithExts(dir, name, matcher) {
|
|
71
71
|
for (const ext of matcher.dottedExtensions) {
|
|
72
|
-
const filePath = path.join(dir, name + ext);
|
|
72
|
+
const filePath = path.posix.join(dir, name + ext);
|
|
73
73
|
if (existsSync(filePath)) return filePath;
|
|
74
74
|
}
|
|
75
75
|
return null;
|