vinext 1.0.0-beta.11 → 1.0.0-beta.13
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 +39 -12
- package/dist/build/action-owner-manifest.js +23 -5
- package/dist/build/lifecycle.d.ts +42 -0
- package/dist/build/lifecycle.js +246 -0
- package/dist/build/nitro-route-rules.js +1 -1
- package/dist/build/pages-client-assets-module.d.ts +0 -3
- package/dist/build/pages-client-assets-module.js +1 -13
- package/dist/build/precompress.js +1 -1
- package/dist/build/prerender-paths.d.ts +1 -1
- package/dist/build/prerender-paths.js +6 -6
- package/dist/build/prerender-server-pool.js +1 -1
- package/dist/build/prerender.d.ts +1 -1
- package/dist/build/prerender.js +5 -5
- package/dist/build/preview-credentials.d.ts +1 -1
- package/dist/build/preview-credentials.js +2 -2
- package/dist/build/report.js +1 -1
- package/dist/build/run-prerender.d.ts +2 -2
- package/dist/build/run-prerender.js +5 -5
- package/dist/build/standalone.js +2 -2
- package/dist/cli-args.d.ts +5 -13
- package/dist/cli-args.js +2 -45
- package/dist/cli-dev-config.d.ts +6 -2
- package/dist/cli-dev-config.js +160 -3
- package/dist/cli.js +104 -439
- package/dist/config/config-matchers.js +1 -1
- package/dist/config/next-config.d.ts +2 -2
- package/dist/config/next-config.js +5 -5
- package/dist/config/prerender.d.ts +3 -0
- package/dist/config/prerender.js +8 -2
- package/dist/entries/app-browser-entry.js +1 -1
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +25 -5
- package/dist/entries/pages-client-entry.d.ts +1 -0
- package/dist/entries/pages-client-entry.js +17 -2
- package/dist/index.d.ts +6 -8
- package/dist/index.js +282 -105
- package/dist/init-cloudflare.d.ts +3 -2
- package/dist/init-cloudflare.js +117 -5
- package/dist/init-platform.d.ts +2 -0
- package/dist/init-platform.js +9 -3
- package/dist/init.d.ts +7 -5
- package/dist/init.js +41 -22
- package/dist/plugins/dynamic-preload-metadata.js +1 -1
- package/dist/plugins/extensionless-dynamic-import.js +2 -2
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +1 -1
- package/dist/plugins/import-meta-url.js +1 -1
- package/dist/plugins/instrumentation-client.js +1 -1
- package/dist/plugins/og-assets.js +32 -13
- package/dist/plugins/og-harfbuzz.d.ts +24 -0
- package/dist/plugins/og-harfbuzz.js +260 -0
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/require-condition-resolution.js +2 -2
- package/dist/plugins/require-context.js +2 -2
- package/dist/plugins/typeof-window.js +1 -1
- package/dist/plugins/use-cache-callable.d.ts +0 -2
- package/dist/plugins/use-cache-callable.js +40 -22
- package/dist/plugins/worker-image-imports.js +1 -1
- package/dist/routing/app-route-graph.js +1 -1
- package/dist/routing/app-router.js +1 -1
- package/dist/routing/pages-router.js +1 -1
- package/dist/server/app-action-forwarding.js +1 -1
- package/dist/server/app-browser-entry.js +1 -0
- package/dist/server/app-browser-error.js +1 -1
- package/dist/server/app-elements-wire.js +2 -2
- package/dist/server/app-middleware.js +1 -1
- package/dist/server/app-optimistic-routing.js +1 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +14 -2
- package/dist/server/app-page-dispatch.js +1 -1
- package/dist/server/app-page-element-builder.js +3 -2
- package/dist/server/app-page-probe.js +3 -3
- package/dist/server/app-page-render.js +1 -0
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +16 -12
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +2 -2
- package/dist/server/app-route-handler-dispatch.d.ts +1 -0
- package/dist/server/app-route-handler-dispatch.js +3 -2
- package/dist/server/app-route-handler-execution.d.ts +1 -0
- package/dist/server/app-route-handler-execution.js +2 -2
- package/dist/server/app-route-handler-runtime.js +1 -1
- package/dist/server/app-router-entry.js +2 -2
- package/dist/server/app-rsc-handler.d.ts +9 -2
- package/dist/server/app-rsc-handler.js +30 -10
- package/dist/server/app-rsc-response-stage.js +6 -3
- package/dist/server/app-rsc-route-matching.js +1 -1
- package/dist/server/app-server-action-execution.js +35 -6
- package/dist/server/app-ssr-entry.js +7 -2
- package/dist/server/app-ssr-stream.js +25 -6
- package/dist/server/app-worker-stages.d.ts +4 -1
- package/dist/server/app-worker-stages.js +4 -4
- package/dist/server/artifact-compatibility.js +1 -1
- package/dist/server/client-reuse-manifest.js +1 -1
- package/dist/server/dev-lockfile.d.ts +1 -1
- package/dist/server/dev-lockfile.js +4 -1
- package/dist/server/dev-server.d.ts +1 -1
- package/dist/server/dev-server.js +28 -6
- package/dist/server/dev-stack-sourcemap.js +1 -1
- package/dist/server/html.d.ts +0 -20
- package/dist/server/html.js +16 -1
- package/dist/server/instrumentation.d.ts +4 -9
- package/dist/server/instrumentation.js +10 -15
- package/dist/server/isr-cache.js +3 -3
- package/dist/server/metadata-route-response.d.ts +1 -0
- package/dist/server/metadata-route-response.js +65 -0
- package/dist/server/middleware-runtime.js +3 -3
- package/dist/server/pages-asset-tags.d.ts +1 -0
- package/dist/server/pages-asset-tags.js +37 -2
- package/dist/server/pages-client-assets.d.ts +7 -0
- package/dist/server/pages-data-route.js +1 -1
- package/dist/server/pages-dev-hydration.d.ts +6 -0
- package/dist/server/pages-dev-hydration.js +19 -7
- package/dist/server/pages-document-initial-props.d.ts +1 -0
- package/dist/server/pages-document-initial-props.js +1 -1
- package/dist/server/pages-page-data.js +2 -2
- package/dist/server/pages-page-handler.js +5 -2
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +3 -2
- package/dist/server/pages-request-pipeline.js +3 -3
- package/dist/server/pages-request-stage-entry.js +3 -3
- package/dist/server/pages-revalidate.js +1 -1
- package/dist/server/prerender-route-params.js +1 -1
- package/dist/server/prod-server.js +19 -13
- package/dist/server/request-pipeline.js +2 -2
- package/dist/server/rsc-stream-hints.d.ts +12 -0
- package/dist/server/rsc-stream-hints.js +70 -35
- package/dist/server/seed-cache.js +3 -4
- package/dist/server/socket-error-backstop.js +1 -1
- package/dist/shims/cache-callable-runtime.d.ts +38 -0
- package/dist/shims/cache-callable-runtime.js +162 -11
- package/dist/shims/cache-runtime.d.ts +6 -8
- package/dist/shims/cache-runtime.js +89 -24
- package/dist/shims/constants.js +1 -1
- package/dist/shims/dynamic-preload-chunks.js +6 -2
- package/dist/shims/font-local.js +1 -1
- package/dist/shims/form.js +1 -1
- package/dist/shims/head.js +1 -1
- package/dist/shims/headers.js +2 -2
- package/dist/shims/image-config.js +2 -0
- package/dist/shims/internal/app-page-props-cache-key.d.ts +29 -0
- package/dist/shims/internal/app-page-props-cache-key.js +53 -1
- package/dist/shims/internal/format-url-object.d.ts +7 -0
- package/dist/shims/internal/format-url-object.js +53 -0
- package/dist/shims/internal/normalize-router-href.d.ts +15 -0
- package/dist/shims/internal/normalize-router-href.js +41 -0
- package/dist/shims/internal/pages-data-target.d.ts +4 -1
- package/dist/shims/internal/pages-data-target.js +28 -35
- package/dist/shims/internal/route-pattern-for-warning.d.ts +2 -2
- package/dist/shims/internal/route-pattern-for-warning.js +3 -3
- package/dist/shims/link.js +31 -92
- package/dist/shims/metadata.js +5 -4
- package/dist/shims/navigation.js +2 -2
- package/dist/shims/router-state.js +1 -1
- package/dist/shims/router.d.ts +8 -7
- package/dist/shims/router.js +312 -148
- package/dist/shims/script-nonce-context.d.ts +4 -1
- package/dist/shims/script-nonce-context.js +15 -6
- package/dist/shims/server.js +3 -3
- package/dist/utils/built-asset-url.js +1 -1
- package/dist/utils/client-runtime-metadata.d.ts +6 -0
- package/dist/utils/client-runtime-metadata.js +16 -0
- package/dist/utils/lazy-chunks.js +1 -1
- package/dist/utils/project.d.ts +1 -11
- package/dist/utils/project.js +20 -29
- package/dist/utils/react-version.d.ts +3 -1
- package/dist/utils/react-version.js +19 -1
- package/dist/utils/vite-cli-invocation.d.ts +21 -0
- package/dist/utils/vite-cli-invocation.js +144 -0
- package/package.json +10 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { magicStringTransformResult } from "./transform-result.js";
|
|
3
|
+
import { resolveHarfbuzzWasmPath } from "./og-harfbuzz.js";
|
|
3
4
|
import { OgAssetOwnership } from "./og-asset-ownership.js";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
6
|
import fs from "node:fs";
|
|
@@ -94,7 +95,11 @@ function createOgInlineFetchAssetsPlugin() {
|
|
|
94
95
|
}
|
|
95
96
|
};
|
|
96
97
|
}
|
|
97
|
-
const OG_WASM_ASSETS = [
|
|
98
|
+
const OG_WASM_ASSETS = [
|
|
99
|
+
"resvg.wasm",
|
|
100
|
+
"yoga.wasm",
|
|
101
|
+
"hb.wasm"
|
|
102
|
+
];
|
|
98
103
|
/**
|
|
99
104
|
* Find an emitted WASM asset in the output bundle whose name corresponds to the
|
|
100
105
|
* given base file (e.g. base `resvg.wasm` matches the emitted `resvg-HASH.wasm`).
|
|
@@ -105,15 +110,20 @@ const OG_WASM_ASSETS = ["resvg.wasm", "yoga.wasm"];
|
|
|
105
110
|
*
|
|
106
111
|
* @returns the emitted asset's `fileName` (relative to outDir), or null.
|
|
107
112
|
*/
|
|
108
|
-
function findEmittedWasmAsset(bundle, baseName) {
|
|
113
|
+
function findEmittedWasmAsset(bundle, baseName, expectedSource) {
|
|
109
114
|
const stem = baseName.replace(/\.wasm$/, "");
|
|
110
115
|
const re = new RegExp(`^${stem}(?:[-.][\\w-]+)?\\.wasm$`);
|
|
111
116
|
for (const output of Object.values(bundle)) {
|
|
112
117
|
if (output.type !== "asset") continue;
|
|
113
|
-
if (re.test(path.basename(output.fileName)))
|
|
118
|
+
if (!re.test(path.basename(output.fileName))) continue;
|
|
119
|
+
if (expectedSource && !isSameBytes(output.source, expectedSource)) continue;
|
|
120
|
+
return output.fileName;
|
|
114
121
|
}
|
|
115
122
|
return null;
|
|
116
123
|
}
|
|
124
|
+
function isSameBytes(source, expected) {
|
|
125
|
+
return source instanceof Uint8Array && Buffer.from(source).equals(expected);
|
|
126
|
+
}
|
|
117
127
|
/**
|
|
118
128
|
* Build the regex that matches the Node.js fallback reference
|
|
119
129
|
* `new URL("./<base>", import.meta.url)` for a given WASM base name.
|
|
@@ -162,7 +172,7 @@ function copyMissingOgWasm(opts) {
|
|
|
162
172
|
* target — so it helps Node/self-hosted builds as well as Cloudflare Workers.
|
|
163
173
|
*/
|
|
164
174
|
function createOgAssetsPlugin() {
|
|
165
|
-
|
|
175
|
+
const dedupedBasesByEnvironment = /* @__PURE__ */ new Map();
|
|
166
176
|
return {
|
|
167
177
|
name: "vinext:og-assets",
|
|
168
178
|
apply: "build",
|
|
@@ -170,17 +180,18 @@ function createOgAssetsPlugin() {
|
|
|
170
180
|
generateBundle: {
|
|
171
181
|
order: "post",
|
|
172
182
|
handler(_options, bundle) {
|
|
173
|
-
|
|
174
|
-
|
|
183
|
+
const envName = this.environment?.name;
|
|
184
|
+
if (envName !== "rsc" && envName !== "ssr") return;
|
|
185
|
+
const dedupedBases = /* @__PURE__ */ new Set();
|
|
186
|
+
dedupedBasesByEnvironment.set(envName, dedupedBases);
|
|
175
187
|
const chunks = Object.values(bundle).filter((o) => o.type === "chunk");
|
|
176
188
|
for (const base of OG_WASM_ASSETS) {
|
|
177
189
|
if (!chunks.some((c) => c.code.includes(base))) continue;
|
|
178
|
-
const emitted = findEmittedWasmAsset(bundle, base);
|
|
179
|
-
if (!emitted) continue;
|
|
190
|
+
const emitted = findEmittedWasmAsset(bundle, base, base === "hb.wasm" ? fs.readFileSync(resolveHarfbuzzWasmPath(createRequire(import.meta.url).resolve("@vercel/og"))) : void 0);
|
|
180
191
|
for (const chunk of chunks) {
|
|
181
192
|
const re = fallbackUrlRegex(base);
|
|
182
193
|
const chunkDir = path.dirname(chunk.fileName);
|
|
183
|
-
const rel = path.relative(chunkDir, emitted);
|
|
194
|
+
const rel = path.relative(chunkDir, emitted ?? base);
|
|
184
195
|
const ref = rel.startsWith(".") ? rel : `./${rel}`;
|
|
185
196
|
const s = new MagicString(chunk.code);
|
|
186
197
|
let edited = false;
|
|
@@ -197,7 +208,7 @@ function createOgAssetsPlugin() {
|
|
|
197
208
|
source: chunk.fileName
|
|
198
209
|
});
|
|
199
210
|
}
|
|
200
|
-
dedupedBases.add(base);
|
|
211
|
+
if (emitted) dedupedBases.add(base);
|
|
201
212
|
}
|
|
202
213
|
}
|
|
203
214
|
},
|
|
@@ -205,18 +216,26 @@ function createOgAssetsPlugin() {
|
|
|
205
216
|
sequential: true,
|
|
206
217
|
order: "post",
|
|
207
218
|
async handler(options, bundle) {
|
|
208
|
-
|
|
219
|
+
const envName = this.environment?.name;
|
|
220
|
+
if (envName !== "rsc" && envName !== "ssr") return;
|
|
209
221
|
const outDir = options.dir;
|
|
210
222
|
if (!outDir) return;
|
|
211
223
|
const chunkCode = Object.values(bundle).map((output) => output.type === "chunk" ? output.code : "").join("\n");
|
|
212
|
-
const
|
|
224
|
+
const dedupedBases = dedupedBasesByEnvironment.get(envName);
|
|
225
|
+
dedupedBasesByEnvironment.delete(envName);
|
|
226
|
+
const referencedAssets = OG_WASM_ASSETS.filter((asset) => chunkCode.includes(asset) && !dedupedBases?.has(asset));
|
|
213
227
|
if (referencedAssets.length === 0) return;
|
|
214
228
|
try {
|
|
215
229
|
const ogPkgPath = createRequire(import.meta.url).resolve("@vercel/og/package.json");
|
|
216
230
|
copyMissingOgWasm({
|
|
217
231
|
outDir,
|
|
218
232
|
sourceDir: path.join(path.dirname(ogPkgPath), "dist"),
|
|
219
|
-
assets: referencedAssets
|
|
233
|
+
assets: referencedAssets.filter((asset) => asset !== "hb.wasm")
|
|
234
|
+
});
|
|
235
|
+
if (referencedAssets.includes("hb.wasm")) copyMissingOgWasm({
|
|
236
|
+
outDir,
|
|
237
|
+
sourceDir: path.dirname(resolveHarfbuzzWasmPath(ogPkgPath)),
|
|
238
|
+
assets: ["hb.wasm"]
|
|
220
239
|
});
|
|
221
240
|
} catch {}
|
|
222
241
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
//#region src/plugins/og-harfbuzz.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the `hb.wasm` binary that matches the glue inlined in @vercel/og.
|
|
5
|
+
* @vercel/og and satori pin exact versions, so resolving through
|
|
6
|
+
* @vercel/og → satori → harfbuzzjs yields the build the bundle was made from.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveHarfbuzzWasmPath(ogEntry: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Read every function type in a WASM binary as an Emscripten signature (result
|
|
11
|
+
* letter, or `v` for none, then parameters). Any callback HarfBuzz calls
|
|
12
|
+
* through its function table must have one of these types, so adapters for
|
|
13
|
+
* all of them cover every callback the glue can register.
|
|
14
|
+
*/
|
|
15
|
+
export declare function readWasmFunctionSignatures(wasm: Uint8Array): string[];
|
|
16
|
+
/**
|
|
17
|
+
* Build the module Emscripten's `convertJsFunctionToWasm` compiles for a
|
|
18
|
+
* signature: it imports a JavaScript function as `e.f` and re-exports it as
|
|
19
|
+
* `f`. Every section in it is shorter than 128 bytes, so each length and count
|
|
20
|
+
* is a single LEB128 byte.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createHarfbuzzCallbackWasm(signature: string): Uint8Array<ArrayBuffer>;
|
|
23
|
+
export declare function createOgHarfbuzzPlugin(): Plugin;
|
|
24
|
+
//#endregion
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
+
import { magicStringTransformResult } from "./transform-result.js";
|
|
3
|
+
import { forEachAstChild, getAstName, staticStringValue } from "./ast-utils.js";
|
|
4
|
+
import { isFunctionNode } from "./ast-scope.js";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import { parseAst } from "vite";
|
|
8
|
+
import MagicString from "magic-string";
|
|
9
|
+
//#region src/plugins/og-harfbuzz.ts
|
|
10
|
+
/**
|
|
11
|
+
* vinext:og-harfbuzz — load @vercel/og's bundled HarfBuzz under vinext.
|
|
12
|
+
*
|
|
13
|
+
* @vercel/og 1.x inlines harfbuzzjs's Emscripten glue into both entry bundles.
|
|
14
|
+
* Unmodified, that glue cannot start:
|
|
15
|
+
*
|
|
16
|
+
* - Node ESM: its Node branch calls esbuild's `__require("fs")` and reads
|
|
17
|
+
* `__dirname`, neither of which exists in an ES module.
|
|
18
|
+
* - workerd: it reads `self.location.href`, takes the Node branch under
|
|
19
|
+
* `nodejs_compat`, and fetches `hb.wasm` from a relative URL. Workers also
|
|
20
|
+
* forbid compiling WASM from bytes, which Emscripten does for every
|
|
21
|
+
* JavaScript callback it adds to the WASM function table.
|
|
22
|
+
*
|
|
23
|
+
* The transform locates the HarfBuzz factory by syntax (the function that
|
|
24
|
+
* names `"hb.wasm"` and reads Emscripten's `instantiateWasm` hook) and, inside
|
|
25
|
+
* it only:
|
|
26
|
+
*
|
|
27
|
+
* 1. sets every `ENVIRONMENT_IS_*` flag to `false`, so no host branch runs;
|
|
28
|
+
* 2. replaces `instantiateWasm` reads with a vinext loader that instantiates
|
|
29
|
+
* `hb.wasm` synchronously (a `?module` import on workerd, a disk read on
|
|
30
|
+
* Node), so a bad binary rejects initialization instead of hanging it;
|
|
31
|
+
* 3. on workerd, serves callback modules from precompiled adapters instead
|
|
32
|
+
* of `new WebAssembly.Module(bytes)`.
|
|
33
|
+
*
|
|
34
|
+
* Whitespace, esbuild's renames and harfbuzzjs's wrapper code can change
|
|
35
|
+
* freely. If a patch site is missing, the build fails with an explicit error
|
|
36
|
+
* instead of shipping an OG route that breaks at runtime.
|
|
37
|
+
*/
|
|
38
|
+
const HARFBUZZ_WASM = "hb.wasm";
|
|
39
|
+
const VALUE_TYPES = {
|
|
40
|
+
i: 127,
|
|
41
|
+
j: 126,
|
|
42
|
+
f: 125,
|
|
43
|
+
d: 124
|
|
44
|
+
};
|
|
45
|
+
const VALUE_TYPE_LETTERS = new Map(Object.entries(VALUE_TYPES).map(([k, v]) => [v, k]));
|
|
46
|
+
/**
|
|
47
|
+
* Resolve the `hb.wasm` binary that matches the glue inlined in @vercel/og.
|
|
48
|
+
* @vercel/og and satori pin exact versions, so resolving through
|
|
49
|
+
* @vercel/og → satori → harfbuzzjs yields the build the bundle was made from.
|
|
50
|
+
*/
|
|
51
|
+
function resolveHarfbuzzWasmPath(ogEntry) {
|
|
52
|
+
const satoriEntry = createRequire(ogEntry).resolve("satori");
|
|
53
|
+
return toSlash(createRequire(satoriEntry).resolve(`harfbuzzjs/${HARFBUZZ_WASM}`));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Read every function type in a WASM binary as an Emscripten signature (result
|
|
57
|
+
* letter, or `v` for none, then parameters). Any callback HarfBuzz calls
|
|
58
|
+
* through its function table must have one of these types, so adapters for
|
|
59
|
+
* all of them cover every callback the glue can register.
|
|
60
|
+
*/
|
|
61
|
+
function readWasmFunctionSignatures(wasm) {
|
|
62
|
+
let offset = 8;
|
|
63
|
+
const readU32 = () => {
|
|
64
|
+
let result = 0;
|
|
65
|
+
for (let shift = 0;; shift += 7) {
|
|
66
|
+
const byte = wasm[offset++];
|
|
67
|
+
result |= (byte & 127) << shift;
|
|
68
|
+
if (!(byte & 128)) return result >>> 0;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const readTypes = () => {
|
|
72
|
+
let letters = "";
|
|
73
|
+
for (let count = readU32(); count > 0; count--) {
|
|
74
|
+
const letter = VALUE_TYPE_LETTERS.get(wasm[offset++]);
|
|
75
|
+
letters = letter && letters !== null ? letters + letter : null;
|
|
76
|
+
}
|
|
77
|
+
return letters;
|
|
78
|
+
};
|
|
79
|
+
const signatures = /* @__PURE__ */ new Set();
|
|
80
|
+
while (offset < wasm.length) {
|
|
81
|
+
const sectionId = wasm[offset++];
|
|
82
|
+
const sectionEnd = readU32() + offset;
|
|
83
|
+
if (sectionId === 1) for (let count = readU32(); count > 0; count--) {
|
|
84
|
+
offset++;
|
|
85
|
+
const params = readTypes();
|
|
86
|
+
const results = readTypes();
|
|
87
|
+
if (params !== null && results !== null && results.length <= 1) signatures.add((results || "v") + params);
|
|
88
|
+
}
|
|
89
|
+
offset = sectionEnd;
|
|
90
|
+
}
|
|
91
|
+
return [...signatures];
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build the module Emscripten's `convertJsFunctionToWasm` compiles for a
|
|
95
|
+
* signature: it imports a JavaScript function as `e.f` and re-exports it as
|
|
96
|
+
* `f`. Every section in it is shorter than 128 bytes, so each length and count
|
|
97
|
+
* is a single LEB128 byte.
|
|
98
|
+
*/
|
|
99
|
+
function createHarfbuzzCallbackWasm(signature) {
|
|
100
|
+
const typeCode = (letter) => {
|
|
101
|
+
const code = VALUE_TYPES[letter];
|
|
102
|
+
if (code === void 0) throw new Error(`[vinext] Invalid WASM callback signature: ${signature}`);
|
|
103
|
+
return code;
|
|
104
|
+
};
|
|
105
|
+
const [result, ...params] = signature;
|
|
106
|
+
const results = result === "v" ? [] : [typeCode(result)];
|
|
107
|
+
const functionType = [
|
|
108
|
+
96,
|
|
109
|
+
params.length,
|
|
110
|
+
...params.map(typeCode),
|
|
111
|
+
results.length,
|
|
112
|
+
...results
|
|
113
|
+
];
|
|
114
|
+
if (functionType.length > 64) throw new Error(`[vinext] WASM callback signature too long: ${signature}`);
|
|
115
|
+
const section = (id, contents) => [
|
|
116
|
+
id,
|
|
117
|
+
contents.length,
|
|
118
|
+
...contents
|
|
119
|
+
];
|
|
120
|
+
return Uint8Array.from([
|
|
121
|
+
0,
|
|
122
|
+
97,
|
|
123
|
+
115,
|
|
124
|
+
109,
|
|
125
|
+
1,
|
|
126
|
+
0,
|
|
127
|
+
0,
|
|
128
|
+
0,
|
|
129
|
+
...section(1, [1, ...functionType]),
|
|
130
|
+
...section(2, [
|
|
131
|
+
1,
|
|
132
|
+
1,
|
|
133
|
+
101,
|
|
134
|
+
1,
|
|
135
|
+
102,
|
|
136
|
+
0,
|
|
137
|
+
0
|
|
138
|
+
]),
|
|
139
|
+
...section(7, [
|
|
140
|
+
1,
|
|
141
|
+
1,
|
|
142
|
+
102,
|
|
143
|
+
0,
|
|
144
|
+
0
|
|
145
|
+
])
|
|
146
|
+
]);
|
|
147
|
+
}
|
|
148
|
+
/** Write each callback adapter once and return its path by signature. */
|
|
149
|
+
function writeHarfbuzzCallbackModules(harfbuzzWasm, outDir) {
|
|
150
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
151
|
+
const modules = /* @__PURE__ */ new Map();
|
|
152
|
+
for (const signature of readWasmFunctionSignatures(fs.readFileSync(harfbuzzWasm))) {
|
|
153
|
+
const filePath = path.join(outDir, `harfbuzz-callback-${signature}.wasm`);
|
|
154
|
+
if (!fs.existsSync(filePath)) {
|
|
155
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
156
|
+
fs.writeFileSync(tempPath, createHarfbuzzCallbackWasm(signature));
|
|
157
|
+
fs.renameSync(tempPath, filePath);
|
|
158
|
+
}
|
|
159
|
+
modules.set(signature, filePath);
|
|
160
|
+
}
|
|
161
|
+
return modules;
|
|
162
|
+
}
|
|
163
|
+
const contains = (outer, inner) => outer.start <= inner.start && inner.end <= outer.end;
|
|
164
|
+
/**
|
|
165
|
+
* Find the HarfBuzz factory — the innermost function that both names
|
|
166
|
+
* `"hb.wasm"` and reads `instantiateWasm` — and the patch sites inside it.
|
|
167
|
+
* Scoping edits to that function keeps yoga's own Emscripten module, which
|
|
168
|
+
* also reads `instantiateWasm`, untouched.
|
|
169
|
+
*/
|
|
170
|
+
function findHarfbuzzPatchSites(program) {
|
|
171
|
+
const functionStack = [];
|
|
172
|
+
const wasmNameScopes = [];
|
|
173
|
+
const instantiateWasmMembers = [];
|
|
174
|
+
const environmentFlags = [];
|
|
175
|
+
const moduleCompilations = [];
|
|
176
|
+
const visit = (node) => {
|
|
177
|
+
const isFunction = isFunctionNode(node);
|
|
178
|
+
if (isFunction) functionStack.push(node);
|
|
179
|
+
if (staticStringValue(node) === HARFBUZZ_WASM) wasmNameScopes.push([...functionStack]);
|
|
180
|
+
else if (node.type === "MemberExpression" && getAstName(node.property) === "instantiateWasm") instantiateWasmMembers.push(node);
|
|
181
|
+
else if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.id.name.startsWith("ENVIRONMENT_IS_") && node.init) environmentFlags.push({
|
|
182
|
+
declarator: node,
|
|
183
|
+
init: node.init
|
|
184
|
+
});
|
|
185
|
+
else if (node.type === "NewExpression" && node.callee.type === "MemberExpression" && getAstName(node.callee.object) === "WebAssembly" && getAstName(node.callee.property) === "Module" && functionStack.length > 0) moduleCompilations.push({
|
|
186
|
+
node,
|
|
187
|
+
enclosingFunction: functionStack[functionStack.length - 1]
|
|
188
|
+
});
|
|
189
|
+
forEachAstChild(node, visit);
|
|
190
|
+
if (isFunction) functionStack.pop();
|
|
191
|
+
};
|
|
192
|
+
visit(program);
|
|
193
|
+
const factories = /* @__PURE__ */ new Set();
|
|
194
|
+
for (const scopes of wasmNameScopes) {
|
|
195
|
+
const factory = [...scopes].reverse().find((scope) => instantiateWasmMembers.some((member) => contains(scope, member)));
|
|
196
|
+
if (factory) factories.add(factory);
|
|
197
|
+
}
|
|
198
|
+
if (factories.size !== 1) return `expected one function that names "${HARFBUZZ_WASM}" and reads instantiateWasm, found ${factories.size}`;
|
|
199
|
+
const [factory] = factories;
|
|
200
|
+
const flags = environmentFlags.filter(({ declarator }) => contains(factory, declarator));
|
|
201
|
+
if (!flags.some(({ declarator }) => getAstName(declarator.id) === "ENVIRONMENT_IS_NODE")) return "the factory does not declare ENVIRONMENT_IS_NODE";
|
|
202
|
+
return {
|
|
203
|
+
instantiateWasmReads: instantiateWasmMembers.filter((member) => contains(factory, member)),
|
|
204
|
+
environmentFlags: flags.map(({ init }) => init),
|
|
205
|
+
moduleCompilations: moduleCompilations.filter(({ node }) => contains(factory, node))
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const INSTANTIATE_WASM = `function __vi_hb_instantiateWasm(imports, receiveInstance) {
|
|
209
|
+
var instance = new WebAssembly.Instance(__vi_hb_module(), imports);
|
|
210
|
+
receiveInstance(instance);
|
|
211
|
+
return instance.exports;
|
|
212
|
+
}`;
|
|
213
|
+
function createOgHarfbuzzPlugin() {
|
|
214
|
+
let callbackModuleDir;
|
|
215
|
+
let isBuild = false;
|
|
216
|
+
return {
|
|
217
|
+
name: "vinext:og-harfbuzz",
|
|
218
|
+
enforce: "pre",
|
|
219
|
+
configResolved(config) {
|
|
220
|
+
callbackModuleDir = path.join(toSlash(config.root), ".vinext", "og-assets");
|
|
221
|
+
isBuild = config.command === "build";
|
|
222
|
+
},
|
|
223
|
+
transform: {
|
|
224
|
+
filter: {
|
|
225
|
+
id: /[\\/]@vercel[\\/]og[\\/]dist[\\/]index\.(?:edge|node)\.js(?:\?.*)?$/,
|
|
226
|
+
code: /["'`]hb\.wasm["'`]/
|
|
227
|
+
},
|
|
228
|
+
handler(code, id) {
|
|
229
|
+
const ogEntry = toSlash(id.split("?", 1)[0]);
|
|
230
|
+
const isWorkerd = ogEntry.endsWith("/index.edge.js");
|
|
231
|
+
const fail = (reason) => this.error(`[vinext] Unsupported @vercel/og HarfBuzz bundle in ${ogEntry}: ${reason}. vinext must be updated to support this @vercel/og version.`);
|
|
232
|
+
const sites = findHarfbuzzPatchSites(parseAst(code, { lang: "js" }));
|
|
233
|
+
if (typeof sites === "string") return fail(sites);
|
|
234
|
+
const output = new MagicString(code);
|
|
235
|
+
for (const flag of sites.environmentFlags) output.overwrite(flag.start, flag.end, "false");
|
|
236
|
+
for (const member of sites.instantiateWasmReads) output.overwrite(member.start, member.end, "__vi_hb_instantiateWasm");
|
|
237
|
+
const harfbuzzWasm = resolveHarfbuzzWasmPath(ogEntry);
|
|
238
|
+
const preamble = [];
|
|
239
|
+
if (isWorkerd) {
|
|
240
|
+
if (sites.moduleCompilations.length === 0) return fail("no callback module compilation (new WebAssembly.Module) was found");
|
|
241
|
+
for (const { node, enclosingFunction } of sites.moduleCompilations) {
|
|
242
|
+
const signature = isFunctionNode(enclosingFunction) ? enclosingFunction.params[1] : void 0;
|
|
243
|
+
if (signature?.type !== "Identifier") return fail("the callback compiler does not take a (func, sig) signature");
|
|
244
|
+
output.prependLeft(node.start, `(__vi_hb_callbacks[${signature.name}.replace(/p/g, "i")] || `);
|
|
245
|
+
output.appendRight(node.end, ")");
|
|
246
|
+
}
|
|
247
|
+
const callbacks = [...writeHarfbuzzCallbackModules(harfbuzzWasm, callbackModuleDir)];
|
|
248
|
+
preamble.push(`import __vi_hb_wasm from ${JSON.stringify(`${harfbuzzWasm}?module`)};`, ...callbacks.map(([, file], index) => `import __vi_hb_callback_${index} from ${JSON.stringify(`${file}?module`)};`), `var __vi_hb_callbacks = { ${callbacks.map(([signature], index) => `${signature}: __vi_hb_callback_${index}`).join(", ")} };`, "function __vi_hb_module() { return __vi_hb_wasm; }");
|
|
249
|
+
} else {
|
|
250
|
+
const location = isBuild ? `new URL("./${HARFBUZZ_WASM}", import.meta.url)` : JSON.stringify(harfbuzzWasm);
|
|
251
|
+
preamble.push(`import { readFileSync as __vi_hb_readFileSync } from "node:fs";`, `function __vi_hb_module() { return new WebAssembly.Module(__vi_hb_readFileSync(${location})); }`);
|
|
252
|
+
}
|
|
253
|
+
output.prepend(`${preamble.join("\n")}\n${INSTANTIATE_WASM}\n`);
|
|
254
|
+
return magicStringTransformResult(output);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
//#endregion
|
|
260
|
+
export { createHarfbuzzCallbackWasm, createOgHarfbuzzPlugin, readWasmFunctionSignatures, resolveHarfbuzzWasmPath };
|
|
@@ -5,8 +5,8 @@ import { VIRTUAL_MODULE_ID_RE } from "../utils/virtual-module.js";
|
|
|
5
5
|
import { collectBindingNames, getAstName } from "./ast-utils.js";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { parseAst } from "vite";
|
|
8
|
-
import fsp from "node:fs/promises";
|
|
9
8
|
import MagicString from "magic-string";
|
|
9
|
+
import fsp from "node:fs/promises";
|
|
10
10
|
//#region src/plugins/optimize-imports.ts
|
|
11
11
|
/**
|
|
12
12
|
* Read a file's contents, returning null on any error.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { stripViteModuleQuery } from "../utils/path.js";
|
|
3
2
|
import { magicStringTransformResult } from "./transform-result.js";
|
|
3
|
+
import { stripViteModuleQuery } from "../utils/path.js";
|
|
4
4
|
import { SCRIPT_MODULE_ID_RE, collectBindingNames, forEachAstChild, isIdentifierNamed, scriptParserLanguage, staticStringValue, unwrapExpression } from "./ast-utils.js";
|
|
5
5
|
import { collectDirectScopeBindings, collectLoopScopeBindings, collectSwitchScopeBindings, collectVarScopeBindings, createAstScope, hasAstBinding, isFunctionNode } from "./ast-scope.js";
|
|
6
6
|
import { createIdResolver, parseAst } from "vite";
|
|
7
|
-
import { readFile } from "node:fs/promises";
|
|
8
7
|
import MagicString from "magic-string";
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
9
|
//#region src/plugins/require-condition-resolution.ts
|
|
10
10
|
const LITERAL_REQUIRE_RE = /\brequire\s*\(/;
|
|
11
11
|
const CONDITIONAL_REQUIRE_SCRIPT_ID_RE = /\.vinext-require\.(?:js|jsx|ts|tsx)$/i;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { stripViteModuleQuery } from "../utils/path.js";
|
|
3
2
|
import { magicStringTransformResult } from "./transform-result.js";
|
|
3
|
+
import { stripViteModuleQuery } from "../utils/path.js";
|
|
4
4
|
import { SCRIPT_MODULE_ID_RE, booleanLiteralValue, scriptParserLanguage, stringLiteralValue, walkAst } from "./ast-utils.js";
|
|
5
5
|
import { parseAst } from "vite";
|
|
6
|
-
import { readdir, realpath, stat } from "node:fs/promises";
|
|
7
6
|
import MagicString from "magic-string";
|
|
7
|
+
import { readdir, realpath, stat } from "node:fs/promises";
|
|
8
8
|
//#region src/plugins/require-context.ts
|
|
9
9
|
function createRequireContextPlugin() {
|
|
10
10
|
const watchedContexts = /* @__PURE__ */ new WeakMap();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { stripViteModuleQuery } from "../utils/path.js";
|
|
3
2
|
import { magicStringTransformResult } from "./transform-result.js";
|
|
3
|
+
import { stripViteModuleQuery } from "../utils/path.js";
|
|
4
4
|
import { booleanLiteralValue, collectBindingNames, forEachAstChild, isIdentifierNamed, stringLiteralValue } from "./ast-utils.js";
|
|
5
5
|
import { collectDirectScopeBindings, collectLoopScopeBindings, collectSwitchScopeBindings, collectVarScopeBindings, createAstScope, hasAstBinding, isFunctionNode } from "./ast-scope.js";
|
|
6
6
|
import { parseAst } from "vite";
|
|
@@ -3,8 +3,6 @@ import { Plugin } from "vite";
|
|
|
3
3
|
type Options = {
|
|
4
4
|
projectRoot: string;
|
|
5
5
|
cacheRuntime: string;
|
|
6
|
-
getAppDir: () => string | undefined;
|
|
7
|
-
matchesPageExtension: (fileName: string) => boolean;
|
|
8
6
|
allowMissingRsc?: boolean;
|
|
9
7
|
};
|
|
10
8
|
export declare function createUseCacheCallablePlugin(options: Options): Promise<Plugin>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { NODE_MODULES_PATH_RE, isPathInside, stripViteModuleQuery } from "../utils/path.js";
|
|
3
2
|
import { magicStringTransformResult } from "./transform-result.js";
|
|
3
|
+
import { NODE_MODULES_PATH_RE } from "../utils/path.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { parseAstAsync } from "vite";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { createHmac, randomBytes } from "node:crypto";
|
|
7
8
|
//#region src/plugins/use-cache-callable.ts
|
|
8
9
|
const PLUGIN_NAME = "vinext:server-function-directives";
|
|
9
10
|
const SOURCE_MODULE_ID_RE = /\.(?:tsx?|jsx?|mjs)(?:\?.*)?$/;
|
|
@@ -43,13 +44,6 @@ function acceptsSecondArgument(meta) {
|
|
|
43
44
|
if (node?.type !== "FunctionDeclaration" && node?.type !== "FunctionExpression" && node?.type !== "ArrowFunctionExpression") return true;
|
|
44
45
|
return node.params.length >= 2 || node.params.some((parameter) => parameter.type === "RestElement");
|
|
45
46
|
}
|
|
46
|
-
function isAppPageDefaultExport(options, id, name, isModuleDirective) {
|
|
47
|
-
const appDir = options.getAppDir();
|
|
48
|
-
if (!isModuleDirective || name !== "default" || !appDir) return false;
|
|
49
|
-
const modulePath = stripViteModuleQuery(id);
|
|
50
|
-
const moduleFileName = path.basename(modulePath);
|
|
51
|
-
return isPathInside(appDir, modulePath) && path.parse(moduleFileName).name === "page" && options.matchesPageExtension(moduleFileName);
|
|
52
|
-
}
|
|
53
47
|
function shouldTransformModuleExport(name, id, meta) {
|
|
54
48
|
if (meta.isFunction === false && (name !== "default" && meta.valueNode?.type === "Literal" || meta.valueNode?.type === "ObjectExpression" || meta.valueNode?.type === "ArrayExpression")) return false;
|
|
55
49
|
if (/\/(layout|template)\.(tsx?|jsx?|mjs)$/.test(id) && name === "default") return false;
|
|
@@ -65,11 +59,21 @@ function hasFunctionDirective(meta, directive) {
|
|
|
65
59
|
if (node?.type !== "FunctionDeclaration" && node?.type !== "FunctionExpression" && node?.type !== "ArrowFunctionExpression" || node.body.type !== "BlockStatement") return false;
|
|
66
60
|
return node.body.body.some((statement) => statement.type === "ExpressionStatement" && "directive" in statement && statement.directive === directive);
|
|
67
61
|
}
|
|
68
|
-
function
|
|
62
|
+
function getFunctionDirectiveExportNames(transforms, ast, directive) {
|
|
63
|
+
const names = /* @__PURE__ */ new Set();
|
|
64
|
+
for (const group of transforms.scanModuleExports(ast)) {
|
|
65
|
+
const entries = group.type === "declaration" ? [group.export] : group.type === "variable-declaration" ? group.declarators.flatMap((declarator) => declarator.exports) : group.type === "specifiers" ? group.exports : group.type === "default" ? [{
|
|
66
|
+
exportName: "default",
|
|
67
|
+
meta: group.meta
|
|
68
|
+
}] : [];
|
|
69
|
+
for (const entry of entries) if (hasFunctionDirective(entry.meta, directive)) names.add(entry.exportName);
|
|
70
|
+
}
|
|
71
|
+
return names;
|
|
72
|
+
}
|
|
73
|
+
function getCacheWrapperOptions(meta) {
|
|
69
74
|
const argumentCount = getArgumentCount(meta);
|
|
70
75
|
return {
|
|
71
76
|
acceptsSecondArgument: acceptsSecondArgument(meta),
|
|
72
|
-
...isAppPageDefaultExport(options, id, name, isModuleDirective) ? { appPageDefaultExport: true } : {},
|
|
73
77
|
...argumentCount === void 0 ? {} : { argumentCount }
|
|
74
78
|
};
|
|
75
79
|
}
|
|
@@ -78,6 +82,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
78
82
|
const transformsPath = resolvePluginRscModule(options.projectRoot, "@vitejs/plugin-rsc/transforms");
|
|
79
83
|
const rscModule = await import(pathToFileURL(rscModulePath).href);
|
|
80
84
|
const transforms = await import(pathToFileURL(transformsPath).href);
|
|
85
|
+
const referenceSecret = randomBytes(32);
|
|
81
86
|
let manager;
|
|
82
87
|
return {
|
|
83
88
|
name: PLUGIN_NAME,
|
|
@@ -109,6 +114,8 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
109
114
|
const useServerBoundary = transforms.hasDirective(ast.body, "use server");
|
|
110
115
|
if (moduleDirective && useServerBoundary) throw new Error(`A module cannot contain both ${JSON.stringify(moduleDirective)} and "use server" directives.`);
|
|
111
116
|
const reference = manager.serverReferences.resolve(id, "rsc");
|
|
117
|
+
const relativeImportId = manager.toRelativeId(reference.importId);
|
|
118
|
+
const secureExportName = (name) => `$$vinext_cache_${createHmac("sha256", referenceSecret).update(relativeImportId).update("\0").update(name).digest("hex")}`;
|
|
112
119
|
if (!(this.environment.name === "rsc")) {
|
|
113
120
|
if (useServerBoundary) {
|
|
114
121
|
manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
|
|
@@ -126,6 +133,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
126
133
|
manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
|
|
127
134
|
return;
|
|
128
135
|
}
|
|
136
|
+
const useServerExportNames = getFunctionDirectiveExportNames(transforms, ast, "use server");
|
|
129
137
|
const result = transforms.transformDirectiveProxyExport(ast, {
|
|
130
138
|
code,
|
|
131
139
|
directive: moduleDirective,
|
|
@@ -134,7 +142,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
134
142
|
validateModuleExport(transforms, meta);
|
|
135
143
|
return true;
|
|
136
144
|
},
|
|
137
|
-
runtime: (name) => `$$ReactClient.createServerReference(${JSON.stringify(`${reference.referenceKey}#${name}`)},$$ReactClient.callServer,undefined,${this.environment.mode === "dev" ? "$$ReactClient.findSourceMapURL" : "undefined"},${JSON.stringify(name)})`
|
|
145
|
+
runtime: (name) => `$$ReactClient.createServerReference(${JSON.stringify(`${reference.referenceKey}#${useServerExportNames.has(name) ? name : secureExportName(name)}`)},$$ReactClient.callServer,undefined,${this.environment.mode === "dev" ? "$$ReactClient.findSourceMapURL" : "undefined"},${JSON.stringify(name)})`
|
|
138
146
|
});
|
|
139
147
|
if (!result?.output.hasChanged()) {
|
|
140
148
|
manager.serverReferences.deleteClaim(PLUGIN_NAME, id);
|
|
@@ -142,7 +150,7 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
142
150
|
}
|
|
143
151
|
manager.serverReferences.replaceClaim(PLUGIN_NAME, id, {
|
|
144
152
|
...reference,
|
|
145
|
-
exportNames: result.exportNames
|
|
153
|
+
exportNames: result.exportNames.map((name) => useServerExportNames.has(name) ? name : secureExportName(name))
|
|
146
154
|
});
|
|
147
155
|
const runtimeEnvironment = this.environment.name === "client" ? "browser" : "ssr";
|
|
148
156
|
result.output.prepend(`import * as $$ReactClient from "@vitejs/plugin-rsc/react/${runtimeEnvironment}";\n`);
|
|
@@ -151,19 +159,23 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
151
159
|
source: id
|
|
152
160
|
});
|
|
153
161
|
}
|
|
154
|
-
const
|
|
162
|
+
const secureExports = /* @__PURE__ */ new Set();
|
|
163
|
+
const wrap = (value, name, directiveMatch, meta) => {
|
|
155
164
|
const variant = directiveMatch[1] ?? "";
|
|
165
|
+
const secureName = secureExportName(name);
|
|
166
|
+
secureExports.add(secureName);
|
|
156
167
|
const wrapperOptions = {
|
|
157
|
-
...getCacheWrapperOptions(
|
|
158
|
-
serverReferenceId: `${reference.referenceKey}#${
|
|
168
|
+
...getCacheWrapperOptions(meta),
|
|
169
|
+
serverReferenceId: `${reference.referenceKey}#${secureName}`
|
|
159
170
|
};
|
|
160
171
|
return `$$cacheRuntime.registerCachedFunction(${value}, ${JSON.stringify(`${id}:${name}`)}, ${JSON.stringify(variant)}, ${JSON.stringify(wrapperOptions)})`;
|
|
161
172
|
};
|
|
162
173
|
let needsReactServer = false;
|
|
163
|
-
const runtime = (value, name, directiveMatch, meta
|
|
164
|
-
const cached = wrap(value, name, directiveMatch, meta
|
|
174
|
+
const runtime = (value, name, directiveMatch, meta) => {
|
|
175
|
+
const cached = wrap(value, name, directiveMatch, meta);
|
|
176
|
+
const secureName = secureExportName(name);
|
|
165
177
|
needsReactServer = true;
|
|
166
|
-
return
|
|
178
|
+
return `(${secureName} = $$VinextReactServer.registerServerReference(${cached}, ${JSON.stringify(reference.referenceKey)}, ${JSON.stringify(secureName)}))`;
|
|
167
179
|
};
|
|
168
180
|
const result = moduleDirective ? transforms.transformWrapExport(code, ast, {
|
|
169
181
|
filter: (name, meta) => {
|
|
@@ -171,12 +183,13 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
171
183
|
validateModuleExport(transforms, meta);
|
|
172
184
|
return true;
|
|
173
185
|
},
|
|
174
|
-
runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(moduleDirective), meta
|
|
186
|
+
runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(moduleDirective), meta)
|
|
175
187
|
}) : transforms.transformHoistInlineDirective(code, ast, {
|
|
176
188
|
directive: USE_CACHE_DIRECTIVE_CANDIDATE,
|
|
177
189
|
rejectNonAsyncFunction: true,
|
|
178
190
|
hoistRuntime: true,
|
|
179
|
-
|
|
191
|
+
noExport: true,
|
|
192
|
+
runtime: (value, name, meta) => runtime(value, name, matchUseCacheDirective(meta.directiveMatch[0]), meta),
|
|
180
193
|
encode: (value) => `$$cacheRuntime.encryptCacheCaptures(${value})`,
|
|
181
194
|
decode: (value) => value
|
|
182
195
|
});
|
|
@@ -186,10 +199,15 @@ async function createUseCacheCallablePlugin(options) {
|
|
|
186
199
|
}
|
|
187
200
|
manager.serverReferences.replaceClaim(PLUGIN_NAME, id, {
|
|
188
201
|
...reference,
|
|
189
|
-
exportNames:
|
|
202
|
+
exportNames: [...secureExports]
|
|
190
203
|
});
|
|
191
204
|
const importPosition = ast.body.find((node) => !("directive" in node))?.start ?? code.length;
|
|
192
|
-
result.output.prependLeft(importPosition, [
|
|
205
|
+
result.output.prependLeft(importPosition, [
|
|
206
|
+
`import * as $$cacheRuntime from ${JSON.stringify(options.cacheRuntime)};`,
|
|
207
|
+
needsReactServer && `import * as $$VinextReactServer from "@vitejs/plugin-rsc/react/rsc/server";`,
|
|
208
|
+
secureExports.size > 0 && `let ${[...secureExports].join(",")};`
|
|
209
|
+
].filter(Boolean).join("\n") + "\n");
|
|
210
|
+
if (secureExports.size > 0) result.output.append(`\nexport { ${[...secureExports].join(",")} };\n`);
|
|
193
211
|
return magicStringTransformResult(result.output, {
|
|
194
212
|
hires: "boundary",
|
|
195
213
|
source: id
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
+
import { magicStringTransformResult } from "./transform-result.js";
|
|
2
3
|
import { appendDeploymentIdQuery } from "../utils/deployment-id.js";
|
|
3
4
|
import { NODE_MODULES_PATH_RE, stripViteModuleQuery } from "../utils/path.js";
|
|
4
|
-
import { magicStringTransformResult } from "./transform-result.js";
|
|
5
5
|
import { staticStringValue, walkAst } from "./ast-utils.js";
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import { parseAst } from "vite";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path, { toSlash } from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
|
|
3
2
|
import { findFileWithExts, scanWithExtensions } from "./file-matcher.js";
|
|
3
|
+
import { decodeRouteSegment, isInvisibleSegment, sortRoutes } from "./utils.js";
|
|
4
4
|
import { validateRoutePatterns } from "./route-validation.js";
|
|
5
5
|
import { compareStrings } from "../utils/compare.js";
|
|
6
6
|
import fs from "node:fs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createValidFileMatcher } from "./file-matcher.js";
|
|
2
|
-
import { createRouteTrieCache, matchRouteWithTrie } from "./route-matching.js";
|
|
3
2
|
import { buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts } from "./app-route-graph.js";
|
|
3
|
+
import { createRouteTrieCache, matchRouteWithTrie } from "./route-matching.js";
|
|
4
4
|
//#region src/routing/app-router.ts
|
|
5
5
|
/**
|
|
6
6
|
* App Router file-system routing.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
-
import { decodeRouteSegment, sortRoutes } from "./utils.js";
|
|
3
2
|
import { createValidFileMatcher, scanWithExtensions } from "./file-matcher.js";
|
|
3
|
+
import { decodeRouteSegment, sortRoutes } from "./utils.js";
|
|
4
4
|
import { patternToNextFormat, validateRoutePatterns } from "./route-validation.js";
|
|
5
5
|
import { createRouteTrieCache, matchRouteWithTrieRawPathname } from "./route-matching.js";
|
|
6
6
|
//#region src/routing/pages-router.ts
|