@react-router/dev 7.0.0-pre.2 → 7.0.0-pre.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/cli/index.d.ts +2 -1
- package/dist/cli/index.js +1352 -8
- package/dist/routes.d.ts +4 -2
- package/dist/routes.js +181 -11
- package/dist/typescript/plugin.d.ts +5 -2
- package/dist/typescript/plugin.js +479 -31
- package/dist/vite/cloudflare.d.ts +1 -1
- package/dist/vite/cloudflare.js +171 -5
- package/dist/vite.d.ts +2 -2
- package/dist/vite.js +2394 -5
- package/package.json +28 -7
- package/dist/cli/commands.d.ts +0 -13
- package/dist/cli/commands.js +0 -179
- package/dist/cli/detectPackageManager.d.ts +0 -10
- package/dist/cli/detectPackageManager.js +0 -39
- package/dist/cli/run.d.ts +0 -5
- package/dist/cli/run.js +0 -188
- package/dist/cli/useJavascript.d.ts +0 -4
- package/dist/cli/useJavascript.js +0 -66
- package/dist/colors.d.ts +0 -17
- package/dist/colors.js +0 -49
- package/dist/config/format.d.ts +0 -5
- package/dist/config/format.js +0 -68
- package/dist/config/routes.d.ts +0 -129
- package/dist/config/routes.js +0 -253
- package/dist/config/serverModes.d.ts +0 -9
- package/dist/invariant.d.ts +0 -2
- package/dist/invariant.js +0 -20
- package/dist/manifest.d.ts +0 -28
- package/dist/typescript/typegen.d.ts +0 -10
- package/dist/typescript/typegen.js +0 -190
- package/dist/vite/babel.d.ts +0 -20
- package/dist/vite/babel.js +0 -49
- package/dist/vite/build.d.ts +0 -15
- package/dist/vite/build.js +0 -249
- package/dist/vite/cloudflare-dev-proxy.d.ts +0 -21
- package/dist/vite/cloudflare-dev-proxy.js +0 -89
- package/dist/vite/combine-urls-test.d.ts +0 -1
- package/dist/vite/combine-urls.d.ts +0 -1
- package/dist/vite/combine-urls.js +0 -20
- package/dist/vite/config.d.ts +0 -234
- package/dist/vite/config.js +0 -282
- package/dist/vite/dev.d.ts +0 -15
- package/dist/vite/dev.js +0 -81
- package/dist/vite/import-vite-esm-sync.d.ts +0 -4
- package/dist/vite/import-vite-esm-sync.js +0 -28
- package/dist/vite/node-adapter.d.ts +0 -6
- package/dist/vite/node-adapter.js +0 -90
- package/dist/vite/plugin.d.ts +0 -75
- package/dist/vite/plugin.js +0 -1301
- package/dist/vite/profiler.d.ts +0 -5
- package/dist/vite/profiler.js +0 -55
- package/dist/vite/remove-exports-test.d.ts +0 -1
- package/dist/vite/remove-exports.d.ts +0 -2
- package/dist/vite/remove-exports.js +0 -148
- package/dist/vite/resolve-file-url.d.ts +0 -3
- package/dist/vite/resolve-file-url.js +0 -53
- package/dist/vite/styles.d.ts +0 -14
- package/dist/vite/styles.js +0 -199
- package/dist/vite/vite-node.d.ts +0 -9
- package/dist/vite/vite-node.js +0 -57
- package/dist/vite/vmod.d.ts +0 -3
- package/dist/vite/vmod.js +0 -21
- package/dist/vite/with-props.d.ts +0 -4
- package/dist/vite/with-props.js +0 -151
- /package/dist/{vite/static → static}/refresh-utils.cjs +0 -0
package/dist/vite/plugin.js
DELETED
|
@@ -1,1301 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @react-router/dev v7.0.0-pre.2
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) Remix Software Inc.
|
|
5
|
-
*
|
|
6
|
-
* This source code is licensed under the MIT license found in the
|
|
7
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
-
*
|
|
9
|
-
* @license MIT
|
|
10
|
-
*/
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
-
|
|
15
|
-
var node_crypto = require('node:crypto');
|
|
16
|
-
var path = require('node:path');
|
|
17
|
-
var url = require('node:url');
|
|
18
|
-
var fse = require('fs-extra');
|
|
19
|
-
var babel$1 = require('@babel/core');
|
|
20
|
-
var reactRouter = require('react-router');
|
|
21
|
-
var esModuleLexer = require('es-module-lexer');
|
|
22
|
-
var jsesc = require('jsesc');
|
|
23
|
-
var colors = require('picocolors');
|
|
24
|
-
var invariant = require('../invariant.js');
|
|
25
|
-
var babel = require('./babel.js');
|
|
26
|
-
var nodeAdapter = require('./node-adapter.js');
|
|
27
|
-
var styles = require('./styles.js');
|
|
28
|
-
var vmod = require('./vmod.js');
|
|
29
|
-
var resolveFileUrl = require('./resolve-file-url.js');
|
|
30
|
-
var combineUrls = require('./combine-urls.js');
|
|
31
|
-
var removeExports = require('./remove-exports.js');
|
|
32
|
-
var importViteEsmSync = require('./import-vite-esm-sync.js');
|
|
33
|
-
var config = require('./config.js');
|
|
34
|
-
var withProps = require('./with-props.js');
|
|
35
|
-
var viteNode = require('./vite-node.js');
|
|
36
|
-
var parser = require('@babel/parser');
|
|
37
|
-
|
|
38
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
39
|
-
|
|
40
|
-
function _interopNamespace(e) {
|
|
41
|
-
if (e && e.__esModule) return e;
|
|
42
|
-
var n = Object.create(null);
|
|
43
|
-
if (e) {
|
|
44
|
-
Object.keys(e).forEach(function (k) {
|
|
45
|
-
if (k !== 'default') {
|
|
46
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
47
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
48
|
-
enumerable: true,
|
|
49
|
-
get: function () { return e[k]; }
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
n["default"] = e;
|
|
55
|
-
return Object.freeze(n);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
59
|
-
var url__namespace = /*#__PURE__*/_interopNamespace(url);
|
|
60
|
-
var fse__namespace = /*#__PURE__*/_interopNamespace(fse);
|
|
61
|
-
var babel__default = /*#__PURE__*/_interopDefaultLegacy(babel$1);
|
|
62
|
-
var jsesc__default = /*#__PURE__*/_interopDefaultLegacy(jsesc);
|
|
63
|
-
var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
|
|
64
|
-
|
|
65
|
-
async function resolveViteConfig({
|
|
66
|
-
configFile,
|
|
67
|
-
mode,
|
|
68
|
-
root
|
|
69
|
-
}) {
|
|
70
|
-
let vite = await import('vite');
|
|
71
|
-
let viteConfig = await vite.resolveConfig({
|
|
72
|
-
mode,
|
|
73
|
-
configFile,
|
|
74
|
-
root
|
|
75
|
-
}, "build",
|
|
76
|
-
// command
|
|
77
|
-
"production",
|
|
78
|
-
// default mode
|
|
79
|
-
"production" // default NODE_ENV
|
|
80
|
-
);
|
|
81
|
-
if (typeof viteConfig.build.manifest === "string") {
|
|
82
|
-
throw new Error("Custom Vite manifest paths are not supported");
|
|
83
|
-
}
|
|
84
|
-
return viteConfig;
|
|
85
|
-
}
|
|
86
|
-
async function extractPluginContext(viteConfig) {
|
|
87
|
-
return viteConfig["__reactRouterPluginContext"];
|
|
88
|
-
}
|
|
89
|
-
async function loadPluginContext({
|
|
90
|
-
configFile,
|
|
91
|
-
root
|
|
92
|
-
}) {
|
|
93
|
-
if (!root) {
|
|
94
|
-
root = process.env.REACT_ROUTER_ROOT || process.cwd();
|
|
95
|
-
}
|
|
96
|
-
configFile = configFile ?? findConfig(root, "vite.config", [".ts", ".cts", ".mts", ".js", ".cjs", ".mjs"]);
|
|
97
|
-
if (!configFile) {
|
|
98
|
-
console.error(colors__default["default"].red("Vite config file not found"));
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
101
|
-
let viteConfig = await resolveViteConfig({
|
|
102
|
-
configFile,
|
|
103
|
-
root
|
|
104
|
-
});
|
|
105
|
-
let ctx = await extractPluginContext(viteConfig);
|
|
106
|
-
if (!ctx) {
|
|
107
|
-
console.error(colors__default["default"].red("React Router Vite plugin not found in Vite config"));
|
|
108
|
-
process.exit(1);
|
|
109
|
-
}
|
|
110
|
-
return ctx;
|
|
111
|
-
}
|
|
112
|
-
const SERVER_ONLY_ROUTE_EXPORTS = ["loader", "action", "headers"];
|
|
113
|
-
const CLIENT_ROUTE_EXPORTS = ["clientAction", "clientLoader", "default", "ErrorBoundary", "handle", "HydrateFallback", "Layout", "links", "meta", "shouldRevalidate"];
|
|
114
|
-
// Each route gets its own virtual module marked with an entry query string
|
|
115
|
-
const ROUTE_ENTRY_QUERY_STRING = "?route-entry=1";
|
|
116
|
-
const isRouteEntry = id => {
|
|
117
|
-
return id.endsWith(ROUTE_ENTRY_QUERY_STRING);
|
|
118
|
-
};
|
|
119
|
-
let serverBuildId = vmod.id("server-build");
|
|
120
|
-
let serverManifestId = vmod.id("server-manifest");
|
|
121
|
-
let browserManifestId = vmod.id("browser-manifest");
|
|
122
|
-
let hmrRuntimeId = vmod.id("hmr-runtime");
|
|
123
|
-
let injectHmrRuntimeId = vmod.id("inject-hmr-runtime");
|
|
124
|
-
const resolveRelativeRouteFilePath = (route, reactRouterConfig) => {
|
|
125
|
-
let vite = importViteEsmSync.importViteEsmSync();
|
|
126
|
-
let file = route.file;
|
|
127
|
-
let fullPath = path__namespace.resolve(reactRouterConfig.appDirectory, file);
|
|
128
|
-
return vite.normalizePath(fullPath);
|
|
129
|
-
};
|
|
130
|
-
let vmods = [serverBuildId, serverManifestId, browserManifestId];
|
|
131
|
-
const invalidateVirtualModules = viteDevServer => {
|
|
132
|
-
vmods.forEach(vmod$1 => {
|
|
133
|
-
let mod = viteDevServer.moduleGraph.getModuleById(vmod.resolve(vmod$1));
|
|
134
|
-
if (mod) {
|
|
135
|
-
viteDevServer.moduleGraph.invalidateModule(mod);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
};
|
|
139
|
-
const getHash = (source, maxLength) => {
|
|
140
|
-
let hash = node_crypto.createHash("sha256").update(source).digest("hex");
|
|
141
|
-
return typeof maxLength === "number" ? hash.slice(0, maxLength) : hash;
|
|
142
|
-
};
|
|
143
|
-
const resolveChunk = (ctx, viteManifest, absoluteFilePath) => {
|
|
144
|
-
let vite = importViteEsmSync.importViteEsmSync();
|
|
145
|
-
let rootRelativeFilePath = vite.normalizePath(path__namespace.relative(ctx.rootDirectory, absoluteFilePath));
|
|
146
|
-
let entryChunk = viteManifest[rootRelativeFilePath + ROUTE_ENTRY_QUERY_STRING] ?? viteManifest[rootRelativeFilePath];
|
|
147
|
-
if (!entryChunk) {
|
|
148
|
-
let knownManifestKeys = Object.keys(viteManifest).map(key => '"' + key + '"').join(", ");
|
|
149
|
-
throw new Error(`No manifest entry found for "${rootRelativeFilePath}". Known manifest keys: ${knownManifestKeys}`);
|
|
150
|
-
}
|
|
151
|
-
return entryChunk;
|
|
152
|
-
};
|
|
153
|
-
const getReactRouterManifestBuildAssets = (ctx, viteManifest, entryFilePath, prependedAssetFilePaths = []) => {
|
|
154
|
-
let entryChunk = resolveChunk(ctx, viteManifest, entryFilePath);
|
|
155
|
-
// This is here to support prepending client entry assets to the root route
|
|
156
|
-
let prependedAssetChunks = prependedAssetFilePaths.map(filePath => resolveChunk(ctx, viteManifest, filePath));
|
|
157
|
-
let chunks = resolveDependantChunks(viteManifest, [...prependedAssetChunks, entryChunk]);
|
|
158
|
-
return {
|
|
159
|
-
module: `${ctx.publicPath}${entryChunk.file}`,
|
|
160
|
-
imports: dedupe(chunks.flatMap(e => e.imports ?? [])).map(imported => {
|
|
161
|
-
return `${ctx.publicPath}${viteManifest[imported].file}`;
|
|
162
|
-
}) ?? [],
|
|
163
|
-
css: dedupe(chunks.flatMap(e => e.css ?? [])).map(href => {
|
|
164
|
-
return `${ctx.publicPath}${href}`;
|
|
165
|
-
}) ?? []
|
|
166
|
-
};
|
|
167
|
-
};
|
|
168
|
-
function resolveDependantChunks(viteManifest, entryChunks) {
|
|
169
|
-
let chunks = new Set();
|
|
170
|
-
function walk(chunk) {
|
|
171
|
-
if (chunks.has(chunk)) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
chunks.add(chunk);
|
|
175
|
-
if (chunk.imports) {
|
|
176
|
-
for (let importKey of chunk.imports) {
|
|
177
|
-
walk(viteManifest[importKey]);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
for (let entryChunk of entryChunks) {
|
|
182
|
-
walk(entryChunk);
|
|
183
|
-
}
|
|
184
|
-
return Array.from(chunks);
|
|
185
|
-
}
|
|
186
|
-
function dedupe(array) {
|
|
187
|
-
return [...new Set(array)];
|
|
188
|
-
}
|
|
189
|
-
const writeFileSafe = async (file, contents) => {
|
|
190
|
-
await fse__namespace.ensureDir(path__namespace.dirname(file));
|
|
191
|
-
await fse__namespace.writeFile(file, contents);
|
|
192
|
-
};
|
|
193
|
-
const getRouteManifestModuleExports = async (viteChildCompiler, ctx) => {
|
|
194
|
-
let entries = await Promise.all(Object.entries(ctx.reactRouterConfig.routes).map(async ([key, route]) => {
|
|
195
|
-
let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, route.file);
|
|
196
|
-
return [key, sourceExports];
|
|
197
|
-
}));
|
|
198
|
-
return Object.fromEntries(entries);
|
|
199
|
-
};
|
|
200
|
-
const getRouteModuleExports = async (viteChildCompiler, ctx, routeFile, readRouteFile) => {
|
|
201
|
-
if (!viteChildCompiler) {
|
|
202
|
-
throw new Error("Vite child compiler not found");
|
|
203
|
-
}
|
|
204
|
-
// We transform the route module code with the Vite child compiler so that we
|
|
205
|
-
// can parse the exports from non-JS files like MDX. This ensures that we can
|
|
206
|
-
// understand the exports from anything that Vite can compile to JS, not just
|
|
207
|
-
// the route file formats that the Remix compiler historically supported.
|
|
208
|
-
let ssr = true;
|
|
209
|
-
let {
|
|
210
|
-
pluginContainer,
|
|
211
|
-
moduleGraph
|
|
212
|
-
} = viteChildCompiler;
|
|
213
|
-
let routePath = path__namespace.resolve(ctx.reactRouterConfig.appDirectory, routeFile);
|
|
214
|
-
let url = resolveFileUrl.resolveFileUrl(ctx, routePath);
|
|
215
|
-
let resolveId = async () => {
|
|
216
|
-
let result = await pluginContainer.resolveId(url, undefined, {
|
|
217
|
-
ssr
|
|
218
|
-
});
|
|
219
|
-
if (!result) throw new Error(`Could not resolve module ID for ${url}`);
|
|
220
|
-
return result.id;
|
|
221
|
-
};
|
|
222
|
-
let [id, code] = await Promise.all([resolveId(), (readRouteFile === null || readRouteFile === void 0 ? void 0 : readRouteFile()) ?? fse__namespace.readFile(routePath, "utf-8"),
|
|
223
|
-
// pluginContainer.transform(...) fails if we don't do this first:
|
|
224
|
-
moduleGraph.ensureEntryFromUrl(url, ssr)]);
|
|
225
|
-
let transformed = await pluginContainer.transform(code, id, {
|
|
226
|
-
ssr
|
|
227
|
-
});
|
|
228
|
-
let [, exports] = esModuleLexer.parse(transformed.code);
|
|
229
|
-
let exportNames = exports.map(e => e.n);
|
|
230
|
-
return exportNames;
|
|
231
|
-
};
|
|
232
|
-
const getServerBundleBuildConfig = viteUserConfig => {
|
|
233
|
-
if (!("__reactRouterServerBundleBuildConfig" in viteUserConfig) || !viteUserConfig.__reactRouterServerBundleBuildConfig) {
|
|
234
|
-
return null;
|
|
235
|
-
}
|
|
236
|
-
return viteUserConfig.__reactRouterServerBundleBuildConfig;
|
|
237
|
-
};
|
|
238
|
-
let getServerBuildDirectory = ctx => path__namespace.join(ctx.reactRouterConfig.buildDirectory, "server", ...(ctx.serverBundleBuildConfig ? [ctx.serverBundleBuildConfig.serverBundleId] : []));
|
|
239
|
-
let getClientBuildDirectory = reactRouterConfig => path__namespace.join(reactRouterConfig.buildDirectory, "client");
|
|
240
|
-
let defaultEntriesDir = path__namespace.resolve(__dirname, "..", "config", "defaults");
|
|
241
|
-
let defaultEntries = fse__namespace.readdirSync(defaultEntriesDir).map(filename => path__namespace.join(defaultEntriesDir, filename));
|
|
242
|
-
invariant(defaultEntries.length > 0, "No default entries found");
|
|
243
|
-
let reactRouterDevLoadContext = () => ({});
|
|
244
|
-
// Inlined from https://github.com/jsdf/deep-freeze
|
|
245
|
-
let deepFreeze = o => {
|
|
246
|
-
Object.freeze(o);
|
|
247
|
-
let oIsFunction = typeof o === "function";
|
|
248
|
-
let hasOwnProp = Object.prototype.hasOwnProperty;
|
|
249
|
-
Object.getOwnPropertyNames(o).forEach(function (prop) {
|
|
250
|
-
if (hasOwnProp.call(o, prop) && (oIsFunction ? prop !== "caller" && prop !== "callee" && prop !== "arguments" : true) && o[prop] !== null && (typeof o[prop] === "object" || typeof o[prop] === "function") && !Object.isFrozen(o[prop])) {
|
|
251
|
-
deepFreeze(o[prop]);
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
return o;
|
|
255
|
-
};
|
|
256
|
-
/**
|
|
257
|
-
* React Router [Vite plugin.](https://vitejs.dev/guide/using-plugins.html)
|
|
258
|
-
*/
|
|
259
|
-
const reactRouterVitePlugin = _config => {
|
|
260
|
-
let reactRouterUserConfig = _config ?? {};
|
|
261
|
-
// Prevent mutations to the user config
|
|
262
|
-
reactRouterUserConfig = deepFreeze(reactRouterUserConfig);
|
|
263
|
-
let viteCommand;
|
|
264
|
-
let viteUserConfig;
|
|
265
|
-
let viteConfigEnv;
|
|
266
|
-
let viteConfig;
|
|
267
|
-
let cssModulesManifest = {};
|
|
268
|
-
let viteChildCompiler = null;
|
|
269
|
-
let routesViteNodeContext = null;
|
|
270
|
-
let ssrExternals = isInReactRouterMonorepo() ? [
|
|
271
|
-
// This is only needed within this repo because these packages
|
|
272
|
-
// are linked to a directory outside of node_modules so Vite
|
|
273
|
-
// treats them as internal code by default.
|
|
274
|
-
"react-router", "react-router-dom", "@react-router/architect", "@react-router/cloudflare", "@react-router/dev", "@react-router/express", "@react-router/node", "@react-router/serve"] : undefined;
|
|
275
|
-
// This is initialized by `updatePluginContext` during Vite's `config`
|
|
276
|
-
// hook, so most of the code can assume this defined without null check.
|
|
277
|
-
// During dev, `updatePluginContext` is called again on every config file
|
|
278
|
-
// change or route file addition/removal.
|
|
279
|
-
let ctx;
|
|
280
|
-
/** Mutates `ctx` as a side-effect */
|
|
281
|
-
let updatePluginContext = async ({
|
|
282
|
-
routeConfigChanged = false
|
|
283
|
-
} = {}) => {
|
|
284
|
-
var _viteUserConfig$build;
|
|
285
|
-
let rootDirectory = viteUserConfig.root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
|
|
286
|
-
invariant(routesViteNodeContext);
|
|
287
|
-
let reactRouterConfig = await config.resolveReactRouterConfig({
|
|
288
|
-
rootDirectory,
|
|
289
|
-
reactRouterUserConfig,
|
|
290
|
-
routeConfigChanged,
|
|
291
|
-
viteUserConfig,
|
|
292
|
-
viteCommand,
|
|
293
|
-
routesViteNodeContext
|
|
294
|
-
});
|
|
295
|
-
let {
|
|
296
|
-
entryClientFilePath,
|
|
297
|
-
entryServerFilePath
|
|
298
|
-
} = await config.resolveEntryFiles({
|
|
299
|
-
rootDirectory,
|
|
300
|
-
reactRouterConfig
|
|
301
|
-
});
|
|
302
|
-
let publicPath = config.resolvePublicPath(viteUserConfig);
|
|
303
|
-
let viteManifestEnabled = ((_viteUserConfig$build = viteUserConfig.build) === null || _viteUserConfig$build === void 0 ? void 0 : _viteUserConfig$build.manifest) === true;
|
|
304
|
-
let ssrBuildCtx = viteConfigEnv.isSsrBuild && viteCommand === "build" ? {
|
|
305
|
-
isSsrBuild: true,
|
|
306
|
-
getReactRouterServerManifest: async () => (await generateReactRouterManifestsForBuild()).reactRouterServerManifest,
|
|
307
|
-
serverBundleBuildConfig: getServerBundleBuildConfig(viteUserConfig)
|
|
308
|
-
} : {
|
|
309
|
-
isSsrBuild: false
|
|
310
|
-
};
|
|
311
|
-
ctx = {
|
|
312
|
-
reactRouterConfig,
|
|
313
|
-
rootDirectory,
|
|
314
|
-
entryClientFilePath,
|
|
315
|
-
entryServerFilePath,
|
|
316
|
-
publicPath,
|
|
317
|
-
viteManifestEnabled,
|
|
318
|
-
...ssrBuildCtx
|
|
319
|
-
};
|
|
320
|
-
};
|
|
321
|
-
let pluginIndex = pluginName => {
|
|
322
|
-
invariant(viteConfig);
|
|
323
|
-
return viteConfig.plugins.findIndex(plugin => plugin.name === pluginName);
|
|
324
|
-
};
|
|
325
|
-
let getServerEntry = async () => {
|
|
326
|
-
invariant(viteConfig, "viteconfig required to generate the server entry");
|
|
327
|
-
let routes = ctx.serverBundleBuildConfig ?
|
|
328
|
-
// For server bundle builds, the server build should only import the
|
|
329
|
-
// routes for this bundle rather than importing all routes
|
|
330
|
-
ctx.serverBundleBuildConfig.routes :
|
|
331
|
-
// Otherwise, all routes are imported as usual
|
|
332
|
-
ctx.reactRouterConfig.routes;
|
|
333
|
-
return `
|
|
334
|
-
import * as entryServer from ${JSON.stringify(resolveFileUrl.resolveFileUrl(ctx, ctx.entryServerFilePath))};
|
|
335
|
-
${Object.keys(routes).map((key, index) => {
|
|
336
|
-
let route = routes[key];
|
|
337
|
-
return `import * as route${index} from ${JSON.stringify(resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig)) + ROUTE_ENTRY_QUERY_STRING)};`;
|
|
338
|
-
}).join("\n")}
|
|
339
|
-
export { default as assets } from ${JSON.stringify(serverManifestId)};
|
|
340
|
-
export const assetsBuildDirectory = ${JSON.stringify(path__namespace.relative(ctx.rootDirectory, getClientBuildDirectory(ctx.reactRouterConfig)))};
|
|
341
|
-
export const basename = ${JSON.stringify(ctx.reactRouterConfig.basename)};
|
|
342
|
-
export const future = ${JSON.stringify(ctx.reactRouterConfig.future)};
|
|
343
|
-
export const isSpaMode = ${!ctx.reactRouterConfig.ssr && ctx.reactRouterConfig.prerender == null};
|
|
344
|
-
export const publicPath = ${JSON.stringify(ctx.publicPath)};
|
|
345
|
-
export const entry = { module: entryServer };
|
|
346
|
-
export const routes = {
|
|
347
|
-
${Object.keys(routes).map((key, index) => {
|
|
348
|
-
let route = routes[key];
|
|
349
|
-
return `${JSON.stringify(key)}: {
|
|
350
|
-
id: ${JSON.stringify(route.id)},
|
|
351
|
-
parentId: ${JSON.stringify(route.parentId)},
|
|
352
|
-
path: ${JSON.stringify(route.path)},
|
|
353
|
-
index: ${JSON.stringify(route.index)},
|
|
354
|
-
caseSensitive: ${JSON.stringify(route.caseSensitive)},
|
|
355
|
-
module: route${index}
|
|
356
|
-
}`;
|
|
357
|
-
}).join(",\n ")}
|
|
358
|
-
};`;
|
|
359
|
-
};
|
|
360
|
-
let loadViteManifest = async directory => {
|
|
361
|
-
let manifestContents = await fse__namespace.readFile(path__namespace.resolve(directory, ".vite", "manifest.json"), "utf-8");
|
|
362
|
-
return JSON.parse(manifestContents);
|
|
363
|
-
};
|
|
364
|
-
let hasDependency = name => {
|
|
365
|
-
try {
|
|
366
|
-
return Boolean(require.resolve(name, {
|
|
367
|
-
paths: [ctx.rootDirectory]
|
|
368
|
-
}));
|
|
369
|
-
} catch (err) {
|
|
370
|
-
return false;
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
let getViteManifestAssetPaths = viteManifest => {
|
|
374
|
-
// Get .css?url imports and CSS entry points
|
|
375
|
-
let cssUrlPaths = Object.values(viteManifest).filter(chunk => chunk.file.endsWith(".css")).map(chunk => chunk.file);
|
|
376
|
-
// Get bundled CSS files and generic asset types
|
|
377
|
-
let chunkAssetPaths = Object.values(viteManifest).flatMap(chunk => chunk.assets ?? []);
|
|
378
|
-
return new Set([...cssUrlPaths, ...chunkAssetPaths]);
|
|
379
|
-
};
|
|
380
|
-
let generateReactRouterManifestsForBuild = async () => {
|
|
381
|
-
invariant(viteConfig);
|
|
382
|
-
let viteManifest = await loadViteManifest(getClientBuildDirectory(ctx.reactRouterConfig));
|
|
383
|
-
let entry = getReactRouterManifestBuildAssets(ctx, viteManifest, ctx.entryClientFilePath);
|
|
384
|
-
let browserRoutes = {};
|
|
385
|
-
let serverRoutes = {};
|
|
386
|
-
let routeManifestExports = await getRouteManifestModuleExports(viteChildCompiler, ctx);
|
|
387
|
-
for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
|
|
388
|
-
var _ctx$serverBundleBuil;
|
|
389
|
-
let routeFilePath = path__namespace.join(ctx.reactRouterConfig.appDirectory, route.file);
|
|
390
|
-
let sourceExports = routeManifestExports[key];
|
|
391
|
-
let isRootRoute = route.parentId === undefined;
|
|
392
|
-
let routeManifestEntry = {
|
|
393
|
-
id: route.id,
|
|
394
|
-
parentId: route.parentId,
|
|
395
|
-
path: route.path,
|
|
396
|
-
index: route.index,
|
|
397
|
-
caseSensitive: route.caseSensitive,
|
|
398
|
-
hasAction: sourceExports.includes("action"),
|
|
399
|
-
hasLoader: sourceExports.includes("loader"),
|
|
400
|
-
hasClientAction: sourceExports.includes("clientAction"),
|
|
401
|
-
hasClientLoader: sourceExports.includes("clientLoader"),
|
|
402
|
-
hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
|
|
403
|
-
...getReactRouterManifestBuildAssets(ctx, viteManifest, routeFilePath,
|
|
404
|
-
// If this is the root route, we also need to include assets from the
|
|
405
|
-
// client entry file as this is a common way for consumers to import
|
|
406
|
-
// global reset styles, etc.
|
|
407
|
-
isRootRoute ? [ctx.entryClientFilePath] : [])
|
|
408
|
-
};
|
|
409
|
-
browserRoutes[key] = routeManifestEntry;
|
|
410
|
-
let serverBundleRoutes = (_ctx$serverBundleBuil = ctx.serverBundleBuildConfig) === null || _ctx$serverBundleBuil === void 0 ? void 0 : _ctx$serverBundleBuil.routes;
|
|
411
|
-
if (!serverBundleRoutes || serverBundleRoutes[key]) {
|
|
412
|
-
serverRoutes[key] = routeManifestEntry;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
let fingerprintedValues = {
|
|
416
|
-
entry,
|
|
417
|
-
routes: browserRoutes
|
|
418
|
-
};
|
|
419
|
-
let version = getHash(JSON.stringify(fingerprintedValues), 8);
|
|
420
|
-
let manifestPath = path__namespace.posix.join(viteConfig.build.assetsDir, `manifest-${version}.js`);
|
|
421
|
-
let url = `${ctx.publicPath}${manifestPath}`;
|
|
422
|
-
let nonFingerprintedValues = {
|
|
423
|
-
url,
|
|
424
|
-
version
|
|
425
|
-
};
|
|
426
|
-
let reactRouterBrowserManifest = {
|
|
427
|
-
...fingerprintedValues,
|
|
428
|
-
...nonFingerprintedValues
|
|
429
|
-
};
|
|
430
|
-
// Write the browser manifest to disk as part of the build process
|
|
431
|
-
await writeFileSafe(path__namespace.join(getClientBuildDirectory(ctx.reactRouterConfig), manifestPath), `window.__reactRouterManifest=${JSON.stringify(reactRouterBrowserManifest)};`);
|
|
432
|
-
// The server manifest is the same as the browser manifest, except for
|
|
433
|
-
// server bundle builds which only includes routes for the current bundle,
|
|
434
|
-
// otherwise the server and client have the same routes
|
|
435
|
-
let reactRouterServerManifest = {
|
|
436
|
-
...reactRouterBrowserManifest,
|
|
437
|
-
routes: serverRoutes
|
|
438
|
-
};
|
|
439
|
-
return {
|
|
440
|
-
reactRouterBrowserManifest,
|
|
441
|
-
reactRouterServerManifest
|
|
442
|
-
};
|
|
443
|
-
};
|
|
444
|
-
// In dev, the server and browser manifests are the same
|
|
445
|
-
let getReactRouterManifestForDev = async () => {
|
|
446
|
-
let routes = {};
|
|
447
|
-
let routeManifestExports = await getRouteManifestModuleExports(viteChildCompiler, ctx);
|
|
448
|
-
for (let [key, route] of Object.entries(ctx.reactRouterConfig.routes)) {
|
|
449
|
-
let sourceExports = routeManifestExports[key];
|
|
450
|
-
routes[key] = {
|
|
451
|
-
id: route.id,
|
|
452
|
-
parentId: route.parentId,
|
|
453
|
-
path: route.path,
|
|
454
|
-
index: route.index,
|
|
455
|
-
caseSensitive: route.caseSensitive,
|
|
456
|
-
module: combineUrls.combineURLs(ctx.publicPath, `${resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))}${ROUTE_ENTRY_QUERY_STRING}`),
|
|
457
|
-
hasAction: sourceExports.includes("action"),
|
|
458
|
-
hasLoader: sourceExports.includes("loader"),
|
|
459
|
-
hasClientAction: sourceExports.includes("clientAction"),
|
|
460
|
-
hasClientLoader: sourceExports.includes("clientLoader"),
|
|
461
|
-
hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
|
|
462
|
-
imports: []
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
return {
|
|
466
|
-
version: String(Math.random()),
|
|
467
|
-
url: combineUrls.combineURLs(ctx.publicPath, vmod.url(browserManifestId)),
|
|
468
|
-
hmr: {
|
|
469
|
-
runtime: combineUrls.combineURLs(ctx.publicPath, vmod.url(injectHmrRuntimeId))
|
|
470
|
-
},
|
|
471
|
-
entry: {
|
|
472
|
-
module: combineUrls.combineURLs(ctx.publicPath, resolveFileUrl.resolveFileUrl(ctx, ctx.entryClientFilePath)),
|
|
473
|
-
imports: []
|
|
474
|
-
},
|
|
475
|
-
routes
|
|
476
|
-
};
|
|
477
|
-
};
|
|
478
|
-
return [{
|
|
479
|
-
name: "react-router",
|
|
480
|
-
config: async (_viteUserConfig, _viteConfigEnv) => {
|
|
481
|
-
var _viteUserConfig$serve, _viteUserConfig$serve2, _viteUserConfig$build4, _viteUserConfig$build5, _viteUserConfig$build6;
|
|
482
|
-
// Preload Vite's ESM build up-front as soon as we're in an async context
|
|
483
|
-
await importViteEsmSync.preloadViteEsm();
|
|
484
|
-
// Ensure sync import of Vite works after async preload
|
|
485
|
-
let vite = importViteEsmSync.importViteEsmSync();
|
|
486
|
-
viteUserConfig = _viteUserConfig;
|
|
487
|
-
viteConfigEnv = _viteConfigEnv;
|
|
488
|
-
viteCommand = viteConfigEnv.command;
|
|
489
|
-
routesViteNodeContext = await viteNode.createContext({
|
|
490
|
-
root: viteUserConfig.root,
|
|
491
|
-
mode: viteConfigEnv.mode,
|
|
492
|
-
server: {
|
|
493
|
-
watch: viteCommand === "build" ? null : undefined
|
|
494
|
-
},
|
|
495
|
-
ssr: {
|
|
496
|
-
external: ssrExternals
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
await updatePluginContext();
|
|
500
|
-
Object.assign(process.env, vite.loadEnv(viteConfigEnv.mode, ctx.rootDirectory,
|
|
501
|
-
// We override default prefix of "VITE_" with a blank string since
|
|
502
|
-
// we're targeting the server, so we want to load all environment
|
|
503
|
-
// variables, not just those explicitly marked for the client
|
|
504
|
-
""));
|
|
505
|
-
let baseRollupOptions = {
|
|
506
|
-
// Silence Rollup "use client" warnings
|
|
507
|
-
// Adapted from https://github.com/vitejs/vite-plugin-react/pull/144
|
|
508
|
-
onwarn(warning, defaultHandler) {
|
|
509
|
-
var _viteUserConfig$build2, _viteUserConfig$build3;
|
|
510
|
-
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && warning.message.includes("use client")) {
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
if ((_viteUserConfig$build2 = viteUserConfig.build) !== null && _viteUserConfig$build2 !== void 0 && (_viteUserConfig$build3 = _viteUserConfig$build2.rollupOptions) !== null && _viteUserConfig$build3 !== void 0 && _viteUserConfig$build3.onwarn) {
|
|
514
|
-
viteUserConfig.build.rollupOptions.onwarn(warning, defaultHandler);
|
|
515
|
-
} else {
|
|
516
|
-
defaultHandler(warning);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
};
|
|
520
|
-
return {
|
|
521
|
-
__reactRouterPluginContext: ctx,
|
|
522
|
-
appType: viteCommand === "serve" && viteConfigEnv.mode === "production" && ctx.reactRouterConfig.ssr === false ? "spa" : "custom",
|
|
523
|
-
ssr: {
|
|
524
|
-
external: ssrExternals
|
|
525
|
-
},
|
|
526
|
-
optimizeDeps: {
|
|
527
|
-
include: [
|
|
528
|
-
// Pre-bundle React dependencies to avoid React duplicates,
|
|
529
|
-
// even if React dependencies are not direct dependencies.
|
|
530
|
-
// https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
|
|
531
|
-
"react", "react/jsx-runtime", "react/jsx-dev-runtime", "react-dom", "react-dom/client",
|
|
532
|
-
// Pre-bundle router dependencies to avoid router duplicates.
|
|
533
|
-
// Mismatching routers cause `Error: You must render this element inside a <Remix> element`.
|
|
534
|
-
"react-router",
|
|
535
|
-
// Check to avoid "Failed to resolve dependency: react-router-dom, present in 'optimizeDeps.include'"
|
|
536
|
-
...(hasDependency("react-router-dom") ? ["react-router-dom"] : [])]
|
|
537
|
-
},
|
|
538
|
-
esbuild: {
|
|
539
|
-
jsx: "automatic",
|
|
540
|
-
jsxDev: viteCommand !== "build"
|
|
541
|
-
},
|
|
542
|
-
resolve: {
|
|
543
|
-
dedupe: [
|
|
544
|
-
// https://react.dev/warnings/invalid-hook-call-warning#duplicate-react
|
|
545
|
-
"react", "react-dom",
|
|
546
|
-
// see description for `optimizeDeps.include`
|
|
547
|
-
"react-router", "react-router-dom"]
|
|
548
|
-
},
|
|
549
|
-
base: viteUserConfig.base,
|
|
550
|
-
// When consumer provides an allow list for files that can be read by
|
|
551
|
-
// the server, ensure that the default entry files are included.
|
|
552
|
-
// If we don't do this and a default entry file is used, the server
|
|
553
|
-
// will throw an error that the file is not allowed to be read.
|
|
554
|
-
// https://vitejs.dev/config/server-options#server-fs-allow
|
|
555
|
-
server: (_viteUserConfig$serve = viteUserConfig.server) !== null && _viteUserConfig$serve !== void 0 && (_viteUserConfig$serve2 = _viteUserConfig$serve.fs) !== null && _viteUserConfig$serve2 !== void 0 && _viteUserConfig$serve2.allow ? {
|
|
556
|
-
fs: {
|
|
557
|
-
allow: defaultEntries
|
|
558
|
-
}
|
|
559
|
-
} : undefined,
|
|
560
|
-
// Vite config options for building
|
|
561
|
-
...(viteCommand === "build" ? {
|
|
562
|
-
build: {
|
|
563
|
-
cssMinify: ((_viteUserConfig$build4 = viteUserConfig.build) === null || _viteUserConfig$build4 === void 0 ? void 0 : _viteUserConfig$build4.cssMinify) ?? true,
|
|
564
|
-
...(!viteConfigEnv.isSsrBuild ? {
|
|
565
|
-
manifest: true,
|
|
566
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig),
|
|
567
|
-
rollupOptions: {
|
|
568
|
-
...baseRollupOptions,
|
|
569
|
-
preserveEntrySignatures: "exports-only",
|
|
570
|
-
input: [ctx.entryClientFilePath, ...Object.values(ctx.reactRouterConfig.routes).map(route => `${path__namespace.resolve(ctx.reactRouterConfig.appDirectory, route.file)}${ROUTE_ENTRY_QUERY_STRING}`)]
|
|
571
|
-
}
|
|
572
|
-
} : {
|
|
573
|
-
// We move SSR-only assets to client assets. Note that the
|
|
574
|
-
// SSR build can also emit code-split JS files (e.g. by
|
|
575
|
-
// dynamic import) under the same assets directory
|
|
576
|
-
// regardless of "ssrEmitAssets" option, so we also need to
|
|
577
|
-
// keep these JS files have to be kept as-is.
|
|
578
|
-
ssrEmitAssets: true,
|
|
579
|
-
copyPublicDir: false,
|
|
580
|
-
// Assets in the public directory are only used by the client
|
|
581
|
-
manifest: true,
|
|
582
|
-
// We need the manifest to detect SSR-only assets
|
|
583
|
-
outDir: getServerBuildDirectory(ctx),
|
|
584
|
-
rollupOptions: {
|
|
585
|
-
...baseRollupOptions,
|
|
586
|
-
preserveEntrySignatures: "exports-only",
|
|
587
|
-
input: ((_viteUserConfig$build5 = viteUserConfig.build) === null || _viteUserConfig$build5 === void 0 ? void 0 : (_viteUserConfig$build6 = _viteUserConfig$build5.rollupOptions) === null || _viteUserConfig$build6 === void 0 ? void 0 : _viteUserConfig$build6.input) ?? serverBuildId,
|
|
588
|
-
output: {
|
|
589
|
-
entryFileNames: ctx.reactRouterConfig.serverBuildFile,
|
|
590
|
-
format: ctx.reactRouterConfig.serverModuleFormat
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
})
|
|
594
|
-
}
|
|
595
|
-
} : undefined),
|
|
596
|
-
// Vite config options for SPA preview mode
|
|
597
|
-
...(viteCommand === "serve" && ctx.reactRouterConfig.ssr === false ? {
|
|
598
|
-
build: {
|
|
599
|
-
manifest: true,
|
|
600
|
-
outDir: getClientBuildDirectory(ctx.reactRouterConfig)
|
|
601
|
-
}
|
|
602
|
-
} : undefined)
|
|
603
|
-
};
|
|
604
|
-
},
|
|
605
|
-
async configResolved(resolvedViteConfig) {
|
|
606
|
-
await esModuleLexer.init;
|
|
607
|
-
viteConfig = resolvedViteConfig;
|
|
608
|
-
invariant(viteConfig);
|
|
609
|
-
// We load the same Vite config file again for the child compiler so
|
|
610
|
-
// that both parent and child compiler's plugins have independent state.
|
|
611
|
-
// If we re-used the `viteUserConfig.plugins` array for the child
|
|
612
|
-
// compiler, it could lead to mutating shared state between plugin
|
|
613
|
-
// instances in unexpected ways, e.g. during `vite build` the
|
|
614
|
-
// `configResolved` plugin hook would be called with `command = "build"`
|
|
615
|
-
// by parent and then `command = "serve"` by child, which some plugins
|
|
616
|
-
// may respond to by updating state referenced by the parent.
|
|
617
|
-
if (!viteConfig.configFile) {
|
|
618
|
-
throw new Error("The React Router Vite plugin requires the use of a Vite config file");
|
|
619
|
-
}
|
|
620
|
-
let vite = importViteEsmSync.importViteEsmSync();
|
|
621
|
-
let childCompilerConfigFile = await vite.loadConfigFromFile({
|
|
622
|
-
command: viteConfig.command,
|
|
623
|
-
mode: viteConfig.mode,
|
|
624
|
-
isSsrBuild: ctx.isSsrBuild
|
|
625
|
-
}, viteConfig.configFile);
|
|
626
|
-
invariant(childCompilerConfigFile, "Vite config file was unable to be resolved for React Router child compiler");
|
|
627
|
-
// Validate that commonly used Rollup plugins that need to run before
|
|
628
|
-
// ours are in the correct order. This is because Rollup plugins can't
|
|
629
|
-
// set `enforce: "pre"` like Vite plugins can. Explicitly validating
|
|
630
|
-
// this provides a much nicer developer experience.
|
|
631
|
-
let rollupPrePlugins = [{
|
|
632
|
-
pluginName: "@mdx-js/rollup",
|
|
633
|
-
displayName: "@mdx-js/rollup"
|
|
634
|
-
}];
|
|
635
|
-
for (let prePlugin of rollupPrePlugins) {
|
|
636
|
-
let prePluginIndex = pluginIndex(prePlugin.pluginName);
|
|
637
|
-
if (prePluginIndex >= 0 && prePluginIndex > pluginIndex("react-router")) {
|
|
638
|
-
throw new Error(`The "${prePlugin.displayName}" plugin should be placed before the React Router plugin in your Vite config file`);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
viteChildCompiler = await vite.createServer({
|
|
642
|
-
...viteUserConfig,
|
|
643
|
-
mode: viteConfig.mode,
|
|
644
|
-
server: {
|
|
645
|
-
watch: viteConfig.command === "build" ? null : undefined,
|
|
646
|
-
preTransformRequests: false,
|
|
647
|
-
hmr: false
|
|
648
|
-
},
|
|
649
|
-
configFile: false,
|
|
650
|
-
envFile: false,
|
|
651
|
-
plugins: [...(childCompilerConfigFile.config.plugins ?? []).flat()
|
|
652
|
-
// Exclude this plugin from the child compiler to prevent an
|
|
653
|
-
// infinite loop (plugin creates a child compiler with the same
|
|
654
|
-
// plugin that creates another child compiler, repeat ad
|
|
655
|
-
// infinitum), and to prevent the manifest from being written to
|
|
656
|
-
// disk from the child compiler. This is important in the
|
|
657
|
-
// production build because the child compiler is a Vite dev
|
|
658
|
-
// server and will generate incorrect manifests.
|
|
659
|
-
.filter(plugin => typeof plugin === "object" && plugin !== null && "name" in plugin && plugin.name !== "react-router" && plugin.name !== "react-router-route-exports" && plugin.name !== "react-router-hmr-updates")]
|
|
660
|
-
});
|
|
661
|
-
await viteChildCompiler.pluginContainer.buildStart({});
|
|
662
|
-
},
|
|
663
|
-
async transform(code, id) {
|
|
664
|
-
if (styles.isCssModulesFile(id)) {
|
|
665
|
-
cssModulesManifest[id] = code;
|
|
666
|
-
}
|
|
667
|
-
},
|
|
668
|
-
buildStart() {
|
|
669
|
-
invariant(viteConfig);
|
|
670
|
-
if (viteCommand === "build" && viteConfig.mode === "production" && !viteConfig.build.ssr && viteConfig.build.sourcemap) {
|
|
671
|
-
viteConfig.logger.warn(colors__default["default"].yellow("\n" + colors__default["default"].bold(" ⚠️ Source maps are enabled in production\n") + ["This makes your server code publicly", "visible in the browser. This is highly", "discouraged! If you insist, ensure that", "you are using environment variables for", "secrets and not hard-coding them in", "your source code."].map(line => " " + line).join("\n") + "\n"));
|
|
672
|
-
}
|
|
673
|
-
},
|
|
674
|
-
async configureServer(viteDevServer) {
|
|
675
|
-
reactRouter.unstable_setDevServerHooks({
|
|
676
|
-
// Give the request handler access to the critical CSS in dev to avoid a
|
|
677
|
-
// flash of unstyled content since Vite injects CSS file contents via JS
|
|
678
|
-
getCriticalCss: async (build, url) => {
|
|
679
|
-
return styles.getStylesForUrl({
|
|
680
|
-
rootDirectory: ctx.rootDirectory,
|
|
681
|
-
entryClientFilePath: ctx.entryClientFilePath,
|
|
682
|
-
reactRouterConfig: ctx.reactRouterConfig,
|
|
683
|
-
viteDevServer,
|
|
684
|
-
cssModulesManifest,
|
|
685
|
-
build,
|
|
686
|
-
url
|
|
687
|
-
});
|
|
688
|
-
},
|
|
689
|
-
// If an error is caught within the request handler, let Vite fix the
|
|
690
|
-
// stack trace so it maps back to the actual source code
|
|
691
|
-
processRequestError: error => {
|
|
692
|
-
if (error instanceof Error) {
|
|
693
|
-
viteDevServer.ssrFixStacktrace(error);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
// Invalidate virtual modules and update cached plugin config via file watcher
|
|
698
|
-
viteDevServer.watcher.on("all", async (eventName, rawFilepath) => {
|
|
699
|
-
var _viteConfig, _routesViteNodeContex, _routesViteNodeContex2;
|
|
700
|
-
let {
|
|
701
|
-
normalizePath
|
|
702
|
-
} = importViteEsmSync.importViteEsmSync();
|
|
703
|
-
let filepath = normalizePath(rawFilepath);
|
|
704
|
-
let appFileAddedOrRemoved = (eventName === "add" || eventName === "unlink") && filepath.startsWith(normalizePath(ctx.reactRouterConfig.appDirectory));
|
|
705
|
-
invariant((_viteConfig = viteConfig) === null || _viteConfig === void 0 ? void 0 : _viteConfig.configFile);
|
|
706
|
-
let viteConfigChanged = eventName === "change" && filepath === normalizePath(viteConfig.configFile);
|
|
707
|
-
let routeConfigChanged = Boolean((_routesViteNodeContex = routesViteNodeContext) === null || _routesViteNodeContex === void 0 ? void 0 : (_routesViteNodeContex2 = _routesViteNodeContex.devServer) === null || _routesViteNodeContex2 === void 0 ? void 0 : _routesViteNodeContex2.moduleGraph.getModuleById(filepath));
|
|
708
|
-
if (routeConfigChanged || appFileAddedOrRemoved) {
|
|
709
|
-
var _routesViteNodeContex3, _routesViteNodeContex4, _routesViteNodeContex5, _routesViteNodeContex6;
|
|
710
|
-
(_routesViteNodeContex3 = routesViteNodeContext) === null || _routesViteNodeContex3 === void 0 ? void 0 : (_routesViteNodeContex4 = _routesViteNodeContex3.devServer) === null || _routesViteNodeContex4 === void 0 ? void 0 : _routesViteNodeContex4.moduleGraph.invalidateAll();
|
|
711
|
-
(_routesViteNodeContex5 = routesViteNodeContext) === null || _routesViteNodeContex5 === void 0 ? void 0 : (_routesViteNodeContex6 = _routesViteNodeContex5.runner) === null || _routesViteNodeContex6 === void 0 ? void 0 : _routesViteNodeContex6.moduleCache.clear();
|
|
712
|
-
}
|
|
713
|
-
if (appFileAddedOrRemoved || viteConfigChanged || routeConfigChanged) {
|
|
714
|
-
let lastReactRouterConfig = ctx.reactRouterConfig;
|
|
715
|
-
await updatePluginContext({
|
|
716
|
-
routeConfigChanged
|
|
717
|
-
});
|
|
718
|
-
if (!isEqualJson(lastReactRouterConfig, ctx.reactRouterConfig)) {
|
|
719
|
-
invalidateVirtualModules(viteDevServer);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
});
|
|
723
|
-
return () => {
|
|
724
|
-
// Let user servers handle SSR requests in middleware mode,
|
|
725
|
-
// otherwise the Vite plugin will handle the request
|
|
726
|
-
if (!viteDevServer.config.server.middlewareMode) {
|
|
727
|
-
viteDevServer.middlewares.use(async (req, res, next) => {
|
|
728
|
-
try {
|
|
729
|
-
let build = await viteDevServer.ssrLoadModule(serverBuildId);
|
|
730
|
-
let handler = reactRouter.createRequestHandler(build, "development");
|
|
731
|
-
let nodeHandler = async (nodeReq, nodeRes) => {
|
|
732
|
-
let req = nodeAdapter.fromNodeRequest(nodeReq, nodeRes);
|
|
733
|
-
let res = await handler(req, await reactRouterDevLoadContext(req));
|
|
734
|
-
await nodeAdapter.toNodeRequest(res, nodeRes);
|
|
735
|
-
};
|
|
736
|
-
await nodeHandler(req, res);
|
|
737
|
-
} catch (error) {
|
|
738
|
-
next(error);
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
},
|
|
744
|
-
writeBundle: {
|
|
745
|
-
// After the SSR build is finished, we inspect the Vite manifest for
|
|
746
|
-
// the SSR build and move server-only assets to client assets directory
|
|
747
|
-
async handler() {
|
|
748
|
-
if (!ctx.isSsrBuild) {
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
invariant(viteConfig);
|
|
752
|
-
let clientBuildDirectory = getClientBuildDirectory(ctx.reactRouterConfig);
|
|
753
|
-
let serverBuildDirectory = getServerBuildDirectory(ctx);
|
|
754
|
-
let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
|
|
755
|
-
let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
|
|
756
|
-
// We only move assets that aren't in the client build, otherwise we
|
|
757
|
-
// remove them. These assets only exist because we explicitly set
|
|
758
|
-
// `ssrEmitAssets: true` in the SSR Vite config. These assets
|
|
759
|
-
// typically wouldn't exist by default, which is why we assume it's
|
|
760
|
-
// safe to remove them. We're aiming for a clean build output so that
|
|
761
|
-
// unnecessary assets don't get deployed alongside the server code.
|
|
762
|
-
let movedAssetPaths = [];
|
|
763
|
-
for (let ssrAssetPath of ssrAssetPaths) {
|
|
764
|
-
let src = path__namespace.join(serverBuildDirectory, ssrAssetPath);
|
|
765
|
-
let dest = path__namespace.join(clientBuildDirectory, ssrAssetPath);
|
|
766
|
-
if (!fse__namespace.existsSync(dest)) {
|
|
767
|
-
await fse__namespace.move(src, dest);
|
|
768
|
-
movedAssetPaths.push(dest);
|
|
769
|
-
} else {
|
|
770
|
-
await fse__namespace.remove(src);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
// We assume CSS assets from the SSR build are unnecessary and remove
|
|
774
|
-
// them for the same reasons as above.
|
|
775
|
-
let ssrCssPaths = Object.values(ssrViteManifest).flatMap(chunk => chunk.css ?? []);
|
|
776
|
-
await Promise.all(ssrCssPaths.map(cssPath => fse__namespace.remove(path__namespace.join(serverBuildDirectory, cssPath))));
|
|
777
|
-
if (movedAssetPaths.length) {
|
|
778
|
-
viteConfig.logger.info(["", `${colors__default["default"].green("✓")} ${movedAssetPaths.length} asset${movedAssetPaths.length > 1 ? "s" : ""} moved from React Router server build to client assets.`, ...movedAssetPaths.map(movedAssetPath => colors__default["default"].dim(path__namespace.relative(ctx.rootDirectory, movedAssetPath))), ""].join("\n"));
|
|
779
|
-
}
|
|
780
|
-
if (ctx.reactRouterConfig.prerender != null && ctx.reactRouterConfig.prerender !== false) {
|
|
781
|
-
// If we have prerender routes, that takes precedence over SPA mode
|
|
782
|
-
// which is ssr:false and only the rot route being rendered
|
|
783
|
-
await handlePrerender(viteConfig, ctx.reactRouterConfig, serverBuildDirectory, clientBuildDirectory);
|
|
784
|
-
} else if (!ctx.reactRouterConfig.ssr) {
|
|
785
|
-
await handleSpaMode(viteConfig, ctx.reactRouterConfig, serverBuildDirectory, clientBuildDirectory);
|
|
786
|
-
}
|
|
787
|
-
// For both SPA mode and prerendering, we can remove the server builds
|
|
788
|
-
// if ssr:false is set
|
|
789
|
-
if (!ctx.reactRouterConfig.ssr) {
|
|
790
|
-
// Cleanup - we no longer need the server build assets
|
|
791
|
-
viteConfig.logger.info(["Removing the server build in", colors__default["default"].green(serverBuildDirectory), "due to ssr:false"].join(" "));
|
|
792
|
-
fse__namespace.removeSync(serverBuildDirectory);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
},
|
|
796
|
-
async buildEnd() {
|
|
797
|
-
var _viteChildCompiler, _routesViteNodeContex7, _routesViteNodeContex8;
|
|
798
|
-
await ((_viteChildCompiler = viteChildCompiler) === null || _viteChildCompiler === void 0 ? void 0 : _viteChildCompiler.close());
|
|
799
|
-
await ((_routesViteNodeContex7 = routesViteNodeContext) === null || _routesViteNodeContex7 === void 0 ? void 0 : (_routesViteNodeContex8 = _routesViteNodeContex7.devServer) === null || _routesViteNodeContex8 === void 0 ? void 0 : _routesViteNodeContex8.close());
|
|
800
|
-
}
|
|
801
|
-
}, {
|
|
802
|
-
name: "react-router-route-entry",
|
|
803
|
-
enforce: "pre",
|
|
804
|
-
async transform(_code, id, options) {
|
|
805
|
-
if (!isRouteEntry(id)) return;
|
|
806
|
-
let routeModuleId = id.replace(ROUTE_ENTRY_QUERY_STRING, "");
|
|
807
|
-
let routeFileName = path__namespace.basename(routeModuleId);
|
|
808
|
-
let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, routeModuleId);
|
|
809
|
-
let reexports = sourceExports.filter(exportName => (options === null || options === void 0 ? void 0 : options.ssr) && SERVER_ONLY_ROUTE_EXPORTS.includes(exportName) || CLIENT_ROUTE_EXPORTS.includes(exportName)).join(", ");
|
|
810
|
-
return `export { ${reexports} } from "./${routeFileName}";`;
|
|
811
|
-
}
|
|
812
|
-
}, {
|
|
813
|
-
name: "react-router-virtual-modules",
|
|
814
|
-
enforce: "pre",
|
|
815
|
-
resolveId(id) {
|
|
816
|
-
if (vmods.includes(id)) return vmod.resolve(id);
|
|
817
|
-
},
|
|
818
|
-
async load(id) {
|
|
819
|
-
switch (id) {
|
|
820
|
-
case vmod.resolve(serverBuildId):
|
|
821
|
-
{
|
|
822
|
-
return await getServerEntry();
|
|
823
|
-
}
|
|
824
|
-
case vmod.resolve(serverManifestId):
|
|
825
|
-
{
|
|
826
|
-
let reactRouterManifest = ctx.isSsrBuild ? await ctx.getReactRouterServerManifest() : await getReactRouterManifestForDev();
|
|
827
|
-
return `export default ${jsesc__default["default"](reactRouterManifest, {
|
|
828
|
-
es6: true
|
|
829
|
-
})};`;
|
|
830
|
-
}
|
|
831
|
-
case vmod.resolve(browserManifestId):
|
|
832
|
-
{
|
|
833
|
-
if (viteCommand === "build") {
|
|
834
|
-
throw new Error("This module only exists in development");
|
|
835
|
-
}
|
|
836
|
-
let reactRouterManifest = await getReactRouterManifestForDev();
|
|
837
|
-
let reactRouterManifestString = jsesc__default["default"](reactRouterManifest, {
|
|
838
|
-
es6: true
|
|
839
|
-
});
|
|
840
|
-
return `window.__reactRouterManifest=${reactRouterManifestString};`;
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
}, {
|
|
845
|
-
name: "react-router-dot-server",
|
|
846
|
-
enforce: "pre",
|
|
847
|
-
async resolveId(id, importer, options) {
|
|
848
|
-
var _options$custom;
|
|
849
|
-
// https://vitejs.dev/config/dep-optimization-options
|
|
850
|
-
let isOptimizeDeps = viteCommand === "serve" && (options === null || options === void 0 ? void 0 : options.scan) === true;
|
|
851
|
-
if (isOptimizeDeps || options !== null && options !== void 0 && options.ssr) return;
|
|
852
|
-
let isResolving = (options === null || options === void 0 ? void 0 : (_options$custom = options.custom) === null || _options$custom === void 0 ? void 0 : _options$custom["react-router-dot-server"]) ?? false;
|
|
853
|
-
if (isResolving) return;
|
|
854
|
-
options.custom = {
|
|
855
|
-
...options.custom,
|
|
856
|
-
"react-router-dot-server": true
|
|
857
|
-
};
|
|
858
|
-
let resolved = await this.resolve(id, importer, options);
|
|
859
|
-
if (!resolved) return;
|
|
860
|
-
let serverFileRE = /\.server(\.[cm]?[jt]sx?)?$/;
|
|
861
|
-
let serverDirRE = /\/\.server\//;
|
|
862
|
-
let isDotServer = serverFileRE.test(resolved.id) || serverDirRE.test(resolved.id);
|
|
863
|
-
if (!isDotServer) return;
|
|
864
|
-
if (!importer) return;
|
|
865
|
-
if (viteCommand !== "build" && importer.endsWith(".html")) {
|
|
866
|
-
// Vite has a special `index.html` importer for `resolveId` within `transformRequest`
|
|
867
|
-
// https://github.com/vitejs/vite/blob/5684fcd8d27110d098b3e1c19d851f44251588f1/packages/vite/src/node/server/transformRequest.ts#L158
|
|
868
|
-
// https://github.com/vitejs/vite/blob/5684fcd8d27110d098b3e1c19d851f44251588f1/packages/vite/src/node/server/pluginContainer.ts#L668
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
let vite = importViteEsmSync.importViteEsmSync();
|
|
872
|
-
let importerShort = vite.normalizePath(path__namespace.relative(ctx.rootDirectory, importer));
|
|
873
|
-
let isRoute = getRoute(ctx.reactRouterConfig, importer);
|
|
874
|
-
if (isRoute) {
|
|
875
|
-
let serverOnlyExports = SERVER_ONLY_ROUTE_EXPORTS.map(xport => `\`${xport}\``).join(", ");
|
|
876
|
-
throw Error([colors__default["default"].red(`Server-only module referenced by client`), "", ` '${id}' imported by route '${importerShort}'`, "", ` React Router automatically removes server-code from these exports:`, ` ${serverOnlyExports}`, "", ` But other route exports in '${importerShort}' depend on '${id}'.`, "", " See https://remix.run/docs/en/main/guides/vite#splitting-up-client-and-server-code", ""].join("\n"));
|
|
877
|
-
}
|
|
878
|
-
throw Error([colors__default["default"].red(`Server-only module referenced by client`), "", ` '${id}' imported by '${importerShort}'`, "", " See https://remix.run/docs/en/main/guides/vite#splitting-up-client-and-server-code", ""].join("\n"));
|
|
879
|
-
}
|
|
880
|
-
}, {
|
|
881
|
-
name: "react-router-dot-client",
|
|
882
|
-
async transform(code, id, options) {
|
|
883
|
-
if (!(options !== null && options !== void 0 && options.ssr)) return;
|
|
884
|
-
let clientFileRE = /\.client(\.[cm]?[jt]sx?)?$/;
|
|
885
|
-
let clientDirRE = /\/\.client\//;
|
|
886
|
-
if (clientFileRE.test(id) || clientDirRE.test(id)) {
|
|
887
|
-
let exports = esModuleLexer.parse(code)[1];
|
|
888
|
-
return {
|
|
889
|
-
code: exports.map(({
|
|
890
|
-
n: name
|
|
891
|
-
}) => name === "default" ? "export default undefined;" : `export const ${name} = undefined;`).join("\n"),
|
|
892
|
-
map: null
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
}, withProps.plugin, {
|
|
897
|
-
name: "react-router-route-exports",
|
|
898
|
-
async transform(code, id, options) {
|
|
899
|
-
let route = getRoute(ctx.reactRouterConfig, id);
|
|
900
|
-
if (!route) return;
|
|
901
|
-
if (!(options !== null && options !== void 0 && options.ssr) && !ctx.reactRouterConfig.ssr) {
|
|
902
|
-
let serverOnlyExports = esModuleLexer.parse(code)[1].map(exp => exp.n).filter(exp => SERVER_ONLY_ROUTE_EXPORTS.includes(exp));
|
|
903
|
-
if (serverOnlyExports.length > 0) {
|
|
904
|
-
let str = serverOnlyExports.map(e => `\`${e}\``).join(", ");
|
|
905
|
-
let message = `SPA Mode: ${serverOnlyExports.length} invalid route export(s) in ` + `\`${route.file}\`: ${str}. See https://remix.run/guides/spa-mode ` + `for more information.`;
|
|
906
|
-
throw Error(message);
|
|
907
|
-
}
|
|
908
|
-
if (route.id !== "root") {
|
|
909
|
-
let hasHydrateFallback = esModuleLexer.parse(code)[1].map(exp => exp.n).some(exp => exp === "HydrateFallback");
|
|
910
|
-
if (hasHydrateFallback) {
|
|
911
|
-
let message = `SPA Mode: Invalid \`HydrateFallback\` export found in ` + `\`${route.file}\`. \`HydrateFallback\` is only permitted on ` + `the root route in SPA Mode. See https://remix.run/guides/spa-mode ` + `for more information.`;
|
|
912
|
-
throw Error(message);
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
let [filepath] = id.split("?");
|
|
917
|
-
let ast = parser.parse(code, {
|
|
918
|
-
sourceType: "module"
|
|
919
|
-
});
|
|
920
|
-
if (!(options !== null && options !== void 0 && options.ssr)) {
|
|
921
|
-
removeExports.removeExports(ast, SERVER_ONLY_ROUTE_EXPORTS);
|
|
922
|
-
}
|
|
923
|
-
withProps.transform(ast);
|
|
924
|
-
return babel.generate(ast, {
|
|
925
|
-
sourceMaps: true,
|
|
926
|
-
filename: id,
|
|
927
|
-
sourceFileName: filepath
|
|
928
|
-
});
|
|
929
|
-
}
|
|
930
|
-
}, {
|
|
931
|
-
name: "react-router-inject-hmr-runtime",
|
|
932
|
-
enforce: "pre",
|
|
933
|
-
resolveId(id) {
|
|
934
|
-
if (id === injectHmrRuntimeId) return vmod.resolve(injectHmrRuntimeId);
|
|
935
|
-
},
|
|
936
|
-
async load(id) {
|
|
937
|
-
if (id !== vmod.resolve(injectHmrRuntimeId)) return;
|
|
938
|
-
return [`import RefreshRuntime from "${hmrRuntimeId}"`, "RefreshRuntime.injectIntoGlobalHook(window)", "window.$RefreshReg$ = () => {}", "window.$RefreshSig$ = () => (type) => type", "window.__vite_plugin_react_preamble_installed__ = true"].join("\n");
|
|
939
|
-
}
|
|
940
|
-
}, {
|
|
941
|
-
name: "react-router-hmr-runtime",
|
|
942
|
-
enforce: "pre",
|
|
943
|
-
resolveId(id) {
|
|
944
|
-
if (id === hmrRuntimeId) return vmod.resolve(hmrRuntimeId);
|
|
945
|
-
},
|
|
946
|
-
async load(id) {
|
|
947
|
-
if (id !== vmod.resolve(hmrRuntimeId)) return;
|
|
948
|
-
let reactRefreshDir = path__namespace.dirname(require.resolve("react-refresh/package.json"));
|
|
949
|
-
let reactRefreshRuntimePath = path__namespace.join(reactRefreshDir, "cjs/react-refresh-runtime.development.js");
|
|
950
|
-
return ["const exports = {}", await fse__namespace.readFile(reactRefreshRuntimePath, "utf8"), await fse__namespace.readFile(require.resolve("./static/refresh-utils.cjs"), "utf8"), "export default exports"].join("\n");
|
|
951
|
-
}
|
|
952
|
-
}, {
|
|
953
|
-
name: "react-router-react-refresh-babel",
|
|
954
|
-
async transform(code, id, options) {
|
|
955
|
-
if (viteCommand !== "serve") return;
|
|
956
|
-
if (id.includes("/node_modules/")) return;
|
|
957
|
-
let [filepath] = id.split("?");
|
|
958
|
-
let extensionsRE = /\.(jsx?|tsx?|mdx?)$/;
|
|
959
|
-
if (!extensionsRE.test(filepath)) return;
|
|
960
|
-
let devRuntime = "react/jsx-dev-runtime";
|
|
961
|
-
let ssr = (options === null || options === void 0 ? void 0 : options.ssr) === true;
|
|
962
|
-
let isJSX = filepath.endsWith("x");
|
|
963
|
-
let useFastRefresh = !ssr && (isJSX || code.includes(devRuntime));
|
|
964
|
-
if (!useFastRefresh) return;
|
|
965
|
-
if (isRouteEntry(id)) {
|
|
966
|
-
return {
|
|
967
|
-
code: addRefreshWrapper(ctx.reactRouterConfig, code, id)
|
|
968
|
-
};
|
|
969
|
-
}
|
|
970
|
-
let result = await babel__default["default"].transformAsync(code, {
|
|
971
|
-
babelrc: false,
|
|
972
|
-
configFile: false,
|
|
973
|
-
filename: id,
|
|
974
|
-
sourceFileName: filepath,
|
|
975
|
-
parserOpts: {
|
|
976
|
-
sourceType: "module",
|
|
977
|
-
allowAwaitOutsideFunction: true
|
|
978
|
-
},
|
|
979
|
-
plugins: [[require("react-refresh/babel"), {
|
|
980
|
-
skipEnvCheck: true
|
|
981
|
-
}]],
|
|
982
|
-
sourceMaps: true
|
|
983
|
-
});
|
|
984
|
-
if (result === null) return;
|
|
985
|
-
code = result.code;
|
|
986
|
-
let refreshContentRE = /\$Refresh(?:Reg|Sig)\$\(/;
|
|
987
|
-
if (refreshContentRE.test(code)) {
|
|
988
|
-
code = addRefreshWrapper(ctx.reactRouterConfig, code, id);
|
|
989
|
-
}
|
|
990
|
-
return {
|
|
991
|
-
code,
|
|
992
|
-
map: result.map
|
|
993
|
-
};
|
|
994
|
-
}
|
|
995
|
-
}, {
|
|
996
|
-
name: "react-router-hmr-updates",
|
|
997
|
-
async handleHotUpdate({
|
|
998
|
-
server,
|
|
999
|
-
file,
|
|
1000
|
-
modules,
|
|
1001
|
-
read
|
|
1002
|
-
}) {
|
|
1003
|
-
let route = getRoute(ctx.reactRouterConfig, file);
|
|
1004
|
-
let hmrEventData = {
|
|
1005
|
-
route: null
|
|
1006
|
-
};
|
|
1007
|
-
if (route) {
|
|
1008
|
-
// invalidate manifest on route exports change
|
|
1009
|
-
let serverManifest = (await server.ssrLoadModule(serverManifestId)).default;
|
|
1010
|
-
let oldRouteMetadata = serverManifest.routes[route.id];
|
|
1011
|
-
let newRouteMetadata = await getRouteMetadata(ctx, viteChildCompiler, route, read);
|
|
1012
|
-
hmrEventData.route = newRouteMetadata;
|
|
1013
|
-
if (!oldRouteMetadata || ["hasLoader", "hasClientLoader", "hasAction", "hasClientAction", "hasErrorBoundary"].some(key => oldRouteMetadata[key] !== newRouteMetadata[key])) {
|
|
1014
|
-
invalidateVirtualModules(server);
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
server.hot.send({
|
|
1018
|
-
type: "custom",
|
|
1019
|
-
event: "react-router:hmr",
|
|
1020
|
-
data: hmrEventData
|
|
1021
|
-
});
|
|
1022
|
-
return modules;
|
|
1023
|
-
}
|
|
1024
|
-
}];
|
|
1025
|
-
};
|
|
1026
|
-
function findConfig(dir, basename, extensions) {
|
|
1027
|
-
for (let ext of extensions) {
|
|
1028
|
-
let name = basename + ext;
|
|
1029
|
-
let file = path__namespace.join(dir, name);
|
|
1030
|
-
if (fse__namespace.existsSync(file)) return file;
|
|
1031
|
-
}
|
|
1032
|
-
return undefined;
|
|
1033
|
-
}
|
|
1034
|
-
function isInReactRouterMonorepo() {
|
|
1035
|
-
// We use '@react-router/node' for this check since it's a
|
|
1036
|
-
// dependency of this package and guaranteed to be in node_modules
|
|
1037
|
-
let serverRuntimePath = path__namespace.dirname(require.resolve("@react-router/node/package.json"));
|
|
1038
|
-
let serverRuntimeParentDir = path__namespace.basename(path__namespace.resolve(serverRuntimePath, ".."));
|
|
1039
|
-
return serverRuntimeParentDir === "packages";
|
|
1040
|
-
}
|
|
1041
|
-
function isEqualJson(v1, v2) {
|
|
1042
|
-
return JSON.stringify(v1) === JSON.stringify(v2);
|
|
1043
|
-
}
|
|
1044
|
-
function addRefreshWrapper(reactRouterConfig, code, id) {
|
|
1045
|
-
let route = getRoute(reactRouterConfig, id);
|
|
1046
|
-
let acceptExports = route || isRouteEntry(id) ? ["clientAction", "clientLoader", "handle", "meta", "links", "shouldRevalidate"] : [];
|
|
1047
|
-
return "\n\n" + withCommentBoundaries("REACT REFRESH HEADER", REACT_REFRESH_HEADER.replaceAll("__SOURCE__", JSON.stringify(id))) + "\n\n" + withCommentBoundaries("REACT REFRESH BODY", code) + "\n\n" + withCommentBoundaries("REACT REFRESH FOOTER", REACT_REFRESH_FOOTER.replaceAll("__SOURCE__", JSON.stringify(id)).replaceAll("__ACCEPT_EXPORTS__", JSON.stringify(acceptExports)).replaceAll("__ROUTE_ID__", JSON.stringify(route === null || route === void 0 ? void 0 : route.id))) + "\n";
|
|
1048
|
-
}
|
|
1049
|
-
function withCommentBoundaries(label, text) {
|
|
1050
|
-
let begin = `// [BEGIN] ${label} `;
|
|
1051
|
-
begin += "-".repeat(80 - begin.length);
|
|
1052
|
-
let end = `// [END] ${label} `;
|
|
1053
|
-
end += "-".repeat(80 - end.length);
|
|
1054
|
-
return `${begin}\n${text}\n${end}`;
|
|
1055
|
-
}
|
|
1056
|
-
const REACT_REFRESH_HEADER = `
|
|
1057
|
-
import RefreshRuntime from "${hmrRuntimeId}";
|
|
1058
|
-
|
|
1059
|
-
const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
|
|
1060
|
-
let prevRefreshReg;
|
|
1061
|
-
let prevRefreshSig;
|
|
1062
|
-
|
|
1063
|
-
if (import.meta.hot && !inWebWorker) {
|
|
1064
|
-
if (!window.__vite_plugin_react_preamble_installed__) {
|
|
1065
|
-
throw new Error(
|
|
1066
|
-
"React Router Vite plugin can't detect preamble. Something is wrong."
|
|
1067
|
-
);
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
prevRefreshReg = window.$RefreshReg$;
|
|
1071
|
-
prevRefreshSig = window.$RefreshSig$;
|
|
1072
|
-
window.$RefreshReg$ = (type, id) => {
|
|
1073
|
-
RefreshRuntime.register(type, __SOURCE__ + " " + id)
|
|
1074
|
-
};
|
|
1075
|
-
window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
|
|
1076
|
-
}`.trim();
|
|
1077
|
-
const REACT_REFRESH_FOOTER = `
|
|
1078
|
-
if (import.meta.hot && !inWebWorker) {
|
|
1079
|
-
window.$RefreshReg$ = prevRefreshReg;
|
|
1080
|
-
window.$RefreshSig$ = prevRefreshSig;
|
|
1081
|
-
RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
|
|
1082
|
-
RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
|
|
1083
|
-
import.meta.hot.accept((nextExports) => {
|
|
1084
|
-
if (!nextExports) return;
|
|
1085
|
-
__ROUTE_ID__ && window.__reactRouterRouteModuleUpdates.set(__ROUTE_ID__, nextExports);
|
|
1086
|
-
const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(currentExports, nextExports, __ACCEPT_EXPORTS__);
|
|
1087
|
-
if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
|
|
1088
|
-
});
|
|
1089
|
-
});
|
|
1090
|
-
}`.trim();
|
|
1091
|
-
function getRoute(pluginConfig, file) {
|
|
1092
|
-
let vite = importViteEsmSync.importViteEsmSync();
|
|
1093
|
-
let routePath = vite.normalizePath(path__namespace.relative(pluginConfig.appDirectory, file));
|
|
1094
|
-
let route = Object.values(pluginConfig.routes).find(r => vite.normalizePath(r.file) === routePath);
|
|
1095
|
-
return route;
|
|
1096
|
-
}
|
|
1097
|
-
async function getRouteMetadata(ctx, viteChildCompiler, route, readRouteFile) {
|
|
1098
|
-
let sourceExports = await getRouteModuleExports(viteChildCompiler, ctx, route.file, readRouteFile);
|
|
1099
|
-
let info = {
|
|
1100
|
-
id: route.id,
|
|
1101
|
-
parentId: route.parentId,
|
|
1102
|
-
path: route.path,
|
|
1103
|
-
index: route.index,
|
|
1104
|
-
caseSensitive: route.caseSensitive,
|
|
1105
|
-
url: combineUrls.combineURLs(ctx.publicPath, "/" + path__namespace.relative(ctx.rootDirectory, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))),
|
|
1106
|
-
module: combineUrls.combineURLs(ctx.publicPath, `${resolveFileUrl.resolveFileUrl(ctx, resolveRelativeRouteFilePath(route, ctx.reactRouterConfig))}?import`),
|
|
1107
|
-
// Ensure the Vite dev server responds with a JS module
|
|
1108
|
-
hasAction: sourceExports.includes("action"),
|
|
1109
|
-
hasClientAction: sourceExports.includes("clientAction"),
|
|
1110
|
-
hasLoader: sourceExports.includes("loader"),
|
|
1111
|
-
hasClientLoader: sourceExports.includes("clientLoader"),
|
|
1112
|
-
hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
|
|
1113
|
-
imports: []
|
|
1114
|
-
};
|
|
1115
|
-
return info;
|
|
1116
|
-
}
|
|
1117
|
-
async function getPrerenderBuildAndHandler(viteConfig, reactRouterConfig, serverBuildDirectory) {
|
|
1118
|
-
let serverBuildPath = path__namespace.join(serverBuildDirectory, reactRouterConfig.serverBuildFile);
|
|
1119
|
-
let build = await import(url__namespace.pathToFileURL(serverBuildPath).toString());
|
|
1120
|
-
let {
|
|
1121
|
-
createRequestHandler: createHandler
|
|
1122
|
-
} = await import('react-router');
|
|
1123
|
-
return {
|
|
1124
|
-
build,
|
|
1125
|
-
handler: createHandler(build, viteConfig.mode)
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory, clientBuildDirectory) {
|
|
1129
|
-
let {
|
|
1130
|
-
handler
|
|
1131
|
-
} = await getPrerenderBuildAndHandler(viteConfig, reactRouterConfig, serverBuildDirectory);
|
|
1132
|
-
let request = new Request(`http://localhost${reactRouterConfig.basename}`);
|
|
1133
|
-
let response = await handler(request);
|
|
1134
|
-
let html = await response.text();
|
|
1135
|
-
validatePrerenderedResponse(response, html, "SPA Mode", "/");
|
|
1136
|
-
validatePrerenderedHtml(html, "SPA Mode");
|
|
1137
|
-
// Write out the index.html file for the SPA
|
|
1138
|
-
await fse__namespace.writeFile(path__namespace.join(clientBuildDirectory, "index.html"), html);
|
|
1139
|
-
viteConfig.logger.info("SPA Mode: index.html has been written to your " + colors__default["default"].bold(path__namespace.relative(process.cwd(), clientBuildDirectory)) + " directory");
|
|
1140
|
-
}
|
|
1141
|
-
async function handlePrerender(viteConfig, reactRouterConfig, serverBuildDirectory, clientBuildDirectory) {
|
|
1142
|
-
let {
|
|
1143
|
-
build,
|
|
1144
|
-
handler
|
|
1145
|
-
} = await getPrerenderBuildAndHandler(viteConfig, reactRouterConfig, serverBuildDirectory);
|
|
1146
|
-
let routes = createPrerenderRoutes(build.routes);
|
|
1147
|
-
let routesToPrerender;
|
|
1148
|
-
if (typeof reactRouterConfig.prerender === "boolean") {
|
|
1149
|
-
invariant(reactRouterConfig.prerender, "Expected prerender:true");
|
|
1150
|
-
routesToPrerender = determineStaticPrerenderRoutes(routes, viteConfig, true);
|
|
1151
|
-
} else if (typeof reactRouterConfig.prerender === "function") {
|
|
1152
|
-
routesToPrerender = await reactRouterConfig.prerender({
|
|
1153
|
-
getStaticPaths: () => determineStaticPrerenderRoutes(routes, viteConfig, false)
|
|
1154
|
-
});
|
|
1155
|
-
} else {
|
|
1156
|
-
routesToPrerender = reactRouterConfig.prerender || ["/"];
|
|
1157
|
-
}
|
|
1158
|
-
let headers = {
|
|
1159
|
-
// Header that can be used in the loader to know if you're running at
|
|
1160
|
-
// build time or runtime
|
|
1161
|
-
"X-React-Router-Prerender": "yes"
|
|
1162
|
-
};
|
|
1163
|
-
for (let path of routesToPrerender) {
|
|
1164
|
-
var _matchRoutes;
|
|
1165
|
-
let hasLoaders = (_matchRoutes = reactRouter.matchRoutes(routes, path)) === null || _matchRoutes === void 0 ? void 0 : _matchRoutes.some(m => m.route.loader);
|
|
1166
|
-
let data;
|
|
1167
|
-
if (hasLoaders) {
|
|
1168
|
-
data = await prerenderData(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, {
|
|
1169
|
-
headers
|
|
1170
|
-
});
|
|
1171
|
-
}
|
|
1172
|
-
await prerenderRoute(handler, path, clientBuildDirectory, reactRouterConfig, viteConfig, data ? {
|
|
1173
|
-
headers: {
|
|
1174
|
-
...headers,
|
|
1175
|
-
"X-React-Router-Prerender-Data": data
|
|
1176
|
-
}
|
|
1177
|
-
} : {
|
|
1178
|
-
headers
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
await prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig);
|
|
1182
|
-
}
|
|
1183
|
-
function determineStaticPrerenderRoutes(routes, viteConfig, isBooleanUsage = false) {
|
|
1184
|
-
// Always start with the root/index route included
|
|
1185
|
-
let paths = ["/"];
|
|
1186
|
-
let paramRoutes = [];
|
|
1187
|
-
// Then recursively add any new path defined by the tree
|
|
1188
|
-
function recurse(subtree, prefix = "") {
|
|
1189
|
-
for (let route of subtree) {
|
|
1190
|
-
let newPath = [prefix, route.path].join("/").replace(/\/\/+/g, "/");
|
|
1191
|
-
if (route.path) {
|
|
1192
|
-
let segments = route.path.split("/");
|
|
1193
|
-
if (segments.some(s => s.startsWith(":") || s === "*")) {
|
|
1194
|
-
paramRoutes.push(route.path);
|
|
1195
|
-
} else {
|
|
1196
|
-
paths.push(newPath);
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
if (route.children) {
|
|
1200
|
-
recurse(route.children, newPath);
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
recurse(routes);
|
|
1205
|
-
if (isBooleanUsage && paramRoutes.length > 0) {
|
|
1206
|
-
viteConfig.logger.warn(["⚠️ Paths with dynamic/splat params cannot be prerendered when using `prerender: true`.", "You may want to use the `prerender()` API to prerender the following paths:", ...paramRoutes.map(p => " - " + p)].join("\n"));
|
|
1207
|
-
}
|
|
1208
|
-
// Clean double slashes and remove trailing slashes
|
|
1209
|
-
return paths.map(p => p.replace(/\/\/+/g, "/").replace(/(.+)\/$/, "$1"));
|
|
1210
|
-
}
|
|
1211
|
-
async function prerenderData(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
1212
|
-
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath === "/" ? "/_root.data" : `${prerenderPath.replace(/\/$/, "")}.data`}`.replace(/\/\/+/g, "/");
|
|
1213
|
-
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
1214
|
-
let response = await handler(request);
|
|
1215
|
-
let data = await response.text();
|
|
1216
|
-
validatePrerenderedResponse(response, data, "Prerender", normalizedPath);
|
|
1217
|
-
// Write out the .data file
|
|
1218
|
-
let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
|
|
1219
|
-
let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"));
|
|
1220
|
-
await fse__namespace.ensureDir(path__namespace.dirname(outfile));
|
|
1221
|
-
await fse__namespace.outputFile(outfile, data);
|
|
1222
|
-
viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
|
|
1223
|
-
return data;
|
|
1224
|
-
}
|
|
1225
|
-
async function prerenderRoute(handler, prerenderPath, clientBuildDirectory, reactRouterConfig, viteConfig, requestInit) {
|
|
1226
|
-
let normalizedPath = `${reactRouterConfig.basename}${prerenderPath}/`.replace(/\/\/+/g, "/");
|
|
1227
|
-
let request = new Request(`http://localhost${normalizedPath}`, requestInit);
|
|
1228
|
-
let response = await handler(request);
|
|
1229
|
-
let html = await response.text();
|
|
1230
|
-
validatePrerenderedResponse(response, html, "Prerender", normalizedPath);
|
|
1231
|
-
if (!reactRouterConfig.ssr) {
|
|
1232
|
-
validatePrerenderedHtml(html, "Prerender");
|
|
1233
|
-
}
|
|
1234
|
-
// Write out the HTML file
|
|
1235
|
-
let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
|
|
1236
|
-
let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"), "index.html");
|
|
1237
|
-
await fse__namespace.ensureDir(path__namespace.dirname(outfile));
|
|
1238
|
-
await fse__namespace.outputFile(outfile, html);
|
|
1239
|
-
viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
|
|
1240
|
-
}
|
|
1241
|
-
async function prerenderManifest(build, clientBuildDirectory, reactRouterConfig, viteConfig) {
|
|
1242
|
-
let normalizedPath = `${reactRouterConfig.basename}/__manifest`.replace(/\/\/+/g, "/");
|
|
1243
|
-
let outdir = path__namespace.relative(process.cwd(), clientBuildDirectory);
|
|
1244
|
-
let outfile = path__namespace.join(outdir, ...normalizedPath.split("/"));
|
|
1245
|
-
await fse__namespace.ensureDir(path__namespace.dirname(outfile));
|
|
1246
|
-
let manifestData = JSON.stringify(build.assets.routes);
|
|
1247
|
-
await fse__namespace.outputFile(outfile, manifestData);
|
|
1248
|
-
viteConfig.logger.info(`Prerender: Generated ${colors__default["default"].bold(outfile)}`);
|
|
1249
|
-
}
|
|
1250
|
-
function validatePrerenderedResponse(response, html, prefix, path) {
|
|
1251
|
-
if (response.status !== 200) {
|
|
1252
|
-
throw new Error(`${prefix}: Received a ${response.status} status code from ` + `\`entry.server.tsx\` while prerendering the \`${path}\` ` + `path.\n${html}`);
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
function validatePrerenderedHtml(html, prefix) {
|
|
1256
|
-
if (!html.includes("window.__reactRouterContext =") || !html.includes("window.__reactRouterRouteModules =")) {
|
|
1257
|
-
throw new Error(`${prefix}: Did you forget to include <Scripts/> in your root route? ` + "Your pre-rendered HTML files cannot hydrate without `<Scripts />`.");
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
// Note: Duplicated from react-router/lib/server-runtime
|
|
1261
|
-
function groupRoutesByParentId(manifest) {
|
|
1262
|
-
let routes = {};
|
|
1263
|
-
Object.values(manifest).forEach(route => {
|
|
1264
|
-
if (route) {
|
|
1265
|
-
let parentId = route.parentId || "";
|
|
1266
|
-
if (!routes[parentId]) {
|
|
1267
|
-
routes[parentId] = [];
|
|
1268
|
-
}
|
|
1269
|
-
routes[parentId].push(route);
|
|
1270
|
-
}
|
|
1271
|
-
});
|
|
1272
|
-
return routes;
|
|
1273
|
-
}
|
|
1274
|
-
// Note: Duplicated from react-router/lib/server-runtime
|
|
1275
|
-
function createPrerenderRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
|
|
1276
|
-
return (routesByParentId[parentId] || []).map(route => {
|
|
1277
|
-
let commonRoute = {
|
|
1278
|
-
// Always include root due to default boundaries
|
|
1279
|
-
hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
|
|
1280
|
-
id: route.id,
|
|
1281
|
-
path: route.path,
|
|
1282
|
-
loader: route.module.loader ? () => null : undefined,
|
|
1283
|
-
action: undefined,
|
|
1284
|
-
handle: route.module.handle
|
|
1285
|
-
};
|
|
1286
|
-
return route.index ? {
|
|
1287
|
-
index: true,
|
|
1288
|
-
...commonRoute
|
|
1289
|
-
} : {
|
|
1290
|
-
caseSensitive: route.caseSensitive,
|
|
1291
|
-
children: createPrerenderRoutes(manifest, route.id, routesByParentId),
|
|
1292
|
-
...commonRoute
|
|
1293
|
-
};
|
|
1294
|
-
});
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
exports.extractPluginContext = extractPluginContext;
|
|
1298
|
-
exports.getServerBuildDirectory = getServerBuildDirectory;
|
|
1299
|
-
exports.loadPluginContext = loadPluginContext;
|
|
1300
|
-
exports.reactRouterVitePlugin = reactRouterVitePlugin;
|
|
1301
|
-
exports.resolveViteConfig = resolveViteConfig;
|