@vitejs/plugin-rsc 0.5.18 → 0.5.20
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/dist/browser.d.ts +2 -2
- package/dist/{chunk-Dj_d7TT4.js → chunk-f2BShn47.js} +1 -1
- package/dist/{cjs-D2v1gYgq.js → cjs-v2jRTNln.js} +1 -61
- package/dist/core/browser.d.ts +5 -1
- package/dist/core/browser.js +1 -1
- package/dist/core/plugin.js +25 -1
- package/dist/core/rsc.d.ts +1 -1
- package/dist/core/rsc.js +84 -1
- package/dist/core/ssr.d.ts +1 -1
- package/dist/core/ssr.js +1 -1
- package/dist/import-environment-B994HXEc.d.ts +11 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -4
- package/dist/{picocolors-BRyoHAlU.js → picocolors-B0A1T24z.js} +1 -1
- package/dist/plugin.d.ts +179 -3
- package/dist/plugin.js +1461 -4
- package/dist/plugins/cjs.js +62 -1
- package/dist/react/browser.d.ts +2 -2
- package/dist/react/rsc.js +1 -1
- package/dist/rsc.d.ts +3 -2
- package/dist/rsc.js +2 -2
- package/dist/ssr.d.ts +3 -2
- package/dist/ssr.js +1 -1
- package/dist/transforms/index.d.ts +1 -1
- package/dist/transforms/index.js +1 -1
- package/dist/utils/encryption-runtime.js +1 -2
- package/dist/utils/rpc.js +89 -1
- package/dist/validate-import-DJumtHRw.js +498 -0
- package/package.json +7 -7
- package/dist/browser-s-WcB8A7.d.ts +0 -6
- package/dist/plugin-BGmSmdwL.js +0 -27
- package/dist/plugin-Cp12dr0Z.js +0 -1944
- package/dist/plugin-K7i9F4Fd.d.ts +0 -187
- package/dist/rpc-EIuXyQpO.js +0 -91
- package/dist/rsc-Bhp6O2qz.js +0 -86
- /package/dist/{encryption-utils-DdqSKS_O.js → encryption-utils-Bk5eKdu6.js} +0 -0
- /package/dist/{index-now_lP2V.d.ts → index-BIbdRBfk.d.ts} +0 -0
- /package/dist/{index-CLmWsR1c.d.ts → server-action-B2zS9t-J.d.ts} +0 -0
- /package/dist/{transforms-B2EJTNXG.js → server-action-JkEy-6yW.js} +0 -0
- /package/dist/{shared-rtJPs0Yj.js → shared-Dhw3vs8e.js} +0 -0
- /package/dist/{shared-CGK4coF3.js → shared-d80_k_tn.js} +0 -0
package/dist/plugin.js
CHANGED
|
@@ -1,6 +1,1463 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import {
|
|
3
|
-
import "./
|
|
4
|
-
import "./
|
|
1
|
+
import { n as __toESM } from "./chunk-f2BShn47.js";
|
|
2
|
+
import { t as createDebug } from "./dist-yW9-EeG1.js";
|
|
3
|
+
import vitePluginRscCore from "./core/plugin.js";
|
|
4
|
+
import "./cjs-v2jRTNln.js";
|
|
5
|
+
import { i as toCssVirtual, n as parseIdQuery, r as parseReferenceValidationVirtual, t as parseCssVirtual } from "./shared-d80_k_tn.js";
|
|
6
|
+
import { cjsModuleRunnerPlugin } from "./plugins/cjs.js";
|
|
7
|
+
import { _ as cleanUrl, a as ensureEnvironmentImportsEntryFallback, b as normalizeViteImportAnalysisUrl, c as createVirtualPlugin, d as getFetchHandlerExport, f as hashString, g as vitePluginFindSourceMapURL, h as withRollupError, i as withResolvedIdProxy, l as getEntrySource, m as sortObject, n as scanBuildStripPlugin, o as vitePluginImportEnvironment, p as normalizeRelativePath, r as vitePluginResolvedIdProxy, s as writeEnvironmentImportsManifest, t as validateImportPlugin, u as getFallbackRollupEntry, v as directRequestRE, x as prepareError, y as evalValue } from "./validate-import-DJumtHRw.js";
|
|
8
|
+
import { a as hasDirective, n as transformDirectiveProxyExport, o as transformWrapExport, s as findDirectives, t as transformServerActionServer } from "./server-action-JkEy-6yW.js";
|
|
9
|
+
import "./transforms/index.js";
|
|
10
|
+
import { o as generateEncryptionKey, s as toBase64 } from "./encryption-utils-Bk5eKdu6.js";
|
|
11
|
+
import { createRpcServer } from "./utils/rpc.js";
|
|
12
|
+
import { createRequire } from "node:module";
|
|
13
|
+
import assert from "node:assert";
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { pathToFileURL } from "node:url";
|
|
17
|
+
import { exactRegex, prefixRegex } from "@rolldown/pluginutils";
|
|
18
|
+
import * as esModuleLexer from "es-module-lexer";
|
|
19
|
+
import MagicString from "magic-string";
|
|
20
|
+
import { toNodeHandler } from "srvx/node";
|
|
21
|
+
import { stripLiteral } from "strip-literal";
|
|
22
|
+
import * as vite from "vite";
|
|
23
|
+
import { defaultServerConditions, isCSSRequest, normalizePath, parseAstAsync } from "vite";
|
|
24
|
+
import { crawlFrameworkPkgs } from "vitefu";
|
|
5
25
|
|
|
26
|
+
//#region src/plugin.ts
|
|
27
|
+
const isRolldownVite = "rolldownVersion" in vite;
|
|
28
|
+
const BUILD_ASSETS_MANIFEST_NAME = "__vite_rsc_assets_manifest.js";
|
|
29
|
+
const PKG_NAME = "@vitejs/plugin-rsc";
|
|
30
|
+
const REACT_SERVER_DOM_NAME = `${PKG_NAME}/vendor/react-server-dom`;
|
|
31
|
+
const VIRTUAL_ENTRIES = { browser: "virtual:vite-rsc/entry-browser" };
|
|
32
|
+
const require = createRequire(import.meta.url);
|
|
33
|
+
function resolvePackage(name) {
|
|
34
|
+
return pathToFileURL(require.resolve(name)).href;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @experimental
|
|
38
|
+
*/
|
|
39
|
+
var RscPluginManager = class {
|
|
40
|
+
server;
|
|
41
|
+
config;
|
|
42
|
+
bundles = {};
|
|
43
|
+
buildAssetsManifest;
|
|
44
|
+
isScanBuild = false;
|
|
45
|
+
clientReferenceMetaMap = {};
|
|
46
|
+
clientReferenceGroups = {};
|
|
47
|
+
serverReferenceMetaMap = {};
|
|
48
|
+
serverResourcesMetaMap = {};
|
|
49
|
+
environmentImportMetaMap = {};
|
|
50
|
+
stabilize() {
|
|
51
|
+
this.clientReferenceMetaMap = sortObject(this.clientReferenceMetaMap);
|
|
52
|
+
this.serverResourcesMetaMap = sortObject(this.serverResourcesMetaMap);
|
|
53
|
+
}
|
|
54
|
+
toRelativeId(id) {
|
|
55
|
+
return normalizePath(path.relative(this.config.root, id));
|
|
56
|
+
}
|
|
57
|
+
writeAssetsManifest(environmentNames) {
|
|
58
|
+
const assetsManifestCode = `export default ${serializeValueWithRuntime(this.buildAssetsManifest)}`;
|
|
59
|
+
for (const name of environmentNames) {
|
|
60
|
+
const manifestPath = path.join(this.config.environments[name].build.outDir, BUILD_ASSETS_MANIFEST_NAME);
|
|
61
|
+
fs.writeFileSync(manifestPath, assetsManifestCode);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
writeEnvironmentImportsManifest() {
|
|
65
|
+
writeEnvironmentImportsManifest(this);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
/** @experimental */
|
|
69
|
+
function getPluginApi(config) {
|
|
70
|
+
return config.plugins.find((p) => p.name === "rsc:minimal")?.api;
|
|
71
|
+
}
|
|
72
|
+
/** @experimental */
|
|
73
|
+
function vitePluginRscMinimal(rscPluginOptions = {}, manager = new RscPluginManager()) {
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
name: "rsc:minimal",
|
|
77
|
+
enforce: "pre",
|
|
78
|
+
api: { manager },
|
|
79
|
+
async config() {
|
|
80
|
+
await esModuleLexer.init;
|
|
81
|
+
},
|
|
82
|
+
configResolved(config) {
|
|
83
|
+
manager.config = config;
|
|
84
|
+
for (const e of Object.values(config.environments)) e.build.outDir = path.resolve(config.root, e.build.outDir);
|
|
85
|
+
},
|
|
86
|
+
configureServer(server_) {
|
|
87
|
+
manager.server = server_;
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "rsc:vite-client-raw-import",
|
|
92
|
+
transform: {
|
|
93
|
+
order: "post",
|
|
94
|
+
filter: { code: "__vite_rsc_raw_import__" },
|
|
95
|
+
handler(code) {
|
|
96
|
+
if (code.includes("__vite_rsc_raw_import__")) return code.replace("__vite_rsc_raw_import__", "import");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
...vitePluginRscCore(),
|
|
101
|
+
...vitePluginUseClient(rscPluginOptions, manager),
|
|
102
|
+
...vitePluginUseServer(rscPluginOptions, manager),
|
|
103
|
+
...vitePluginDefineEncryptionKey(rscPluginOptions),
|
|
104
|
+
{
|
|
105
|
+
name: "rsc:reference-validation",
|
|
106
|
+
apply: "serve",
|
|
107
|
+
load: {
|
|
108
|
+
filter: { id: prefixRegex("\0virtual:vite-rsc/reference-validation?") },
|
|
109
|
+
handler(id, _options) {
|
|
110
|
+
if (id.startsWith("\0virtual:vite-rsc/reference-validation?")) {
|
|
111
|
+
const parsed = parseReferenceValidationVirtual(id);
|
|
112
|
+
assert(parsed);
|
|
113
|
+
if (parsed.type === "client") {
|
|
114
|
+
if (Object.values(manager.clientReferenceMetaMap).find((meta) => meta.referenceKey === parsed.id)) return `export {}`;
|
|
115
|
+
}
|
|
116
|
+
if (parsed.type === "server") {
|
|
117
|
+
if (Object.values(manager.serverReferenceMetaMap).find((meta) => meta.referenceKey === parsed.id)) return `export {}`;
|
|
118
|
+
}
|
|
119
|
+
this.error(`[vite-rsc] invalid ${parsed.type} reference '${parsed.id}'`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
scanBuildStripPlugin({ manager }),
|
|
125
|
+
vitePluginResolvedIdProxy()
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
function vitePluginRsc(rscPluginOptions = {}) {
|
|
129
|
+
const manager = new RscPluginManager();
|
|
130
|
+
const buildApp = async (builder) => {
|
|
131
|
+
const colors = await import("./picocolors-B0A1T24z.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
|
|
132
|
+
const logStep = (msg) => {
|
|
133
|
+
builder.config.logger.info(colors.blue(msg));
|
|
134
|
+
};
|
|
135
|
+
const rscOutDir = builder.environments.rsc.config.build.outDir;
|
|
136
|
+
const ssrOutDir = builder.environments.ssr.config.build.outDir;
|
|
137
|
+
const rscInsideSsr = path.normalize(rscOutDir).startsWith(path.normalize(ssrOutDir) + path.sep);
|
|
138
|
+
const tempRscOutDir = path.join(builder.config.root, "node_modules", ".vite-rsc-temp", "rsc");
|
|
139
|
+
ensureEnvironmentImportsEntryFallback(builder.config);
|
|
140
|
+
manager.isScanBuild = true;
|
|
141
|
+
builder.environments.rsc.config.build.write = false;
|
|
142
|
+
builder.environments.ssr.config.build.write = false;
|
|
143
|
+
logStep("[1/5] analyze client references...");
|
|
144
|
+
await builder.build(builder.environments.rsc);
|
|
145
|
+
logStep("[2/5] analyze server references...");
|
|
146
|
+
await builder.build(builder.environments.ssr);
|
|
147
|
+
manager.isScanBuild = false;
|
|
148
|
+
builder.environments.rsc.config.build.write = true;
|
|
149
|
+
builder.environments.ssr.config.build.write = true;
|
|
150
|
+
logStep("[3/5] build rsc environment...");
|
|
151
|
+
await builder.build(builder.environments.rsc);
|
|
152
|
+
if (rscInsideSsr) {
|
|
153
|
+
if (fs.existsSync(tempRscOutDir)) fs.rmSync(tempRscOutDir, { recursive: true });
|
|
154
|
+
fs.mkdirSync(path.dirname(tempRscOutDir), { recursive: true });
|
|
155
|
+
fs.renameSync(rscOutDir, tempRscOutDir);
|
|
156
|
+
}
|
|
157
|
+
manager.stabilize();
|
|
158
|
+
logStep("[4/5] build client environment...");
|
|
159
|
+
await builder.build(builder.environments.client);
|
|
160
|
+
logStep("[5/5] build ssr environment...");
|
|
161
|
+
await builder.build(builder.environments.ssr);
|
|
162
|
+
if (rscInsideSsr) {
|
|
163
|
+
if (fs.existsSync(rscOutDir)) fs.rmSync(rscOutDir, { recursive: true });
|
|
164
|
+
fs.mkdirSync(path.dirname(rscOutDir), { recursive: true });
|
|
165
|
+
fs.renameSync(tempRscOutDir, rscOutDir);
|
|
166
|
+
}
|
|
167
|
+
manager.writeAssetsManifest(["ssr", "rsc"]);
|
|
168
|
+
manager.writeEnvironmentImportsManifest();
|
|
169
|
+
};
|
|
170
|
+
let hasReactServerDomWebpack = false;
|
|
171
|
+
return [
|
|
172
|
+
{
|
|
173
|
+
name: "rsc",
|
|
174
|
+
async config(config, env) {
|
|
175
|
+
if (config.rsc) Object.assign(rscPluginOptions, vite.mergeConfig(config.rsc, rscPluginOptions));
|
|
176
|
+
const result = await crawlFrameworkPkgs({
|
|
177
|
+
root: process.cwd(),
|
|
178
|
+
isBuild: env.command === "build",
|
|
179
|
+
isFrameworkPkgByJson(pkgJson) {
|
|
180
|
+
if ([PKG_NAME, "react-dom"].includes(pkgJson.name)) return;
|
|
181
|
+
const deps = pkgJson["peerDependencies"];
|
|
182
|
+
return deps && "react" in deps;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
const noExternal = [
|
|
186
|
+
"react",
|
|
187
|
+
"react-dom",
|
|
188
|
+
"server-only",
|
|
189
|
+
"client-only",
|
|
190
|
+
PKG_NAME,
|
|
191
|
+
...result.ssr.noExternal.sort()
|
|
192
|
+
];
|
|
193
|
+
hasReactServerDomWebpack = result.ssr.noExternal.includes("react-server-dom-webpack");
|
|
194
|
+
const reactServerDomPackageName = hasReactServerDomWebpack ? "react-server-dom-webpack" : REACT_SERVER_DOM_NAME;
|
|
195
|
+
return {
|
|
196
|
+
appType: config.appType ?? "custom",
|
|
197
|
+
define: { "import.meta.env.__vite_rsc_build__": JSON.stringify(env.command === "build") },
|
|
198
|
+
environments: {
|
|
199
|
+
client: {
|
|
200
|
+
build: {
|
|
201
|
+
outDir: config.environments?.client?.build?.outDir ?? "dist/client",
|
|
202
|
+
rollupOptions: { input: rscPluginOptions.entries?.client && { index: rscPluginOptions.entries.client } }
|
|
203
|
+
},
|
|
204
|
+
optimizeDeps: {
|
|
205
|
+
include: ["react-dom/client", `${reactServerDomPackageName}/client.browser`],
|
|
206
|
+
exclude: [PKG_NAME]
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
ssr: {
|
|
210
|
+
build: {
|
|
211
|
+
outDir: config.environments?.ssr?.build?.outDir ?? "dist/ssr",
|
|
212
|
+
copyPublicDir: false,
|
|
213
|
+
rollupOptions: { input: rscPluginOptions.entries?.ssr && { index: rscPluginOptions.entries.ssr } }
|
|
214
|
+
},
|
|
215
|
+
resolve: { noExternal },
|
|
216
|
+
optimizeDeps: {
|
|
217
|
+
include: [
|
|
218
|
+
"react",
|
|
219
|
+
"react-dom",
|
|
220
|
+
"react/jsx-runtime",
|
|
221
|
+
"react/jsx-dev-runtime",
|
|
222
|
+
"react-dom/server.edge",
|
|
223
|
+
"react-dom/static.edge",
|
|
224
|
+
`${reactServerDomPackageName}/client.edge`
|
|
225
|
+
],
|
|
226
|
+
exclude: [PKG_NAME]
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
rsc: {
|
|
230
|
+
build: {
|
|
231
|
+
outDir: config.environments?.rsc?.build?.outDir ?? "dist/rsc",
|
|
232
|
+
copyPublicDir: false,
|
|
233
|
+
emitAssets: true,
|
|
234
|
+
rollupOptions: { input: rscPluginOptions.entries?.rsc && { index: rscPluginOptions.entries.rsc } }
|
|
235
|
+
},
|
|
236
|
+
resolve: {
|
|
237
|
+
conditions: ["react-server", ...defaultServerConditions],
|
|
238
|
+
noExternal
|
|
239
|
+
},
|
|
240
|
+
optimizeDeps: {
|
|
241
|
+
include: [
|
|
242
|
+
"react",
|
|
243
|
+
"react-dom",
|
|
244
|
+
"react/jsx-runtime",
|
|
245
|
+
"react/jsx-dev-runtime",
|
|
246
|
+
`${reactServerDomPackageName}/server.edge`,
|
|
247
|
+
`${reactServerDomPackageName}/client.edge`
|
|
248
|
+
],
|
|
249
|
+
exclude: [PKG_NAME]
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
builder: rscPluginOptions.customBuildApp ? void 0 : {
|
|
254
|
+
sharedPlugins: true,
|
|
255
|
+
sharedConfigBuild: true,
|
|
256
|
+
async buildApp(builder) {
|
|
257
|
+
if (!rscPluginOptions.useBuildAppHook) await buildApp(builder);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
},
|
|
262
|
+
configResolved() {
|
|
263
|
+
if (Number(vite.version.split(".")[0]) >= 7) rscPluginOptions.useBuildAppHook ??= true;
|
|
264
|
+
},
|
|
265
|
+
buildApp: { async handler(builder) {
|
|
266
|
+
if (rscPluginOptions.customBuildApp) return;
|
|
267
|
+
if (rscPluginOptions.useBuildAppHook) await buildApp(builder);
|
|
268
|
+
} },
|
|
269
|
+
configureServer(server) {
|
|
270
|
+
globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__ = async function(environmentName, id) {
|
|
271
|
+
const environment = server.environments[environmentName];
|
|
272
|
+
if (!environment) throw new Error(`[vite-rsc] unknown environment '${environmentName}'`);
|
|
273
|
+
if (!vite.isRunnableDevEnvironment(environment)) throw new Error(`[vite-rsc] environment '${environmentName}' is not runnable`);
|
|
274
|
+
return environment.runner.import(id);
|
|
275
|
+
};
|
|
276
|
+
const oldSend = server.environments.client.hot.send;
|
|
277
|
+
server.environments.client.hot.send = async function(...args) {
|
|
278
|
+
const e = args[0];
|
|
279
|
+
if (e && typeof e === "object" && e.type === "update") {
|
|
280
|
+
for (const update of e.updates) if (update.type === "js-update") {
|
|
281
|
+
const mod = server.environments.client.moduleGraph.urlToModuleMap.get(update.path);
|
|
282
|
+
if (mod && mod.id && manager.clientReferenceMetaMap[mod.id]) {
|
|
283
|
+
const serverMod = server.environments.rsc.moduleGraph.getModuleById(mod.id);
|
|
284
|
+
if (serverMod) server.environments.rsc.moduleGraph.invalidateModule(serverMod);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return oldSend.apply(this, args);
|
|
289
|
+
};
|
|
290
|
+
if (rscPluginOptions.serverHandler === false) return;
|
|
291
|
+
const options = rscPluginOptions.serverHandler ?? {
|
|
292
|
+
environmentName: "rsc",
|
|
293
|
+
entryName: "index"
|
|
294
|
+
};
|
|
295
|
+
const environment = server.environments[options.environmentName];
|
|
296
|
+
const source = getEntrySource(environment.config, options.entryName);
|
|
297
|
+
return () => {
|
|
298
|
+
server.middlewares.use(async (req, res, next) => {
|
|
299
|
+
try {
|
|
300
|
+
const resolved = await environment.pluginContainer.resolveId(source);
|
|
301
|
+
assert(resolved, `[vite-rsc] failed to resolve server handler '${source}'`);
|
|
302
|
+
const fetchHandler = getFetchHandlerExport(await environment.runner.import(resolved.id));
|
|
303
|
+
req.url = req.originalUrl ?? req.url;
|
|
304
|
+
await toNodeHandler(fetchHandler)(req, res);
|
|
305
|
+
} catch (e) {
|
|
306
|
+
next(e);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
},
|
|
311
|
+
async configurePreviewServer(server) {
|
|
312
|
+
if (rscPluginOptions.serverHandler === false) return;
|
|
313
|
+
const options = rscPluginOptions.serverHandler ?? {
|
|
314
|
+
environmentName: "rsc",
|
|
315
|
+
entryName: "index"
|
|
316
|
+
};
|
|
317
|
+
const handler = toNodeHandler(getFetchHandlerExport(await import(pathToFileURL(path.join(manager.config.environments[options.environmentName].build.outDir, `${options.entryName}.js`)).href)));
|
|
318
|
+
server.middlewares.use((req, _res, next) => {
|
|
319
|
+
delete req.headers["accept-encoding"];
|
|
320
|
+
next();
|
|
321
|
+
});
|
|
322
|
+
return () => {
|
|
323
|
+
server.middlewares.use(async (req, res, next) => {
|
|
324
|
+
try {
|
|
325
|
+
req.url = req.originalUrl ?? req.url;
|
|
326
|
+
await handler(req, res);
|
|
327
|
+
} catch (e) {
|
|
328
|
+
next(e);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
},
|
|
333
|
+
async hotUpdate(ctx) {
|
|
334
|
+
if (isCSSRequest(ctx.file)) {
|
|
335
|
+
if (this.environment.name === "client") return;
|
|
336
|
+
}
|
|
337
|
+
if (ctx.modules.map((mod) => mod.id).filter((v) => v !== null).length === 0) return;
|
|
338
|
+
if (this.environment.name === "rsc") {
|
|
339
|
+
for (const mod of ctx.modules) if (mod.type === "js" && mod.id && mod.id in manager.clientReferenceMetaMap) try {
|
|
340
|
+
await this.environment.transformRequest(mod.url);
|
|
341
|
+
} catch {}
|
|
342
|
+
}
|
|
343
|
+
function isInsideClientBoundary(mods) {
|
|
344
|
+
const visited = /* @__PURE__ */ new Set();
|
|
345
|
+
function recurse(mod) {
|
|
346
|
+
if (!mod.id) return false;
|
|
347
|
+
if (manager.clientReferenceMetaMap[mod.id]) return true;
|
|
348
|
+
if (visited.has(mod.id)) return false;
|
|
349
|
+
visited.add(mod.id);
|
|
350
|
+
for (const importer of mod.importers) if (recurse(importer)) return true;
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
return mods.some((mod) => recurse(mod));
|
|
354
|
+
}
|
|
355
|
+
if (!isInsideClientBoundary(ctx.modules)) {
|
|
356
|
+
if (this.environment.name === "rsc") {
|
|
357
|
+
if (ctx.modules.length === 1) {
|
|
358
|
+
const importers = [...ctx.modules[0].importers];
|
|
359
|
+
if (importers.length > 0 && importers.every((m) => m.id && isCSSRequest(m.id))) return [];
|
|
360
|
+
}
|
|
361
|
+
for (const mod of ctx.modules) if (mod.type === "js") try {
|
|
362
|
+
await this.environment.transformRequest(mod.url);
|
|
363
|
+
} catch (e) {
|
|
364
|
+
manager.server.environments.client.hot.send({
|
|
365
|
+
type: "error",
|
|
366
|
+
err: prepareError(e)
|
|
367
|
+
});
|
|
368
|
+
throw e;
|
|
369
|
+
}
|
|
370
|
+
ctx.server.environments.client.hot.send({
|
|
371
|
+
type: "custom",
|
|
372
|
+
event: "rsc:update",
|
|
373
|
+
data: { file: ctx.file }
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
if (this.environment.name === "client") {
|
|
377
|
+
if (ctx.server.environments.rsc.moduleGraph.getModuleById(ctx.file)) {
|
|
378
|
+
for (const clientMod of ctx.modules) for (const importer of clientMod.importers) if (importer.id && isCSSRequest(importer.id)) await this.environment.reloadModule(importer);
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: "rsc:react-server-dom-webpack-alias",
|
|
387
|
+
resolveId: {
|
|
388
|
+
order: "pre",
|
|
389
|
+
filter: { id: prefixRegex(`${PKG_NAME}/vendor/react-server-dom/`) },
|
|
390
|
+
async handler(source, importer, options) {
|
|
391
|
+
if (hasReactServerDomWebpack && source.startsWith(`${PKG_NAME}/vendor/react-server-dom/`)) {
|
|
392
|
+
const newSource = source.replace(`${PKG_NAME}/vendor/react-server-dom`, "react-server-dom-webpack");
|
|
393
|
+
return await this.resolve(newSource, importer, {
|
|
394
|
+
...options,
|
|
395
|
+
skipSelf: true
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
name: "rsc:load-environment-module",
|
|
403
|
+
transform: {
|
|
404
|
+
filter: { code: "import.meta.viteRsc.loadModule" },
|
|
405
|
+
async handler(code) {
|
|
406
|
+
if (!code.includes("import.meta.viteRsc.loadModule")) return;
|
|
407
|
+
const { server } = manager;
|
|
408
|
+
const s = new MagicString(code);
|
|
409
|
+
for (const match of stripLiteral(code).matchAll(/import\.meta\.viteRsc\.loadModule\(([\s\S]*?)\)/dg)) {
|
|
410
|
+
const [argStart, argEnd] = match.indices[1];
|
|
411
|
+
const [environmentName, entryName] = evalValue(`[${code.slice(argStart, argEnd).trim()}]`);
|
|
412
|
+
let replacement;
|
|
413
|
+
if (this.environment.mode === "dev" && rscPluginOptions.loadModuleDevProxy) replacement = `import("virtual:vite-rsc/rpc-client").then((module) => module.createRpcClient(${JSON.stringify({
|
|
414
|
+
environmentName,
|
|
415
|
+
entryName
|
|
416
|
+
})}))`;
|
|
417
|
+
else if (this.environment.mode === "dev") {
|
|
418
|
+
const environment = server.environments[environmentName];
|
|
419
|
+
const source = getEntrySource(environment.config, entryName);
|
|
420
|
+
const resolved = await environment.pluginContainer.resolveId(source);
|
|
421
|
+
assert(resolved, `[vite-rsc] failed to resolve entry '${source}'`);
|
|
422
|
+
replacement = `globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__(${JSON.stringify(environmentName)}, ${JSON.stringify(resolved.id)})`;
|
|
423
|
+
} else {
|
|
424
|
+
const environment = manager.config.environments[environmentName];
|
|
425
|
+
const targetName = entryName || getFallbackRollupEntry(environment.build.rollupOptions.input).name;
|
|
426
|
+
replacement = JSON.stringify(`__vite_rsc_load_module_start__:` + JSON.stringify({
|
|
427
|
+
fromEnv: this.environment.name,
|
|
428
|
+
toEnv: environmentName,
|
|
429
|
+
targetFileName: `${targetName}.js`
|
|
430
|
+
}) + `:__vite_rsc_load_module_end__`);
|
|
431
|
+
}
|
|
432
|
+
const [start, end] = match.indices[0];
|
|
433
|
+
s.overwrite(start, end, replacement);
|
|
434
|
+
}
|
|
435
|
+
if (s.hasChanged()) return {
|
|
436
|
+
code: s.toString(),
|
|
437
|
+
map: s.generateMap({ hires: "boundary" })
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
renderChunk(code, chunk) {
|
|
442
|
+
if (!code.includes("__vite_rsc_load_module")) return;
|
|
443
|
+
const { config } = manager;
|
|
444
|
+
const s = new MagicString(code);
|
|
445
|
+
for (const match of code.matchAll(/[`'"]__vite_rsc_load_module_start__:([\s\S]*?):__vite_rsc_load_module_end__[`'"]/dg)) {
|
|
446
|
+
const markerString = evalValue(match[0]);
|
|
447
|
+
const { fromEnv, toEnv, targetFileName } = JSON.parse(markerString.slice(31, -29));
|
|
448
|
+
const importPath = normalizeRelativePath(path.relative(path.join(config.environments[fromEnv].build.outDir, chunk.fileName, ".."), path.join(config.environments[toEnv].build.outDir, targetFileName)));
|
|
449
|
+
const replacement = `(import(${JSON.stringify(importPath)}))`;
|
|
450
|
+
const [start, end] = match.indices[0];
|
|
451
|
+
s.overwrite(start, end, replacement);
|
|
452
|
+
}
|
|
453
|
+
if (s.hasChanged()) return {
|
|
454
|
+
code: s.toString(),
|
|
455
|
+
map: s.generateMap({ hires: "boundary" })
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: "vite-rsc-load-module-dev-proxy",
|
|
461
|
+
configureServer(server) {
|
|
462
|
+
if (!rscPluginOptions.loadModuleDevProxy) return;
|
|
463
|
+
async function createHandler(url) {
|
|
464
|
+
const { environmentName, entryName } = Object.fromEntries(url.searchParams);
|
|
465
|
+
assert(environmentName);
|
|
466
|
+
const environment = server.environments[environmentName];
|
|
467
|
+
const source = getEntrySource(environment.config, entryName);
|
|
468
|
+
const resolvedEntry = await environment.pluginContainer.resolveId(source);
|
|
469
|
+
assert(resolvedEntry, `[vite-rsc] failed to resolve entry '${source}'`);
|
|
470
|
+
return createRpcServer(new Proxy({}, { get(_target, p, _receiver) {
|
|
471
|
+
if (typeof p !== "string" || p === "then") return;
|
|
472
|
+
return async (...args) => {
|
|
473
|
+
return (await environment.runner.import(resolvedEntry.id))[p](...args);
|
|
474
|
+
};
|
|
475
|
+
} }));
|
|
476
|
+
}
|
|
477
|
+
server.middlewares.use(async (req, res, next) => {
|
|
478
|
+
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
479
|
+
if (url.pathname === "/__vite_rsc_load_module_dev_proxy") {
|
|
480
|
+
try {
|
|
481
|
+
await toNodeHandler(await createHandler(url))(req, res);
|
|
482
|
+
} catch (e) {
|
|
483
|
+
next(e);
|
|
484
|
+
}
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
next();
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: "rsc:virtual:vite-rsc/rpc-client",
|
|
493
|
+
resolveId: {
|
|
494
|
+
filter: { id: exactRegex("virtual:vite-rsc/rpc-client") },
|
|
495
|
+
handler(source) {
|
|
496
|
+
if (source === "virtual:vite-rsc/rpc-client") return `\0${source}`;
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
load: {
|
|
500
|
+
filter: { id: exactRegex("\0virtual:vite-rsc/rpc-client") },
|
|
501
|
+
handler(id) {
|
|
502
|
+
if (id === "\0virtual:vite-rsc/rpc-client") {
|
|
503
|
+
const { server } = manager;
|
|
504
|
+
const origin = server.resolvedUrls?.local[0];
|
|
505
|
+
assert(origin, "[vite-rsc] no server for loadModuleDevProxy");
|
|
506
|
+
return `\
|
|
507
|
+
import * as __vite_rsc_rpc from "@vitejs/plugin-rsc/utils/rpc";
|
|
508
|
+
export function createRpcClient(params) {
|
|
509
|
+
const endpoint =
|
|
510
|
+
"${origin}" +
|
|
511
|
+
"__vite_rsc_load_module_dev_proxy?" +
|
|
512
|
+
new URLSearchParams(params);
|
|
513
|
+
return __vite_rsc_rpc.createRpcClient({ endpoint });
|
|
514
|
+
}
|
|
515
|
+
`;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
name: "rsc:virtual:vite-rsc/assets-manifest",
|
|
522
|
+
resolveId: {
|
|
523
|
+
filter: { id: exactRegex("virtual:vite-rsc/assets-manifest") },
|
|
524
|
+
handler(source) {
|
|
525
|
+
if (source === "virtual:vite-rsc/assets-manifest") {
|
|
526
|
+
if (this.environment.mode === "build") return {
|
|
527
|
+
id: source,
|
|
528
|
+
external: true
|
|
529
|
+
};
|
|
530
|
+
return `\0` + source;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
load: {
|
|
535
|
+
filter: { id: exactRegex("\0virtual:vite-rsc/assets-manifest") },
|
|
536
|
+
handler(id) {
|
|
537
|
+
if (id === "\0virtual:vite-rsc/assets-manifest") {
|
|
538
|
+
assert(this.environment.name !== "client");
|
|
539
|
+
assert(this.environment.mode === "dev");
|
|
540
|
+
const manifest = {
|
|
541
|
+
bootstrapScriptContent: `import(${serializeValueWithRuntime(assetsURL("@id/__x00__" + VIRTUAL_ENTRIES.browser, manager))})`,
|
|
542
|
+
clientReferenceDeps: {},
|
|
543
|
+
cssLinkPrecedence: rscPluginOptions.cssLinkPrecedence
|
|
544
|
+
};
|
|
545
|
+
return `export default ${JSON.stringify(manifest, null, 2)}`;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
generateBundle(_options, bundle) {
|
|
550
|
+
manager.bundles[this.environment.name] = bundle;
|
|
551
|
+
if (this.environment.name === "client") {
|
|
552
|
+
const rscBundle = manager.bundles["rsc"];
|
|
553
|
+
const assets = new Set(Object.values(rscBundle).flatMap((output) => output.type === "chunk" ? [...output.viteMetadata?.importedCss ?? [], ...output.viteMetadata?.importedAssets ?? []] : []));
|
|
554
|
+
for (const fileName of assets) {
|
|
555
|
+
const asset = rscBundle[fileName];
|
|
556
|
+
assert(asset?.type === "asset");
|
|
557
|
+
this.emitFile({
|
|
558
|
+
type: "asset",
|
|
559
|
+
fileName: asset.fileName,
|
|
560
|
+
source: asset.source
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
const serverResources = {};
|
|
564
|
+
const rscAssetDeps = collectAssetDeps(manager.bundles["rsc"]);
|
|
565
|
+
for (const [id, meta] of Object.entries(manager.serverResourcesMetaMap)) serverResources[meta.key] = assetsURLOfDeps({
|
|
566
|
+
js: [],
|
|
567
|
+
css: rscAssetDeps[id]?.deps.css ?? []
|
|
568
|
+
}, manager);
|
|
569
|
+
const assetDeps = collectAssetDeps(bundle);
|
|
570
|
+
let bootstrapScriptContent = "";
|
|
571
|
+
const clientReferenceDeps = {};
|
|
572
|
+
for (const meta of Object.values(manager.clientReferenceMetaMap)) {
|
|
573
|
+
const deps = assetDeps[meta.groupChunkId]?.deps ?? {
|
|
574
|
+
js: [],
|
|
575
|
+
css: []
|
|
576
|
+
};
|
|
577
|
+
clientReferenceDeps[meta.referenceKey] = assetsURLOfDeps(deps, manager);
|
|
578
|
+
}
|
|
579
|
+
if (!rscPluginOptions.customClientEntry) {
|
|
580
|
+
const entry = Object.values(assetDeps).find((v) => v.chunk.name === "index" && v.chunk.isEntry);
|
|
581
|
+
if (!entry) throw new Error(`[vite-rsc] Client build must have an entry chunk named "index". Use 'customClientEntry' option to disable this requirement.`);
|
|
582
|
+
const entryDeps = assetsURLOfDeps(entry.deps, manager);
|
|
583
|
+
for (const [key, deps] of Object.entries(clientReferenceDeps)) clientReferenceDeps[key] = mergeAssetDeps(deps, entryDeps);
|
|
584
|
+
const entryUrl = assetsURL(entry.chunk.fileName, manager);
|
|
585
|
+
if (typeof entryUrl === "string") bootstrapScriptContent = `import(${JSON.stringify(entryUrl)})`;
|
|
586
|
+
else bootstrapScriptContent = new RuntimeAsset(`"import(" + JSON.stringify(${entryUrl.runtime}) + ")"`);
|
|
587
|
+
}
|
|
588
|
+
manager.buildAssetsManifest = {
|
|
589
|
+
bootstrapScriptContent,
|
|
590
|
+
clientReferenceDeps,
|
|
591
|
+
serverResources,
|
|
592
|
+
cssLinkPrecedence: rscPluginOptions.cssLinkPrecedence
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
renderChunk(code, chunk) {
|
|
597
|
+
if (code.includes("virtual:vite-rsc/assets-manifest")) {
|
|
598
|
+
assert(this.environment.name !== "client");
|
|
599
|
+
const replacement = normalizeRelativePath(path.relative(path.join(chunk.fileName, ".."), BUILD_ASSETS_MANIFEST_NAME));
|
|
600
|
+
code = code.replaceAll("virtual:vite-rsc/assets-manifest", () => replacement);
|
|
601
|
+
return { code };
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
createVirtualPlugin("vite-rsc/bootstrap-script-content", function() {
|
|
606
|
+
assert(this.environment.name !== "client");
|
|
607
|
+
return `\
|
|
608
|
+
import assetsManifest from "virtual:vite-rsc/assets-manifest";
|
|
609
|
+
export default assetsManifest.bootstrapScriptContent;
|
|
610
|
+
`;
|
|
611
|
+
}),
|
|
612
|
+
{
|
|
613
|
+
name: "rsc:bootstrap-script-content",
|
|
614
|
+
transform: {
|
|
615
|
+
filter: { code: "loadBootstrapScriptContent" },
|
|
616
|
+
async handler(code) {
|
|
617
|
+
if (!code.includes("loadBootstrapScriptContent") || !/import\s*\.\s*meta\s*\.\s*viteRsc\s*\.\s*loadBootstrapScriptContent/.test(code)) return;
|
|
618
|
+
assert(!rscPluginOptions.customClientEntry, `[vite-rsc] 'import.meta.viteRsc.loadBootstrapScriptContent' cannot be used with 'customClientEntry' option`);
|
|
619
|
+
assert(this.environment.name !== "client");
|
|
620
|
+
const output = new MagicString(code);
|
|
621
|
+
for (const match of stripLiteral(code).matchAll(/import\s*\.\s*meta\s*\.\s*viteRsc\s*\.\s*loadBootstrapScriptContent\(([\s\S]*?)\)/dg)) {
|
|
622
|
+
const [argStart, argEnd] = match.indices[1];
|
|
623
|
+
const argCode = code.slice(argStart, argEnd).trim();
|
|
624
|
+
assert(evalValue(argCode), `[vite-rsc] expected 'loadBootstrapScriptContent("index")' but got ${argCode}`);
|
|
625
|
+
let replacement = `Promise.resolve(__vite_rsc_assets_manifest.bootstrapScriptContent)`;
|
|
626
|
+
const [start, end] = match.indices[0];
|
|
627
|
+
output.overwrite(start, end, replacement);
|
|
628
|
+
}
|
|
629
|
+
if (output.hasChanged()) {
|
|
630
|
+
if (!code.includes("__vite_rsc_assets_manifest")) output.prepend(`import __vite_rsc_assets_manifest from "virtual:vite-rsc/assets-manifest";`);
|
|
631
|
+
return {
|
|
632
|
+
code: output.toString(),
|
|
633
|
+
map: output.generateMap({ hires: "boundary" })
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
createVirtualPlugin(VIRTUAL_ENTRIES.browser.slice(8), async function() {
|
|
640
|
+
assert(this.environment.mode === "dev");
|
|
641
|
+
let code = "";
|
|
642
|
+
if (await this.resolve("/@react-refresh")) code += `
|
|
643
|
+
import RefreshRuntime from "/@react-refresh";
|
|
644
|
+
RefreshRuntime.injectIntoGlobalHook(window);
|
|
645
|
+
window.$RefreshReg$ = () => {};
|
|
646
|
+
window.$RefreshSig$ = () => (type) => type;
|
|
647
|
+
window.__vite_plugin_react_preamble_installed__ = true;
|
|
648
|
+
`;
|
|
649
|
+
const source = getEntrySource(this.environment.config, "index");
|
|
650
|
+
const resolvedEntry = await this.resolve(source);
|
|
651
|
+
assert(resolvedEntry, `[vite-rsc] failed to resolve entry '${source}'`);
|
|
652
|
+
code += `await import(${JSON.stringify(resolvedEntry.id)});`;
|
|
653
|
+
code += `
|
|
654
|
+
const ssrCss = document.querySelectorAll("link[rel='stylesheet']");
|
|
655
|
+
import.meta.hot.on("vite:beforeUpdate", () => {
|
|
656
|
+
ssrCss.forEach(node => {
|
|
657
|
+
if (node.dataset.precedence?.startsWith("vite-rsc/client-references")) {
|
|
658
|
+
node.remove();
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
});
|
|
662
|
+
`;
|
|
663
|
+
code += `
|
|
664
|
+
import.meta.hot.on("rsc:update", () => {
|
|
665
|
+
document.querySelectorAll("vite-error-overlay").forEach((n) => n.close())
|
|
666
|
+
});
|
|
667
|
+
`;
|
|
668
|
+
code += `import.meta.hot.on("rsc:prune", ${(e) => {
|
|
669
|
+
document.querySelectorAll("link[rel='stylesheet']").forEach((node) => {
|
|
670
|
+
if (e.paths.includes(node.dataset.rscCssHref)) node.remove();
|
|
671
|
+
});
|
|
672
|
+
}});`;
|
|
673
|
+
return code;
|
|
674
|
+
}),
|
|
675
|
+
...vitePluginRscMinimal(rscPluginOptions, manager),
|
|
676
|
+
...vitePluginImportEnvironment(manager),
|
|
677
|
+
...vitePluginFindSourceMapURL(),
|
|
678
|
+
...vitePluginRscCss(rscPluginOptions, manager),
|
|
679
|
+
{
|
|
680
|
+
...validateImportPlugin(),
|
|
681
|
+
apply: () => rscPluginOptions.validateImports !== false
|
|
682
|
+
},
|
|
683
|
+
scanBuildStripPlugin({ manager }),
|
|
684
|
+
...cjsModuleRunnerPlugin(),
|
|
685
|
+
...globalAsyncLocalStoragePlugin()
|
|
686
|
+
];
|
|
687
|
+
}
|
|
688
|
+
function globalAsyncLocalStoragePlugin() {
|
|
689
|
+
return [{
|
|
690
|
+
name: "rsc:inject-async-local-storage",
|
|
691
|
+
transform: {
|
|
692
|
+
filter: { code: "typeof AsyncLocalStorage" },
|
|
693
|
+
handler(code) {
|
|
694
|
+
if ((this.environment.name === "ssr" || this.environment.name === "rsc") && code.includes("typeof AsyncLocalStorage") && code.includes("new AsyncLocalStorage()") && !code.includes("__viteRscAsyncHooks")) return (this.environment.mode === "build" && !isRolldownVite ? `const __viteRscAsyncHooks = require("node:async_hooks");` : `import * as __viteRscAsyncHooks from "node:async_hooks";`) + `globalThis.AsyncLocalStorage = __viteRscAsyncHooks.AsyncLocalStorage;` + code;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}];
|
|
698
|
+
}
|
|
699
|
+
function vitePluginUseClient(useClientPluginOptions, manager) {
|
|
700
|
+
const packageSources = /* @__PURE__ */ new Map();
|
|
701
|
+
const bareImportRE = /^(?![a-zA-Z]:)[\w@](?!.*:\/\/)/;
|
|
702
|
+
const serverEnvironmentName = useClientPluginOptions.environment?.rsc ?? "rsc";
|
|
703
|
+
const browserEnvironmentName = useClientPluginOptions.environment?.browser ?? "client";
|
|
704
|
+
let optimizerMetadata;
|
|
705
|
+
function warnInoncistentClientOptimization(ctx, id) {
|
|
706
|
+
id = normalizePath(path.relative(process.cwd(), id));
|
|
707
|
+
if (optimizerMetadata?.ids.includes(id)) ctx.warn("client component dependency is inconsistently optimized. It's recommended to add the dependency to 'optimizeDeps.exclude'.");
|
|
708
|
+
}
|
|
709
|
+
const debug = createDebug("vite-rsc:use-client");
|
|
710
|
+
return [
|
|
711
|
+
{
|
|
712
|
+
name: "rsc:use-client",
|
|
713
|
+
transform: { async handler(code, id) {
|
|
714
|
+
if (this.environment.name !== serverEnvironmentName) return;
|
|
715
|
+
if (!code.includes("use client")) {
|
|
716
|
+
delete manager.clientReferenceMetaMap[id];
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
const ast = await parseAstAsync(code);
|
|
720
|
+
if (!hasDirective(ast.body, "use client")) {
|
|
721
|
+
delete manager.clientReferenceMetaMap[id];
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
if (code.includes("use server")) {
|
|
725
|
+
const directives = findDirectives(ast, "use server");
|
|
726
|
+
if (directives.length > 0) this.error(`'use server' directive is not allowed inside 'use client'`, directives[0]?.start);
|
|
727
|
+
}
|
|
728
|
+
let importId;
|
|
729
|
+
let referenceKey;
|
|
730
|
+
const packageSource = packageSources.get(id);
|
|
731
|
+
if (!packageSource && this.environment.mode === "dev" && id.includes("/node_modules/")) {
|
|
732
|
+
debug(`internal client reference created through a package imported in '${this.environment.name}' environment: ${id}`);
|
|
733
|
+
id = cleanUrl(id);
|
|
734
|
+
warnInoncistentClientOptimization(this, id);
|
|
735
|
+
importId = `/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/${encodeURIComponent(id)}`;
|
|
736
|
+
referenceKey = importId;
|
|
737
|
+
} else if (packageSource) if (this.environment.mode === "dev") {
|
|
738
|
+
importId = `/@id/__x00__virtual:vite-rsc/client-package-proxy/${packageSource}`;
|
|
739
|
+
referenceKey = importId;
|
|
740
|
+
} else {
|
|
741
|
+
importId = packageSource;
|
|
742
|
+
referenceKey = hashString(packageSource);
|
|
743
|
+
}
|
|
744
|
+
else if (this.environment.mode === "dev") {
|
|
745
|
+
importId = normalizeViteImportAnalysisUrl(manager.server.environments[browserEnvironmentName], id);
|
|
746
|
+
referenceKey = importId;
|
|
747
|
+
} else {
|
|
748
|
+
importId = id;
|
|
749
|
+
referenceKey = hashString(manager.toRelativeId(id));
|
|
750
|
+
}
|
|
751
|
+
const result = withRollupError(this, transformDirectiveProxyExport)(ast, {
|
|
752
|
+
directive: "use client",
|
|
753
|
+
code,
|
|
754
|
+
keep: !!useClientPluginOptions.keepUseCientProxy,
|
|
755
|
+
runtime: (name, meta) => {
|
|
756
|
+
let proxyValue = `() => { throw new Error("Unexpectedly client reference export '" + ` + JSON.stringify(name) + ` + "' is called on server") }`;
|
|
757
|
+
if (meta?.value) proxyValue = `(${meta.value})`;
|
|
758
|
+
return `$$ReactServer.registerClientReference( ${proxyValue}, ${JSON.stringify(referenceKey)}, ${JSON.stringify(name)})`;
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
if (!result) return;
|
|
762
|
+
const { output, exportNames } = result;
|
|
763
|
+
manager.clientReferenceMetaMap[id] = {
|
|
764
|
+
importId,
|
|
765
|
+
referenceKey,
|
|
766
|
+
packageSource,
|
|
767
|
+
exportNames,
|
|
768
|
+
renderedExports: []
|
|
769
|
+
};
|
|
770
|
+
const importSource = resolvePackage(`${PKG_NAME}/react/rsc`);
|
|
771
|
+
output.prepend(`import * as $$ReactServer from "${importSource}";\n`);
|
|
772
|
+
return {
|
|
773
|
+
code: output.toString(),
|
|
774
|
+
map: { mappings: "" }
|
|
775
|
+
};
|
|
776
|
+
} }
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
name: "rsc:use-client/build-references",
|
|
780
|
+
resolveId: {
|
|
781
|
+
filter: { id: prefixRegex("virtual:vite-rsc/client-references") },
|
|
782
|
+
handler(source) {
|
|
783
|
+
if (source.startsWith("virtual:vite-rsc/client-references")) return "\0" + source;
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
load: {
|
|
787
|
+
filter: { id: prefixRegex("\0virtual:vite-rsc/client-references") },
|
|
788
|
+
handler(id) {
|
|
789
|
+
if (id === "\0virtual:vite-rsc/client-references") {
|
|
790
|
+
if (this.environment.mode === "dev") return {
|
|
791
|
+
code: `export default {}`,
|
|
792
|
+
map: null
|
|
793
|
+
};
|
|
794
|
+
if (manager.isScanBuild) {
|
|
795
|
+
let code = ``;
|
|
796
|
+
for (const meta of Object.values(manager.clientReferenceMetaMap)) code += `import ${JSON.stringify(withResolvedIdProxy(meta.importId))};\n`;
|
|
797
|
+
return {
|
|
798
|
+
code,
|
|
799
|
+
map: null
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
let code = "";
|
|
803
|
+
manager.clientReferenceGroups = {};
|
|
804
|
+
for (const meta of Object.values(manager.clientReferenceMetaMap)) {
|
|
805
|
+
if (!meta.serverChunk) continue;
|
|
806
|
+
let name = useClientPluginOptions.clientChunks?.({
|
|
807
|
+
id: meta.importId,
|
|
808
|
+
normalizedId: manager.toRelativeId(meta.importId),
|
|
809
|
+
serverChunk: meta.serverChunk
|
|
810
|
+
}) ?? meta.serverChunk;
|
|
811
|
+
name = cleanUrl(name.replaceAll("..", "__"));
|
|
812
|
+
(manager.clientReferenceGroups[name] ??= []).push(meta);
|
|
813
|
+
meta.groupChunkId = `\0virtual:vite-rsc/client-references/group/${name}`;
|
|
814
|
+
}
|
|
815
|
+
debug("client-reference-groups", manager.clientReferenceGroups);
|
|
816
|
+
for (const [name, metas] of Object.entries(manager.clientReferenceGroups)) {
|
|
817
|
+
const groupVirtual = `virtual:vite-rsc/client-references/group/${name}`;
|
|
818
|
+
for (const meta of metas) code += `\
|
|
819
|
+
${JSON.stringify(meta.referenceKey)}: async () => {
|
|
820
|
+
const m = await import(${JSON.stringify(groupVirtual)});
|
|
821
|
+
return m.export_${meta.referenceKey};
|
|
822
|
+
},
|
|
823
|
+
`;
|
|
824
|
+
}
|
|
825
|
+
code = `export default {${code}};\n`;
|
|
826
|
+
return {
|
|
827
|
+
code,
|
|
828
|
+
map: null
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
if (id.startsWith("\0virtual:vite-rsc/client-references/group/")) {
|
|
832
|
+
const name = id.slice(42);
|
|
833
|
+
const metas = manager.clientReferenceGroups[name];
|
|
834
|
+
assert(metas, `unknown client reference group: ${name}`);
|
|
835
|
+
let code = ``;
|
|
836
|
+
for (const meta of metas) {
|
|
837
|
+
const exports = meta.renderedExports.map((name) => `${name}: import_${meta.referenceKey}.${name},\n`).sort().join("");
|
|
838
|
+
code += `
|
|
839
|
+
import * as import_${meta.referenceKey} from ${JSON.stringify(withResolvedIdProxy(meta.importId))};
|
|
840
|
+
export const export_${meta.referenceKey} = {${exports}};
|
|
841
|
+
`;
|
|
842
|
+
}
|
|
843
|
+
return {
|
|
844
|
+
code,
|
|
845
|
+
map: null
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
name: "rsc:virtual-client-in-server-package",
|
|
853
|
+
load: {
|
|
854
|
+
filter: { id: prefixRegex("\0virtual:vite-rsc/client-in-server-package-proxy/") },
|
|
855
|
+
async handler(id) {
|
|
856
|
+
if (id.startsWith("\0virtual:vite-rsc/client-in-server-package-proxy/")) {
|
|
857
|
+
assert.equal(this.environment.mode, "dev");
|
|
858
|
+
assert(this.environment.name !== serverEnvironmentName);
|
|
859
|
+
id = decodeURIComponent(id.slice(49));
|
|
860
|
+
return `
|
|
861
|
+
export * from ${JSON.stringify(id)};
|
|
862
|
+
import * as __all__ from ${JSON.stringify(id)};
|
|
863
|
+
export default __all__.default;
|
|
864
|
+
`;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
name: "rsc:virtual-client-package",
|
|
871
|
+
resolveId: {
|
|
872
|
+
order: "pre",
|
|
873
|
+
async handler(source, importer, options) {
|
|
874
|
+
if (this.environment.name === serverEnvironmentName && bareImportRE.test(source) && !(source === "client-only" || source === "server-only")) {
|
|
875
|
+
const resolved = await this.resolve(source, importer, options);
|
|
876
|
+
if (resolved && resolved.id.includes("/node_modules/")) {
|
|
877
|
+
packageSources.set(resolved.id, source);
|
|
878
|
+
return resolved;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
load: {
|
|
884
|
+
filter: { id: prefixRegex("\0virtual:vite-rsc/client-package-proxy/") },
|
|
885
|
+
async handler(id) {
|
|
886
|
+
if (id.startsWith("\0virtual:vite-rsc/client-package-proxy/")) {
|
|
887
|
+
assert(this.environment.mode === "dev");
|
|
888
|
+
const source = id.slice(39);
|
|
889
|
+
return `export {${Object.values(manager.clientReferenceMetaMap).find((v) => v.packageSource === source).exportNames.join(",")}} from ${JSON.stringify(source)};\n`;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
generateBundle(_options, bundle) {
|
|
894
|
+
if (manager.isScanBuild) return;
|
|
895
|
+
if (this.environment.name !== serverEnvironmentName) return;
|
|
896
|
+
for (const chunk of Object.values(bundle)) if (chunk.type === "chunk") {
|
|
897
|
+
const metas = [];
|
|
898
|
+
for (const id of chunk.moduleIds) {
|
|
899
|
+
const meta = manager.clientReferenceMetaMap[id];
|
|
900
|
+
if (meta) metas.push([id, meta]);
|
|
901
|
+
}
|
|
902
|
+
if (metas.length > 0) {
|
|
903
|
+
let serverChunk;
|
|
904
|
+
if (chunk.facadeModuleId) serverChunk = "facade:" + manager.toRelativeId(chunk.facadeModuleId);
|
|
905
|
+
else serverChunk = "shared:" + manager.toRelativeId(metas.map(([id]) => id).sort()[0]);
|
|
906
|
+
for (const [id, meta] of metas) {
|
|
907
|
+
const mod = chunk.modules[id];
|
|
908
|
+
assert(mod);
|
|
909
|
+
meta.renderedExports = mod.renderedExports;
|
|
910
|
+
meta.serverChunk = serverChunk;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
...customOptimizerMetadataPlugin({ setMetadata: (metadata) => {
|
|
917
|
+
optimizerMetadata = metadata;
|
|
918
|
+
} })
|
|
919
|
+
];
|
|
920
|
+
}
|
|
921
|
+
function customOptimizerMetadataPlugin({ setMetadata }) {
|
|
922
|
+
const MEATADATA_FILE = "_metadata-rsc.json";
|
|
923
|
+
function optimizerPluginEsbuild() {
|
|
924
|
+
return {
|
|
925
|
+
name: "vite-rsc-metafile",
|
|
926
|
+
setup(build) {
|
|
927
|
+
build.onEnd((result) => {
|
|
928
|
+
if (!result.metafile?.inputs || !build.initialOptions.outdir) return;
|
|
929
|
+
const metadata = { ids: Object.keys(result.metafile.inputs) };
|
|
930
|
+
setMetadata(metadata);
|
|
931
|
+
fs.writeFileSync(path.join(build.initialOptions.outdir, MEATADATA_FILE), JSON.stringify(metadata, null, 2));
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
function optimizerPluginRolldown() {
|
|
937
|
+
return {
|
|
938
|
+
name: "vite-rsc-metafile",
|
|
939
|
+
writeBundle(options) {
|
|
940
|
+
assert(options.dir);
|
|
941
|
+
const metadata = { ids: [...this.getModuleIds()].map((id) => path.relative(process.cwd(), id)) };
|
|
942
|
+
setMetadata(metadata);
|
|
943
|
+
fs.writeFileSync(path.join(options.dir, MEATADATA_FILE), JSON.stringify(metadata, null, 2));
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
return [{
|
|
948
|
+
name: "rsc:use-client:optimizer-metadata",
|
|
949
|
+
apply: "serve",
|
|
950
|
+
config() {
|
|
951
|
+
return { environments: { client: { optimizeDeps: "rolldownVersion" in vite ? { rolldownOptions: { plugins: [optimizerPluginRolldown()] } } : { esbuildOptions: { plugins: [optimizerPluginEsbuild()] } } } } };
|
|
952
|
+
},
|
|
953
|
+
configResolved(config) {
|
|
954
|
+
const file = path.join(config.cacheDir, "deps", MEATADATA_FILE);
|
|
955
|
+
if (fs.existsSync(file)) try {
|
|
956
|
+
setMetadata(JSON.parse(fs.readFileSync(file, "utf-8")));
|
|
957
|
+
} catch (e) {
|
|
958
|
+
this.warn(`failed to load '${file}'`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}];
|
|
962
|
+
}
|
|
963
|
+
function vitePluginDefineEncryptionKey(useServerPluginOptions) {
|
|
964
|
+
let defineEncryptionKey;
|
|
965
|
+
let emitEncryptionKey = false;
|
|
966
|
+
const KEY_PLACEHOLDER = "__vite_rsc_define_encryption_key";
|
|
967
|
+
const KEY_FILE = "__vite_rsc_encryption_key.js";
|
|
968
|
+
const serverEnvironmentName = useServerPluginOptions.environment?.rsc ?? "rsc";
|
|
969
|
+
return [{
|
|
970
|
+
name: "rsc:encryption-key",
|
|
971
|
+
async configEnvironment(name, _config, env) {
|
|
972
|
+
if (name === serverEnvironmentName && !env.isPreview) defineEncryptionKey = useServerPluginOptions.defineEncryptionKey ?? JSON.stringify(toBase64(await generateEncryptionKey()));
|
|
973
|
+
},
|
|
974
|
+
resolveId: {
|
|
975
|
+
filter: { id: exactRegex("virtual:vite-rsc/encryption-key") },
|
|
976
|
+
handler(source) {
|
|
977
|
+
if (source === "virtual:vite-rsc/encryption-key") return {
|
|
978
|
+
id: "\0" + source,
|
|
979
|
+
moduleSideEffects: false
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
},
|
|
983
|
+
load: {
|
|
984
|
+
filter: { id: exactRegex("\0virtual:vite-rsc/encryption-key") },
|
|
985
|
+
handler(id) {
|
|
986
|
+
if (id === "\0virtual:vite-rsc/encryption-key") {
|
|
987
|
+
if (this.environment.mode === "build") return `export default () => ${KEY_PLACEHOLDER}`;
|
|
988
|
+
return `export default () => (${defineEncryptionKey})`;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
renderChunk(code, chunk) {
|
|
993
|
+
if (code.includes(KEY_PLACEHOLDER)) {
|
|
994
|
+
assert.equal(this.environment.name, serverEnvironmentName);
|
|
995
|
+
emitEncryptionKey = true;
|
|
996
|
+
const normalizedPath = normalizeRelativePath(path.relative(path.join(chunk.fileName, ".."), KEY_FILE));
|
|
997
|
+
const replacement = `import(${JSON.stringify(normalizedPath)}).then(__m => __m.default)`;
|
|
998
|
+
code = code.replaceAll(KEY_PLACEHOLDER, () => replacement);
|
|
999
|
+
return { code };
|
|
1000
|
+
}
|
|
1001
|
+
},
|
|
1002
|
+
writeBundle() {
|
|
1003
|
+
if (this.environment.name === serverEnvironmentName && emitEncryptionKey) fs.writeFileSync(path.join(this.environment.config.build.outDir, KEY_FILE), `export default ${defineEncryptionKey};\n`);
|
|
1004
|
+
}
|
|
1005
|
+
}];
|
|
1006
|
+
}
|
|
1007
|
+
function vitePluginUseServer(useServerPluginOptions, manager) {
|
|
1008
|
+
const serverEnvironmentName = useServerPluginOptions.environment?.rsc ?? "rsc";
|
|
1009
|
+
const browserEnvironmentName = useServerPluginOptions.environment?.browser ?? "client";
|
|
1010
|
+
const debug = createDebug("vite-rsc:use-server");
|
|
1011
|
+
return [{
|
|
1012
|
+
name: "rsc:use-server",
|
|
1013
|
+
transform: { async handler(code, id) {
|
|
1014
|
+
if (!code.includes("use server")) {
|
|
1015
|
+
delete manager.serverReferenceMetaMap[id];
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
const ast = await parseAstAsync(code);
|
|
1019
|
+
let normalizedId_;
|
|
1020
|
+
const getNormalizedId = () => {
|
|
1021
|
+
if (!normalizedId_) {
|
|
1022
|
+
if (this.environment.mode === "dev" && id.includes("/node_modules/")) {
|
|
1023
|
+
debug(`internal server reference created through a package imported in ${this.environment.name} environment: ${id}`);
|
|
1024
|
+
id = cleanUrl(id);
|
|
1025
|
+
}
|
|
1026
|
+
if (manager.config.command === "build") normalizedId_ = hashString(manager.toRelativeId(id));
|
|
1027
|
+
else normalizedId_ = normalizeViteImportAnalysisUrl(manager.server.environments[serverEnvironmentName], id);
|
|
1028
|
+
}
|
|
1029
|
+
return normalizedId_;
|
|
1030
|
+
};
|
|
1031
|
+
if (this.environment.name === serverEnvironmentName) {
|
|
1032
|
+
const transformServerActionServer_ = withRollupError(this, transformServerActionServer);
|
|
1033
|
+
const enableEncryption = useServerPluginOptions.enableActionEncryption ?? true;
|
|
1034
|
+
const result = transformServerActionServer_(code, ast, {
|
|
1035
|
+
runtime: (value, name) => `$$ReactServer.registerServerReference(${value}, ${JSON.stringify(getNormalizedId())}, ${JSON.stringify(name)})`,
|
|
1036
|
+
rejectNonAsyncFunction: true,
|
|
1037
|
+
encode: enableEncryption ? (value) => `__vite_rsc_encryption_runtime.encryptActionBoundArgs(${value})` : void 0,
|
|
1038
|
+
decode: enableEncryption ? (value) => `await __vite_rsc_encryption_runtime.decryptActionBoundArgs(${value})` : void 0
|
|
1039
|
+
});
|
|
1040
|
+
const output = result.output;
|
|
1041
|
+
if (!result || !output.hasChanged()) {
|
|
1042
|
+
delete manager.serverReferenceMetaMap[id];
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
manager.serverReferenceMetaMap[id] = {
|
|
1046
|
+
importId: id,
|
|
1047
|
+
referenceKey: getNormalizedId(),
|
|
1048
|
+
exportNames: "names" in result ? result.names : result.exportNames
|
|
1049
|
+
};
|
|
1050
|
+
const importSource = resolvePackage(`${PKG_NAME}/react/rsc`);
|
|
1051
|
+
output.prepend(`import * as $$ReactServer from "${importSource}";\n`);
|
|
1052
|
+
if (enableEncryption) {
|
|
1053
|
+
const importSource = resolvePackage(`${PKG_NAME}/utils/encryption-runtime`);
|
|
1054
|
+
output.prepend(`import * as __vite_rsc_encryption_runtime from ${JSON.stringify(importSource)};\n`);
|
|
1055
|
+
}
|
|
1056
|
+
return {
|
|
1057
|
+
code: output.toString(),
|
|
1058
|
+
map: output.generateMap({ hires: "boundary" })
|
|
1059
|
+
};
|
|
1060
|
+
} else {
|
|
1061
|
+
if (!hasDirective(ast.body, "use server")) {
|
|
1062
|
+
delete manager.serverReferenceMetaMap[id];
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
const result = withRollupError(this, transformDirectiveProxyExport)(ast, {
|
|
1066
|
+
code,
|
|
1067
|
+
runtime: (name) => `$$ReactClient.createServerReference(${JSON.stringify(getNormalizedId() + "#" + name)},$$ReactClient.callServer, undefined, ` + (this.environment.mode === "dev" ? `$$ReactClient.findSourceMapURL,` : "undefined,") + `${JSON.stringify(name)})`,
|
|
1068
|
+
directive: "use server",
|
|
1069
|
+
rejectNonAsyncFunction: true
|
|
1070
|
+
});
|
|
1071
|
+
if (!result) return;
|
|
1072
|
+
const output = result?.output;
|
|
1073
|
+
if (!output?.hasChanged()) return;
|
|
1074
|
+
manager.serverReferenceMetaMap[id] = {
|
|
1075
|
+
importId: id,
|
|
1076
|
+
referenceKey: getNormalizedId(),
|
|
1077
|
+
exportNames: result.exportNames
|
|
1078
|
+
};
|
|
1079
|
+
const importSource = resolvePackage(`${PKG_NAME}/react/${this.environment.name === browserEnvironmentName ? "browser" : "ssr"}`);
|
|
1080
|
+
output.prepend(`import * as $$ReactClient from "${importSource}";\n`);
|
|
1081
|
+
return {
|
|
1082
|
+
code: output.toString(),
|
|
1083
|
+
map: output.generateMap({ hires: "boundary" })
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
} }
|
|
1087
|
+
}, createVirtualPlugin("vite-rsc/server-references", function() {
|
|
1088
|
+
if (this.environment.mode === "dev") return {
|
|
1089
|
+
code: `export {}`,
|
|
1090
|
+
map: null
|
|
1091
|
+
};
|
|
1092
|
+
let code = "";
|
|
1093
|
+
for (const meta of Object.values(manager.serverReferenceMetaMap)) {
|
|
1094
|
+
const key = JSON.stringify(meta.referenceKey);
|
|
1095
|
+
const id = JSON.stringify(meta.importId);
|
|
1096
|
+
const exports = meta.exportNames.map((name) => name === "default" ? "default: _default" : name).sort();
|
|
1097
|
+
code += `
|
|
1098
|
+
${key}: async () => {
|
|
1099
|
+
const {${exports}} = await import(${id});
|
|
1100
|
+
return {${exports}};
|
|
1101
|
+
},
|
|
1102
|
+
`;
|
|
1103
|
+
}
|
|
1104
|
+
code = `export default {${code}};\n`;
|
|
1105
|
+
return {
|
|
1106
|
+
code,
|
|
1107
|
+
map: null
|
|
1108
|
+
};
|
|
1109
|
+
})];
|
|
1110
|
+
}
|
|
1111
|
+
var RuntimeAsset = class {
|
|
1112
|
+
runtime;
|
|
1113
|
+
constructor(value) {
|
|
1114
|
+
this.runtime = value;
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
function serializeValueWithRuntime(value) {
|
|
1118
|
+
const replacements = [];
|
|
1119
|
+
let result = JSON.stringify(value, (_key, value) => {
|
|
1120
|
+
if (value instanceof RuntimeAsset) {
|
|
1121
|
+
const placeholder = `__runtime_placeholder_${replacements.length}__`;
|
|
1122
|
+
replacements.push([placeholder, value.runtime]);
|
|
1123
|
+
return placeholder;
|
|
1124
|
+
}
|
|
1125
|
+
return value;
|
|
1126
|
+
}, 2);
|
|
1127
|
+
for (const [placeholder, runtime] of replacements) result = result.replace(`"${placeholder}"`, runtime);
|
|
1128
|
+
return result;
|
|
1129
|
+
}
|
|
1130
|
+
function assetsURL(url, manager) {
|
|
1131
|
+
const { config } = manager;
|
|
1132
|
+
if (config.command === "build" && typeof config.experimental?.renderBuiltUrl === "function") {
|
|
1133
|
+
const result = config.experimental.renderBuiltUrl(url, {
|
|
1134
|
+
type: "asset",
|
|
1135
|
+
hostType: "js",
|
|
1136
|
+
ssr: true,
|
|
1137
|
+
hostId: ""
|
|
1138
|
+
});
|
|
1139
|
+
if (typeof result === "object") {
|
|
1140
|
+
if (result.runtime) return new RuntimeAsset(result.runtime);
|
|
1141
|
+
assert(!result.relative, "\"result.relative\" not supported on renderBuiltUrl() for RSC");
|
|
1142
|
+
} else if (result) return result;
|
|
1143
|
+
}
|
|
1144
|
+
return config.base + url;
|
|
1145
|
+
}
|
|
1146
|
+
function assetsURLOfDeps(deps, manager) {
|
|
1147
|
+
return {
|
|
1148
|
+
js: deps.js.map((href) => {
|
|
1149
|
+
assert(typeof href === "string");
|
|
1150
|
+
return assetsURL(href, manager);
|
|
1151
|
+
}),
|
|
1152
|
+
css: deps.css.map((href) => {
|
|
1153
|
+
assert(typeof href === "string");
|
|
1154
|
+
return assetsURL(href, manager);
|
|
1155
|
+
})
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
function mergeAssetDeps(a, b) {
|
|
1159
|
+
return {
|
|
1160
|
+
js: [...new Set([...a.js, ...b.js])],
|
|
1161
|
+
css: [...new Set([...a.css, ...b.css])]
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
function collectAssetDeps(bundle) {
|
|
1165
|
+
const chunkToDeps = /* @__PURE__ */ new Map();
|
|
1166
|
+
for (const chunk of Object.values(bundle)) if (chunk.type === "chunk") chunkToDeps.set(chunk, collectAssetDepsInner(chunk.fileName, bundle));
|
|
1167
|
+
const idToDeps = {};
|
|
1168
|
+
for (const [chunk, deps] of chunkToDeps.entries()) for (const id of chunk.moduleIds) idToDeps[id] = {
|
|
1169
|
+
chunk,
|
|
1170
|
+
deps
|
|
1171
|
+
};
|
|
1172
|
+
return idToDeps;
|
|
1173
|
+
}
|
|
1174
|
+
function collectAssetDepsInner(fileName, bundle) {
|
|
1175
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1176
|
+
const css = [];
|
|
1177
|
+
function recurse(k) {
|
|
1178
|
+
if (visited.has(k)) return;
|
|
1179
|
+
visited.add(k);
|
|
1180
|
+
const v = bundle[k];
|
|
1181
|
+
assert(v, `Not found '${k}' in the bundle`);
|
|
1182
|
+
if (v.type === "chunk") {
|
|
1183
|
+
css.push(...v.viteMetadata?.importedCss ?? []);
|
|
1184
|
+
for (const k2 of v.imports) if (k2 in bundle) recurse(k2);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
recurse(fileName);
|
|
1188
|
+
return {
|
|
1189
|
+
js: [...visited],
|
|
1190
|
+
css: [...new Set(css)]
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
function vitePluginRscCss(rscCssOptions = {}, manager) {
|
|
1194
|
+
function hasSpecialCssQuery(id) {
|
|
1195
|
+
return /[?&](url|inline|raw)(\b|=|&|$)/.test(id);
|
|
1196
|
+
}
|
|
1197
|
+
function collectCss(environment, entryId) {
|
|
1198
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1199
|
+
const cssIds = /* @__PURE__ */ new Set();
|
|
1200
|
+
const visitedFiles = /* @__PURE__ */ new Set();
|
|
1201
|
+
function recurse(id) {
|
|
1202
|
+
if (visited.has(id)) return;
|
|
1203
|
+
visited.add(id);
|
|
1204
|
+
const mod = environment.moduleGraph.getModuleById(id);
|
|
1205
|
+
if (mod?.file) visitedFiles.add(mod.file);
|
|
1206
|
+
for (const next of mod?.importedModules ?? []) if (next.id) if (isCSSRequest(next.id)) {
|
|
1207
|
+
if (hasSpecialCssQuery(next.id)) continue;
|
|
1208
|
+
cssIds.add(next.id);
|
|
1209
|
+
} else recurse(next.id);
|
|
1210
|
+
}
|
|
1211
|
+
recurse(entryId);
|
|
1212
|
+
const hrefs = [...cssIds].map((id) => normalizeViteImportAnalysisUrl(environment, id));
|
|
1213
|
+
return {
|
|
1214
|
+
ids: [...cssIds],
|
|
1215
|
+
hrefs,
|
|
1216
|
+
visitedFiles: [...visitedFiles]
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
function getRscCssTransformFilter({ id, code }) {
|
|
1220
|
+
const { filename, query } = parseIdQuery(id);
|
|
1221
|
+
if ("vite-rsc-css-export" in query) {
|
|
1222
|
+
const value = query["vite-rsc-css-export"];
|
|
1223
|
+
if (value) {
|
|
1224
|
+
const names = value.split(",");
|
|
1225
|
+
return (name) => names.includes(name);
|
|
1226
|
+
}
|
|
1227
|
+
return (name) => /^[A-Z]/.test(name);
|
|
1228
|
+
}
|
|
1229
|
+
const options = rscCssOptions?.rscCssTransform;
|
|
1230
|
+
if (options === false) return false;
|
|
1231
|
+
if (options?.filter && !options.filter(filename)) return false;
|
|
1232
|
+
if (!/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)\b/.test(code) || !/\.[tj]sx?$/.test(filename)) return false;
|
|
1233
|
+
if (!esModuleLexer.parse(code)[0].some((i) => i.t === 1 && i.n && isCSSRequest(i.n))) return false;
|
|
1234
|
+
return (_name, meta) => !!(meta.isFunction && meta.declName && /^[A-Z]/.test(meta.declName) || meta.defaultExportIdentifierName && /^[A-Z]/.test(meta.defaultExportIdentifierName));
|
|
1235
|
+
}
|
|
1236
|
+
return [
|
|
1237
|
+
{
|
|
1238
|
+
name: "rsc:rsc-css-export-transform",
|
|
1239
|
+
transform: { async handler(code, id) {
|
|
1240
|
+
if (this.environment.name !== "rsc") return;
|
|
1241
|
+
const filter = getRscCssTransformFilter({
|
|
1242
|
+
id,
|
|
1243
|
+
code
|
|
1244
|
+
});
|
|
1245
|
+
if (!filter) return;
|
|
1246
|
+
const result = await transformRscCssExport({
|
|
1247
|
+
ast: await parseAstAsync(code),
|
|
1248
|
+
code,
|
|
1249
|
+
filter
|
|
1250
|
+
});
|
|
1251
|
+
if (result) return {
|
|
1252
|
+
code: result.output.toString(),
|
|
1253
|
+
map: result.output.generateMap({ hires: "boundary" })
|
|
1254
|
+
};
|
|
1255
|
+
} }
|
|
1256
|
+
},
|
|
1257
|
+
{
|
|
1258
|
+
name: "rsc:rsc-css-self-accept",
|
|
1259
|
+
apply: "serve",
|
|
1260
|
+
transform: {
|
|
1261
|
+
order: "post",
|
|
1262
|
+
filter: { id: /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(\?|$)/ },
|
|
1263
|
+
handler(_code, id, _options) {
|
|
1264
|
+
if (this.environment.name === "client" && this.environment.mode === "dev" && isCSSRequest(id) && directRequestRE.test(id)) {
|
|
1265
|
+
const mod = this.environment.moduleGraph.getModuleById(id);
|
|
1266
|
+
if (mod && !mod.isSelfAccepting) mod.isSelfAccepting = true;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
},
|
|
1271
|
+
{
|
|
1272
|
+
name: "rsc:css-virtual",
|
|
1273
|
+
resolveId: {
|
|
1274
|
+
filter: { id: prefixRegex("virtual:vite-rsc/css?") },
|
|
1275
|
+
handler(source) {
|
|
1276
|
+
if (source.startsWith("virtual:vite-rsc/css?")) return "\0" + source;
|
|
1277
|
+
}
|
|
1278
|
+
},
|
|
1279
|
+
load: {
|
|
1280
|
+
filter: { id: prefixRegex("\0virtual:vite-rsc/css?") },
|
|
1281
|
+
async handler(id) {
|
|
1282
|
+
const parsed = parseCssVirtual(id);
|
|
1283
|
+
if (parsed?.type === "ssr") {
|
|
1284
|
+
id = parsed.id;
|
|
1285
|
+
const { server } = manager;
|
|
1286
|
+
const mod = await server.environments.ssr.moduleGraph.getModuleByUrl(id);
|
|
1287
|
+
if (!mod?.id || !mod?.file) return `export default []`;
|
|
1288
|
+
const result = collectCss(server.environments.ssr, mod.id);
|
|
1289
|
+
for (const file of [mod.file, ...result.visitedFiles]) this.addWatchFile(file);
|
|
1290
|
+
return `export default ${serializeValueWithRuntime(result.hrefs.map((href) => assetsURL(href.slice(1), manager)))}`;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
},
|
|
1295
|
+
{
|
|
1296
|
+
name: "rsc:importer-resources",
|
|
1297
|
+
configureServer(server) {
|
|
1298
|
+
const hot = server.environments.rsc.hot;
|
|
1299
|
+
const original = hot.send;
|
|
1300
|
+
hot.send = function(...args) {
|
|
1301
|
+
const e = args[0];
|
|
1302
|
+
if (e && typeof e === "object" && e.type === "prune") server.environments.client.hot.send({
|
|
1303
|
+
type: "custom",
|
|
1304
|
+
event: "rsc:prune",
|
|
1305
|
+
data: e
|
|
1306
|
+
});
|
|
1307
|
+
return original.apply(this, args);
|
|
1308
|
+
};
|
|
1309
|
+
},
|
|
1310
|
+
transform: {
|
|
1311
|
+
filter: { code: "import.meta.viteRsc.loadCss" },
|
|
1312
|
+
async handler(code, id) {
|
|
1313
|
+
if (!code.includes("import.meta.viteRsc.loadCss")) return;
|
|
1314
|
+
assert(this.environment.name === "rsc");
|
|
1315
|
+
const output = new MagicString(code);
|
|
1316
|
+
let importAdded = false;
|
|
1317
|
+
for (const match of stripLiteral(code).matchAll(/import\.meta\.viteRsc\.loadCss\(([\s\S]*?)\)/dg)) {
|
|
1318
|
+
const [start, end] = match.indices[0];
|
|
1319
|
+
const [argStart, argEnd] = match.indices[1];
|
|
1320
|
+
const argCode = code.slice(argStart, argEnd).trim();
|
|
1321
|
+
let importer = id;
|
|
1322
|
+
if (argCode) {
|
|
1323
|
+
const argValue = evalValue(argCode);
|
|
1324
|
+
const resolved = await this.resolve(argValue, id);
|
|
1325
|
+
if (resolved) importer = resolved.id;
|
|
1326
|
+
else {
|
|
1327
|
+
this.warn(`[vite-rsc] failed to transform 'import.meta.viteRsc.loadCss(${argCode})'`);
|
|
1328
|
+
output.update(start, end, `null`);
|
|
1329
|
+
continue;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
const importId = toCssVirtual({
|
|
1333
|
+
id: importer,
|
|
1334
|
+
type: "rsc"
|
|
1335
|
+
});
|
|
1336
|
+
let replacement;
|
|
1337
|
+
if (this.environment.mode === "dev") replacement = `__vite_rsc_react__.createElement(async () => {
|
|
1338
|
+
const __m = await import(${JSON.stringify(importId)});
|
|
1339
|
+
return __vite_rsc_react__.createElement(__m.Resources);
|
|
1340
|
+
})`;
|
|
1341
|
+
else {
|
|
1342
|
+
const hash = hashString(importId);
|
|
1343
|
+
if (!importAdded && !code.includes(`__vite_rsc_importer_resources_${hash}`)) {
|
|
1344
|
+
importAdded = true;
|
|
1345
|
+
output.prepend(`import * as __vite_rsc_importer_resources_${hash} from ${JSON.stringify(importId)};`);
|
|
1346
|
+
}
|
|
1347
|
+
replacement = `__vite_rsc_react__.createElement(__vite_rsc_importer_resources_${hash}.Resources)`;
|
|
1348
|
+
}
|
|
1349
|
+
output.update(start, end, replacement);
|
|
1350
|
+
}
|
|
1351
|
+
if (output.hasChanged()) {
|
|
1352
|
+
if (!code.includes("__vite_rsc_react__")) output.prepend(`import __vite_rsc_react__ from "react";`);
|
|
1353
|
+
return {
|
|
1354
|
+
code: output.toString(),
|
|
1355
|
+
map: output.generateMap({ hires: "boundary" })
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
},
|
|
1360
|
+
load: {
|
|
1361
|
+
filter: { id: prefixRegex("\0virtual:vite-rsc/css?") },
|
|
1362
|
+
handler(id) {
|
|
1363
|
+
const { server } = manager;
|
|
1364
|
+
const parsed = parseCssVirtual(id);
|
|
1365
|
+
if (parsed?.type === "rsc") {
|
|
1366
|
+
assert(this.environment.name === "rsc");
|
|
1367
|
+
const importer = parsed.id;
|
|
1368
|
+
if (this.environment.mode === "dev") {
|
|
1369
|
+
const result = collectCss(server.environments.rsc, importer);
|
|
1370
|
+
for (const file of [importer, ...result.visitedFiles]) this.addWatchFile(file);
|
|
1371
|
+
return generateResourcesCode(serializeValueWithRuntime(assetsURLOfDeps({
|
|
1372
|
+
css: result.hrefs.map((href) => href.slice(1)),
|
|
1373
|
+
js: []
|
|
1374
|
+
}, manager)), manager, { cssLinkPrecedence: rscCssOptions.cssLinkPrecedence });
|
|
1375
|
+
} else {
|
|
1376
|
+
const key = manager.toRelativeId(importer);
|
|
1377
|
+
manager.serverResourcesMetaMap[importer] = { key };
|
|
1378
|
+
return `
|
|
1379
|
+
import __vite_rsc_assets_manifest__ from "virtual:vite-rsc/assets-manifest";
|
|
1380
|
+
${generateResourcesCode(`__vite_rsc_assets_manifest__.serverResources[${JSON.stringify(key)}]`, manager, { cssLinkPrecedence: rscCssOptions.cssLinkPrecedence })}
|
|
1381
|
+
`;
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
},
|
|
1387
|
+
createVirtualPlugin("vite-rsc/remove-duplicate-server-css", async function() {
|
|
1388
|
+
assert.equal(this.environment.mode, "dev");
|
|
1389
|
+
function removeFn() {
|
|
1390
|
+
document.querySelectorAll("link[rel='stylesheet']").forEach((node) => {
|
|
1391
|
+
if (node instanceof HTMLElement && node.dataset.precedence?.startsWith("vite-rsc/client-reference")) node.remove();
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
return `\
|
|
1395
|
+
"use client"
|
|
1396
|
+
import React from "react";
|
|
1397
|
+
export default function RemoveDuplicateServerCss() {
|
|
1398
|
+
React.useEffect(() => {
|
|
1399
|
+
(${removeFn.toString()})();
|
|
1400
|
+
}, []);
|
|
1401
|
+
return null;
|
|
1402
|
+
}
|
|
1403
|
+
`;
|
|
1404
|
+
})
|
|
1405
|
+
];
|
|
1406
|
+
}
|
|
1407
|
+
function generateResourcesCode(depsCode, manager, options = {}) {
|
|
1408
|
+
const usePrecedence = options.cssLinkPrecedence !== false;
|
|
1409
|
+
const ResourcesFn = (React, deps, RemoveDuplicateServerCss, precedence) => {
|
|
1410
|
+
return function Resources() {
|
|
1411
|
+
return React.createElement(React.Fragment, null, [...deps.css.map((href) => React.createElement("link", {
|
|
1412
|
+
key: "css:" + href,
|
|
1413
|
+
rel: "stylesheet",
|
|
1414
|
+
...precedence ? { precedence } : {},
|
|
1415
|
+
href,
|
|
1416
|
+
"data-rsc-css-href": href
|
|
1417
|
+
})), RemoveDuplicateServerCss && React.createElement(RemoveDuplicateServerCss, { key: "remove-duplicate-css" })]);
|
|
1418
|
+
};
|
|
1419
|
+
};
|
|
1420
|
+
return `
|
|
1421
|
+
import __vite_rsc_react__ from "react";
|
|
1422
|
+
|
|
1423
|
+
${manager.config.command === "serve" ? `import RemoveDuplicateServerCss from "virtual:vite-rsc/remove-duplicate-server-css";` : `const RemoveDuplicateServerCss = undefined;`}
|
|
1424
|
+
|
|
1425
|
+
export const Resources = (${ResourcesFn.toString()})(
|
|
1426
|
+
__vite_rsc_react__,
|
|
1427
|
+
${depsCode},
|
|
1428
|
+
RemoveDuplicateServerCss,
|
|
1429
|
+
${usePrecedence ? `"vite-rsc/importer-resources"` : `undefined`},
|
|
1430
|
+
);
|
|
1431
|
+
`;
|
|
1432
|
+
}
|
|
1433
|
+
async function transformRscCssExport(options) {
|
|
1434
|
+
if (hasDirective(options.ast.body, "use client")) return;
|
|
1435
|
+
const result = transformWrapExport(options.code, options.ast, {
|
|
1436
|
+
runtime: (value, name, meta) => `__vite_rsc_wrap_css__(${value}, ${JSON.stringify(meta.defaultExportIdentifierName ?? name)})`,
|
|
1437
|
+
filter: options.filter,
|
|
1438
|
+
ignoreExportAllDeclaration: true
|
|
1439
|
+
});
|
|
1440
|
+
if (result.output.hasChanged()) {
|
|
1441
|
+
if (!options.code.includes("__vite_rsc_react__")) result.output.prepend(`import __vite_rsc_react__ from "react";`);
|
|
1442
|
+
result.output.append(`
|
|
1443
|
+
function __vite_rsc_wrap_css__(value, name) {
|
|
1444
|
+
if (typeof value !== 'function') return value;
|
|
1445
|
+
|
|
1446
|
+
function __wrapper(props) {
|
|
1447
|
+
return __vite_rsc_react__.createElement(
|
|
1448
|
+
__vite_rsc_react__.Fragment,
|
|
1449
|
+
null,
|
|
1450
|
+
import.meta.viteRsc.loadCss(${options.id ? JSON.stringify(options.id) : ""}),
|
|
1451
|
+
__vite_rsc_react__.createElement(value, props),
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
Object.defineProperty(__wrapper, "name", { value: name });
|
|
1455
|
+
return __wrapper;
|
|
1456
|
+
}
|
|
1457
|
+
`);
|
|
1458
|
+
return { output: result.output };
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
//#endregion
|
|
6
1463
|
export { vitePluginRsc as default, getPluginApi, transformRscCssExport, vitePluginRscMinimal };
|