vinext 0.1.0 → 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/assets-ignore.d.ts +32 -0
- package/dist/build/assets-ignore.js +48 -0
- package/dist/build/client-build-config.d.ts +33 -1
- package/dist/build/client-build-config.js +66 -1
- package/dist/check.js +4 -3
- package/dist/cli.js +2 -0
- package/dist/client/navigation-runtime.d.ts +11 -2
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/client/vinext-next-data.d.ts +2 -1
- package/dist/client/window-next.d.ts +6 -4
- package/dist/config/config-matchers.d.ts +31 -5
- package/dist/config/config-matchers.js +50 -3
- package/dist/config/next-config.d.ts +29 -3
- package/dist/config/next-config.js +32 -2
- package/dist/deploy.js +47 -304
- package/dist/entries/app-rsc-entry.d.ts +8 -2
- package/dist/entries/app-rsc-entry.js +61 -5
- package/dist/entries/app-rsc-manifest.js +20 -2
- package/dist/entries/pages-client-entry.js +1 -1
- package/dist/entries/pages-server-entry.js +16 -7
- package/dist/index.d.ts +0 -2
- package/dist/index.js +233 -280
- 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/postcss.js +18 -14
- package/dist/plugins/require-context.d.ts +6 -0
- package/dist/plugins/require-context.js +184 -0
- 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 +35 -2
- package/dist/routing/app-route-graph.js +179 -8
- package/dist/routing/file-matcher.js +1 -1
- package/dist/routing/route-pattern.d.ts +2 -1
- package/dist/routing/route-pattern.js +16 -1
- package/dist/server/api-handler.js +4 -0
- package/dist/server/app-browser-entry.js +155 -215
- 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-interception-context.d.ts +2 -1
- package/dist/server/app-browser-interception-context.js +15 -2
- package/dist/server/app-browser-navigation-controller.d.ts +13 -2
- package/dist/server/app-browser-navigation-controller.js +83 -4
- package/dist/server/app-browser-popstate.d.ts +12 -3
- package/dist/server/app-browser-popstate.js +19 -4
- 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.d.ts +3 -0
- package/dist/server/app-browser-state.js +10 -10
- package/dist/server/app-browser-visible-commit.js +10 -8
- package/dist/server/app-fallback-renderer.d.ts +2 -1
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-history-state.d.ts +45 -1
- package/dist/server/app-history-state.js +109 -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 +45 -21
- package/dist/server/app-page-cache.js +9 -7
- package/dist/server/app-page-dispatch.d.ts +14 -0
- package/dist/server/app-page-dispatch.js +21 -6
- package/dist/server/app-page-element-builder.d.ts +23 -2
- package/dist/server/app-page-element-builder.js +58 -17
- 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 +7 -1
- package/dist/server/app-page-render.js +11 -16
- package/dist/server/app-page-request.d.ts +9 -6
- package/dist/server/app-page-request.js +14 -10
- package/dist/server/app-page-response.d.ts +2 -2
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +10 -8
- package/dist/server/app-page-stream.d.ts +37 -7
- package/dist/server/app-page-stream.js +36 -6
- package/dist/server/app-pages-bridge.d.ts +16 -0
- package/dist/server/app-pages-bridge.js +23 -3
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +1 -0
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +2 -0
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +1 -0
- package/dist/server/app-route-handler-response.js +11 -10
- package/dist/server/app-route-handler-runtime.d.ts +1 -0
- package/dist/server/app-route-handler-runtime.js +15 -3
- package/dist/server/app-rsc-handler.d.ts +1 -0
- package/dist/server/app-rsc-handler.js +5 -4
- package/dist/server/app-rsc-response-finalizer.js +1 -1
- package/dist/server/app-rsc-route-matching.d.ts +20 -1
- package/dist/server/app-rsc-route-matching.js +29 -4
- package/dist/server/app-server-action-execution.d.ts +22 -1
- package/dist/server/app-server-action-execution.js +73 -12
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +19 -3
- package/dist/server/app-ssr-stream.js +9 -1
- package/dist/server/dev-lockfile.js +2 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +97 -43
- 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-cache.d.ts +37 -1
- package/dist/server/isr-cache.js +85 -1
- 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 +193 -3
- package/dist/server/navigation-trace.d.ts +12 -2
- 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 +5 -11
- package/dist/server/pages-node-compat.js +175 -118
- package/dist/server/pages-page-data.d.ts +38 -7
- package/dist/server/pages-page-data.js +64 -18
- package/dist/server/pages-page-handler.d.ts +10 -2
- package/dist/server/pages-page-handler.js +49 -20
- package/dist/server/pages-page-response.d.ts +55 -2
- package/dist/server/pages-page-response.js +74 -6
- package/dist/server/pages-readiness.d.ts +36 -0
- package/dist/server/pages-readiness.js +21 -0
- package/dist/server/pages-request-pipeline.d.ts +113 -0
- package/dist/server/pages-request-pipeline.js +230 -0
- package/dist/server/pages-revalidate.d.ts +15 -0
- package/dist/server/pages-revalidate.js +19 -0
- package/dist/server/prod-server.d.ts +45 -3
- package/dist/server/prod-server.js +182 -234
- package/dist/server/socket-error-backstop.d.ts +19 -1
- package/dist/server/socket-error-backstop.js +77 -4
- package/dist/shims/app-router-scroll.js +22 -4
- package/dist/shims/cache-runtime.js +39 -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 +17 -7
- package/dist/shims/error-boundary.js +8 -1
- package/dist/shims/error.js +37 -11
- package/dist/shims/fetch-cache.d.ts +22 -1
- package/dist/shims/fetch-cache.js +28 -1
- package/dist/shims/hash-scroll.d.ts +1 -0
- package/dist/shims/hash-scroll.js +3 -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/internal/link-status-registry.d.ts +43 -0
- package/dist/shims/internal/link-status-registry.js +42 -0
- package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
- package/dist/shims/internal/route-pattern-for-warning.js +40 -0
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/link.js +20 -6
- package/dist/shims/metadata.d.ts +6 -2
- package/dist/shims/metadata.js +32 -14
- package/dist/shims/navigation.d.ts +9 -18
- package/dist/shims/navigation.js +96 -23
- package/dist/shims/router-state.d.ts +1 -0
- package/dist/shims/router-state.js +2 -0
- package/dist/shims/router.d.ts +6 -3
- package/dist/shims/router.js +156 -22
- 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.d.ts +8 -1
- package/dist/utils/client-build-manifest.js +41 -6
- package/dist/utils/client-entry-manifest.d.ts +11 -0
- package/dist/utils/client-entry-manifest.js +29 -0
- 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 +6 -2
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { forEachAstChild, hasRange, isAstRecord, nodeArray } from "./ast-utils.js";
|
|
2
|
+
import { parseAst } from "vite";
|
|
3
|
+
import MagicString from "magic-string";
|
|
4
|
+
//#region src/plugins/require-context.ts
|
|
5
|
+
const TRANSFORMABLE_EXTENSIONS = new Set([
|
|
6
|
+
".js",
|
|
7
|
+
".jsx",
|
|
8
|
+
".ts",
|
|
9
|
+
".tsx",
|
|
10
|
+
".mjs",
|
|
11
|
+
".cjs",
|
|
12
|
+
".mts",
|
|
13
|
+
".cts"
|
|
14
|
+
]);
|
|
15
|
+
function createRequireContextPlugin() {
|
|
16
|
+
return {
|
|
17
|
+
name: "vinext:require-context",
|
|
18
|
+
enforce: "pre",
|
|
19
|
+
transform(code, id) {
|
|
20
|
+
if (!mayContainRequireContext(code)) return null;
|
|
21
|
+
const lang = langForId(id);
|
|
22
|
+
if (!lang) return null;
|
|
23
|
+
let ast;
|
|
24
|
+
try {
|
|
25
|
+
ast = parseAst(code, { lang });
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const calls = collectRequireContextCalls(ast);
|
|
30
|
+
if (calls.length === 0) return null;
|
|
31
|
+
const output = new MagicString(code);
|
|
32
|
+
for (const call of calls) output.overwrite(call.range.start, call.range.end, buildReplacement(call));
|
|
33
|
+
return {
|
|
34
|
+
code: output.toString(),
|
|
35
|
+
map: output.generateMap({ hires: "boundary" })
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function mayContainRequireContext(code) {
|
|
41
|
+
return code.includes("require") && code.includes(".context");
|
|
42
|
+
}
|
|
43
|
+
function langForId(id) {
|
|
44
|
+
const clean = id.split("?", 1)[0];
|
|
45
|
+
const dot = clean.lastIndexOf(".");
|
|
46
|
+
if (dot < 0) return null;
|
|
47
|
+
const ext = clean.slice(dot).toLowerCase();
|
|
48
|
+
if (!TRANSFORMABLE_EXTENSIONS.has(ext)) return null;
|
|
49
|
+
switch (ext) {
|
|
50
|
+
case ".ts":
|
|
51
|
+
case ".cts":
|
|
52
|
+
case ".mts": return "ts";
|
|
53
|
+
case ".tsx": return "tsx";
|
|
54
|
+
case ".jsx": return "jsx";
|
|
55
|
+
default: return "jsx";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function collectRequireContextCalls(ast) {
|
|
59
|
+
const calls = [];
|
|
60
|
+
function visit(value) {
|
|
61
|
+
if (!isAstRecord(value)) return;
|
|
62
|
+
const parsed = parseRequireContextCall(value);
|
|
63
|
+
if (parsed) {
|
|
64
|
+
calls.push(parsed);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
forEachAstChild(value, visit);
|
|
68
|
+
}
|
|
69
|
+
visit(ast);
|
|
70
|
+
return calls;
|
|
71
|
+
}
|
|
72
|
+
function parseRequireContextCall(node) {
|
|
73
|
+
if (node.type !== "CallExpression" || !hasRange(node)) return null;
|
|
74
|
+
const callee = node.callee;
|
|
75
|
+
if (!isAstRecord(callee) || callee.type !== "MemberExpression" || callee.computed === true || callee.optional === true) return null;
|
|
76
|
+
if (!isPropertyNamed(callee.property, "context")) return null;
|
|
77
|
+
if (!isRequireExpression(callee.object)) return null;
|
|
78
|
+
const args = nodeArray(node.arguments);
|
|
79
|
+
const dir = stringLiteralValue(args[0]);
|
|
80
|
+
if (dir == null || !(dir.startsWith("./") || dir.startsWith("../"))) return null;
|
|
81
|
+
let recursive = true;
|
|
82
|
+
if (args.length >= 2) {
|
|
83
|
+
const value = booleanLiteralValue(args[1]);
|
|
84
|
+
if (value == null) return null;
|
|
85
|
+
recursive = value;
|
|
86
|
+
}
|
|
87
|
+
let pattern = "";
|
|
88
|
+
let flags = "";
|
|
89
|
+
if (args.length >= 3) {
|
|
90
|
+
const regex = regexLiteralValue(args[2]);
|
|
91
|
+
if (regex == null) return null;
|
|
92
|
+
pattern = regex.pattern;
|
|
93
|
+
flags = regex.flags;
|
|
94
|
+
} else if (args.length > 3) return null;
|
|
95
|
+
return {
|
|
96
|
+
range: node,
|
|
97
|
+
dir,
|
|
98
|
+
recursive,
|
|
99
|
+
pattern,
|
|
100
|
+
flags
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function isRequireExpression(value) {
|
|
104
|
+
let node = value;
|
|
105
|
+
while (isAstRecord(node)) {
|
|
106
|
+
if (node.type === "Identifier") return node.name === "require";
|
|
107
|
+
if (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") {
|
|
108
|
+
node = node.expression;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (node.type === "TSNonNullExpression") {
|
|
112
|
+
node = node.expression;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (node.type === "ParenthesizedExpression") {
|
|
116
|
+
node = node.expression;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
function isPropertyNamed(value, name) {
|
|
124
|
+
return isAstRecord(value) && value.type === "Identifier" && value.name === name;
|
|
125
|
+
}
|
|
126
|
+
function stringLiteralValue(value) {
|
|
127
|
+
if (isAstRecord(value) && value.type === "Literal" && typeof value.value === "string") return value.value;
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
function booleanLiteralValue(value) {
|
|
131
|
+
if (isAstRecord(value) && value.type === "Literal" && typeof value.value === "boolean") return value.value;
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
function regexLiteralValue(value) {
|
|
135
|
+
if (!isAstRecord(value) || value.type !== "Literal") return null;
|
|
136
|
+
const regex = value.regex;
|
|
137
|
+
if (typeof regex === "object" && regex !== null && typeof regex.pattern === "string" && typeof regex.flags === "string") return {
|
|
138
|
+
pattern: regex.pattern,
|
|
139
|
+
flags: regex.flags
|
|
140
|
+
};
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
function buildReplacement(call) {
|
|
144
|
+
const globPattern = globPatternFor(call.dir, call.recursive);
|
|
145
|
+
const glob = `import.meta.glob(${JSON.stringify(globPattern)}, { eager: true })`;
|
|
146
|
+
const base = JSON.stringify(stripTrailingSlash(call.dir));
|
|
147
|
+
const filterFlags = call.flags.replace(/[gy]/g, "");
|
|
148
|
+
const regexArgs = `${JSON.stringify(call.pattern)}, ${JSON.stringify(filterFlags)}`;
|
|
149
|
+
return [
|
|
150
|
+
"(() => {",
|
|
151
|
+
` const __modules = ${glob};`,
|
|
152
|
+
` const __base = ${base};`,
|
|
153
|
+
` const __re = ${call.pattern ? `new RegExp(${regexArgs})` : "null"};`,
|
|
154
|
+
" const __prefix = __base.endsWith('/') ? __base : __base + '/';",
|
|
155
|
+
" const __map = Object.create(null);",
|
|
156
|
+
" for (const __abs in __modules) {",
|
|
157
|
+
" if (!__abs.startsWith(__prefix)) continue;",
|
|
158
|
+
" const __key = './' + __abs.slice(__prefix.length);",
|
|
159
|
+
" if (__re && !__re.test(__key)) continue;",
|
|
160
|
+
" __map[__key] = __modules[__abs];",
|
|
161
|
+
" }",
|
|
162
|
+
" const __keys = Object.keys(__map).sort();",
|
|
163
|
+
" const __ctx = (__key) => {",
|
|
164
|
+
" if (__key in __map) return __map[__key];",
|
|
165
|
+
" const __err = new Error('Cannot find module \\'' + __key + '\\'');",
|
|
166
|
+
" __err.code = 'MODULE_NOT_FOUND';",
|
|
167
|
+
" throw __err;",
|
|
168
|
+
" };",
|
|
169
|
+
" __ctx.keys = () => __keys.slice();",
|
|
170
|
+
" __ctx.resolve = (__key) => __key;",
|
|
171
|
+
` __ctx.id = __base;`,
|
|
172
|
+
" return __ctx;",
|
|
173
|
+
"})()"
|
|
174
|
+
].join("\n");
|
|
175
|
+
}
|
|
176
|
+
function globPatternFor(dir, recursive) {
|
|
177
|
+
const base = stripTrailingSlash(dir);
|
|
178
|
+
return recursive ? `${base}/**/*` : `${base}/*`;
|
|
179
|
+
}
|
|
180
|
+
function stripTrailingSlash(value) {
|
|
181
|
+
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
export { createRequireContextPlugin };
|
package/dist/plugins/sass.d.ts
CHANGED
|
@@ -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 };
|
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 };
|
|
@@ -24,6 +24,11 @@ type InterceptingRoute = {
|
|
|
24
24
|
pagePath: string; /** Absolute layout paths inside the intercepting route tree, outermost to innermost */
|
|
25
25
|
layoutPaths: string[]; /** Parameter names for dynamic segments */
|
|
26
26
|
params: string[];
|
|
27
|
+
/**
|
|
28
|
+
* Synthetic page-carrier slot id for sibling (slot-less) interception.
|
|
29
|
+
* Set only when the marker has no `@slot` wrapper; undefined for slot intercepts.
|
|
30
|
+
*/
|
|
31
|
+
slotId?: string;
|
|
27
32
|
};
|
|
28
33
|
type ParallelSlot = {
|
|
29
34
|
/** Graph-owned semantic slot identity. Required on AppRouteGraphParallelSlot. */id?: string; /** Stable slot identity (name + owning directory), used for route serialization keys. */
|
|
@@ -73,7 +78,13 @@ type AppRoute = {
|
|
|
73
78
|
routePath: string | null; /** Ordered list of layout files from root to leaf */
|
|
74
79
|
layouts: string[]; /** Ordered list of all discovered template files from root to leaf (not necessarily aligned 1:1 with layouts) */
|
|
75
80
|
templates: string[]; /** Parallel route slots (from @slot directories at the route's directory level) */
|
|
76
|
-
parallelSlots: ParallelSlot[];
|
|
81
|
+
parallelSlots: ParallelSlot[];
|
|
82
|
+
/**
|
|
83
|
+
* Interception markers not wrapped in an `@slot` directory.
|
|
84
|
+
* On soft-nav, the intercepting page replaces the entire page response.
|
|
85
|
+
* Empty array when there are no sibling-style interception markers.
|
|
86
|
+
*/
|
|
87
|
+
siblingIntercepts: InterceptingRoute[]; /** Loading component path */
|
|
77
88
|
loadingPath: string | null; /** Error component path (leaf directory only) */
|
|
78
89
|
errorPath: string | null;
|
|
79
90
|
/**
|
|
@@ -265,6 +276,28 @@ declare function buildAppRouteGraph(appDir: string, matcher: ValidFileMatcher):
|
|
|
265
276
|
routeManifest: RouteManifest;
|
|
266
277
|
}>;
|
|
267
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;
|
|
268
301
|
/**
|
|
269
302
|
* Convert filesystem path segments to URL route parts, skipping invisible segments
|
|
270
303
|
* (route groups, @slots, ".") and converting dynamic segment syntax to Express-style
|
|
@@ -299,4 +332,4 @@ declare function computeAppRouteStaticSiblings(allRoutes: readonly {
|
|
|
299
332
|
patternParts?: readonly string[] | null;
|
|
300
333
|
}): string[];
|
|
301
334
|
//#endregion
|
|
302
|
-
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 };
|