@modern-js/runtime 2.52.0 → 2.54.0
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/cjs/{runtimeContext.js → cli/constants.js} +6 -10
- package/dist/cjs/cli/entry.js +42 -0
- package/dist/cjs/cli/index.js +10 -0
- package/dist/cjs/core/compatible.js +13 -29
- package/dist/cjs/core/{appConfig.js → config.js} +6 -4
- package/dist/cjs/core/context/index.js +28 -0
- package/dist/cjs/core/context/runtime.js +42 -0
- package/dist/cjs/core/index.js +8 -12
- package/dist/cjs/core/loader/useLoader.js +2 -2
- package/dist/cjs/core/{plugin.js → plugin/base.js} +5 -25
- package/dist/cjs/core/plugin/index.js +39 -0
- package/dist/cjs/core/plugin/runner.js +42 -0
- package/dist/cjs/index.js +2 -4
- package/dist/cjs/router/cli/code/getClientRoutes/getRoutes.js +197 -0
- package/dist/cjs/router/cli/code/getClientRoutes/getRoutesLegacy.js +195 -0
- package/dist/cjs/router/cli/code/getClientRoutes/index.js +31 -0
- package/dist/cjs/router/cli/code/getClientRoutes/utils.js +59 -0
- package/dist/cjs/router/cli/code/index.js +134 -0
- package/dist/cjs/router/cli/code/makeLegalIdentifier.js +37 -0
- package/dist/cjs/router/cli/code/nestedRoutes.js +294 -0
- package/dist/cjs/router/cli/code/templates.js +371 -0
- package/dist/cjs/router/cli/code/utils.js +143 -0
- package/dist/cjs/router/cli/constants.js +83 -0
- package/dist/cjs/router/cli/entry.js +87 -0
- package/dist/cjs/router/cli/handler.js +71 -0
- package/dist/cjs/router/cli/index.js +25 -0
- package/dist/cjs/router/runtime/plugin.js +7 -4
- package/dist/cjs/router/runtime/plugin.node.js +12 -5
- package/dist/cjs/ssr/index.node.js +1 -0
- package/dist/cjs/state/runtime/plugin.js +3 -2
- package/dist/esm/cli/constants.js +4 -0
- package/dist/esm/cli/entry.js +14 -0
- package/dist/esm/cli/index.js +10 -0
- package/dist/esm/core/compatible.js +11 -30
- package/dist/esm/core/{appConfig.js → config.js} +4 -1
- package/dist/esm/core/context/index.js +4 -0
- package/dist/esm/core/context/runtime.js +18 -0
- package/dist/esm/core/index.js +4 -6
- package/dist/esm/core/loader/useLoader.js +1 -1
- package/dist/esm/core/plugin/base.js +21 -0
- package/dist/esm/core/plugin/index.js +15 -0
- package/dist/esm/core/plugin/runner.js +17 -0
- package/dist/esm/index.js +2 -3
- package/dist/esm/router/cli/code/getClientRoutes/getRoutes.js +185 -0
- package/dist/esm/router/cli/code/getClientRoutes/getRoutesLegacy.js +183 -0
- package/dist/esm/router/cli/code/getClientRoutes/index.js +6 -0
- package/dist/esm/router/cli/code/getClientRoutes/utils.js +28 -0
- package/dist/esm/router/cli/code/index.js +214 -0
- package/dist/esm/router/cli/code/makeLegalIdentifier.js +15 -0
- package/dist/esm/router/cli/code/nestedRoutes.js +397 -0
- package/dist/esm/router/cli/code/templates.js +417 -0
- package/dist/esm/router/cli/code/utils.js +212 -0
- package/dist/esm/router/cli/constants.js +47 -0
- package/dist/esm/router/cli/entry.js +57 -0
- package/dist/esm/router/cli/handler.js +103 -0
- package/dist/esm/router/cli/index.js +57 -0
- package/dist/esm/router/runtime/plugin.js +7 -4
- package/dist/esm/router/runtime/plugin.node.js +13 -6
- package/dist/esm/ssr/index.node.js +1 -0
- package/dist/esm/state/runtime/plugin.js +3 -2
- package/dist/esm-node/cli/constants.js +4 -0
- package/dist/esm-node/cli/entry.js +8 -0
- package/dist/esm-node/cli/index.js +9 -0
- package/dist/esm-node/core/compatible.js +12 -28
- package/dist/esm-node/core/{appConfig.js → config.js} +2 -1
- package/dist/esm-node/core/context/index.js +4 -0
- package/dist/esm-node/core/context/runtime.js +16 -0
- package/dist/esm-node/core/index.js +4 -6
- package/dist/esm-node/core/loader/useLoader.js +1 -1
- package/dist/esm-node/core/plugin/base.js +19 -0
- package/dist/esm-node/core/plugin/index.js +13 -0
- package/dist/esm-node/core/plugin/runner.js +17 -0
- package/dist/esm-node/index.js +2 -3
- package/dist/esm-node/router/cli/code/getClientRoutes/getRoutes.js +163 -0
- package/dist/esm-node/router/cli/code/getClientRoutes/getRoutesLegacy.js +161 -0
- package/dist/esm-node/router/cli/code/getClientRoutes/index.js +6 -0
- package/dist/esm-node/router/cli/code/getClientRoutes/utils.js +22 -0
- package/dist/esm-node/router/cli/code/index.js +100 -0
- package/dist/esm-node/router/cli/code/makeLegalIdentifier.js +13 -0
- package/dist/esm-node/router/cli/code/nestedRoutes.js +258 -0
- package/dist/esm-node/router/cli/code/templates.js +335 -0
- package/dist/esm-node/router/cli/code/utils.js +101 -0
- package/dist/esm-node/router/cli/constants.js +47 -0
- package/dist/esm-node/router/cli/entry.js +50 -0
- package/dist/esm-node/router/cli/handler.js +36 -0
- package/dist/esm-node/router/cli/index.js +22 -0
- package/dist/esm-node/router/runtime/plugin.js +7 -4
- package/dist/esm-node/router/runtime/plugin.node.js +12 -5
- package/dist/esm-node/ssr/index.node.js +1 -0
- package/dist/esm-node/state/runtime/plugin.js +3 -2
- package/dist/types/cli/constants.d.ts +1 -0
- package/dist/types/cli/entry.d.ts +1 -0
- package/dist/types/cli/index.d.ts +1 -0
- package/dist/types/core/compatible.d.ts +7 -3
- package/dist/types/core/config.d.ts +14 -0
- package/dist/types/core/context/index.d.ts +1 -0
- package/dist/types/{runtimeContext.d.ts → core/context/runtime.d.ts} +5 -4
- package/dist/types/core/index.d.ts +4 -4
- package/dist/types/core/plugin/base.d.ts +80 -0
- package/dist/types/core/plugin/index.d.ts +29 -0
- package/dist/types/core/plugin/runner.d.ts +26 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/router/cli/code/getClientRoutes/getRoutes.d.ts +8 -0
- package/dist/types/router/cli/code/getClientRoutes/getRoutesLegacy.d.ts +9 -0
- package/dist/types/router/cli/code/getClientRoutes/index.d.ts +2 -0
- package/dist/types/router/cli/code/getClientRoutes/utils.d.ts +5 -0
- package/dist/types/router/cli/code/index.d.ts +6 -0
- package/dist/types/router/cli/code/makeLegalIdentifier.d.ts +1 -0
- package/dist/types/router/cli/code/nestedRoutes.d.ts +7 -0
- package/dist/types/router/cli/code/templates.d.ts +14 -0
- package/dist/types/router/cli/code/utils.d.ts +12 -0
- package/dist/types/router/cli/constants.d.ts +32 -0
- package/dist/types/router/cli/entry.d.ts +5 -0
- package/dist/types/router/cli/handler.d.ts +5 -0
- package/dist/types/router/cli/index.d.ts +3 -1
- package/dist/types/ssr/serverRender/types.d.ts +3 -0
- package/package.json +37 -11
- package/dist/esm/core/plugin.js +0 -59
- package/dist/esm/runtimeContext.js +0 -7
- package/dist/esm-node/core/plugin.js +0 -37
- package/dist/esm-node/runtimeContext.js +0 -7
- package/dist/types/core/appConfig.d.ts +0 -4
- package/dist/types/core/plugin.d.ts +0 -204
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
import { JS_EXTENSIONS, fs, normalizeToPosixPath } from "@modern-js/utils";
|
|
3
|
+
import { NESTED_ROUTE } from "../constants";
|
|
4
|
+
import { getPathWithoutExt, hasAction, replaceWithAlias } from "./utils";
|
|
5
|
+
const conventionNames = Object.values(NESTED_ROUTE);
|
|
6
|
+
const replaceDynamicPath = (routePath) => {
|
|
7
|
+
return routePath.replace(/\[(.*?)\]/g, ":$1");
|
|
8
|
+
};
|
|
9
|
+
const getRouteId = (componentPath, routesDir, entryName, isMainEntry) => {
|
|
10
|
+
const relativePath = normalizeToPosixPath(path.relative(routesDir, componentPath));
|
|
11
|
+
const pathWithoutExt = getPathWithoutExt(relativePath);
|
|
12
|
+
let id = ``;
|
|
13
|
+
if (isMainEntry) {
|
|
14
|
+
id = pathWithoutExt;
|
|
15
|
+
} else {
|
|
16
|
+
id = `${entryName}_${pathWithoutExt}`;
|
|
17
|
+
}
|
|
18
|
+
return id.replace(/\[(.*?)\]/g, "($1)");
|
|
19
|
+
};
|
|
20
|
+
const createIndexRoute = (routeInfo, rootDir, filename, entryName, isMainEntry) => {
|
|
21
|
+
return createRoute({
|
|
22
|
+
...routeInfo,
|
|
23
|
+
index: true,
|
|
24
|
+
children: void 0
|
|
25
|
+
}, rootDir, filename, entryName, isMainEntry);
|
|
26
|
+
};
|
|
27
|
+
const createRoute = (routeInfo, rootDir, filename, entryName, isMainEntry) => {
|
|
28
|
+
const id = getRouteId(filename, rootDir, entryName, isMainEntry);
|
|
29
|
+
return {
|
|
30
|
+
...routeInfo,
|
|
31
|
+
id,
|
|
32
|
+
type: "nested"
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const optimizeRoute = (routeTree) => {
|
|
36
|
+
if (!routeTree.children || routeTree.children.length === 0) {
|
|
37
|
+
return [
|
|
38
|
+
routeTree
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
const { children } = routeTree;
|
|
42
|
+
if (!routeTree._component && !routeTree.error && !routeTree.loading && !routeTree.config && !routeTree.clientData) {
|
|
43
|
+
const newRoutes = children.map((child) => {
|
|
44
|
+
const routePath = `${routeTree.path ? routeTree.path : ""}${child.path ? `/${child.path}` : ""}`;
|
|
45
|
+
const newRoute = {
|
|
46
|
+
...child,
|
|
47
|
+
path: routePath.replace(/\/\//g, "/")
|
|
48
|
+
};
|
|
49
|
+
if (routePath.length > 0) {
|
|
50
|
+
delete newRoute.index;
|
|
51
|
+
} else {
|
|
52
|
+
delete newRoute.path;
|
|
53
|
+
}
|
|
54
|
+
return newRoute;
|
|
55
|
+
});
|
|
56
|
+
return Array.from(new Set(newRoutes)).flatMap(optimizeRoute);
|
|
57
|
+
} else {
|
|
58
|
+
const optimizedChildren = routeTree.children.flatMap(optimizeRoute);
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
...routeTree,
|
|
62
|
+
children: optimizedChildren
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const walk = async (dirname, rootDir, alias, entryName, isMainEntry, oldVersion) => {
|
|
68
|
+
var _finalRoute_children;
|
|
69
|
+
if (!await fs.pathExists(dirname)) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const isDirectory = (await fs.stat(dirname)).isDirectory();
|
|
73
|
+
if (!isDirectory) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
const relativeDir = path.relative(rootDir, dirname);
|
|
77
|
+
const pathSegments = relativeDir.split(path.sep);
|
|
78
|
+
const lastSegment = pathSegments[pathSegments.length - 1];
|
|
79
|
+
const isRoot = lastSegment === "";
|
|
80
|
+
const isPathlessLayout = lastSegment.startsWith("__");
|
|
81
|
+
const isWithoutLayoutPath = lastSegment.includes(".");
|
|
82
|
+
let routePath = isRoot || isPathlessLayout ? "/" : `${lastSegment}`;
|
|
83
|
+
if (isWithoutLayoutPath) {
|
|
84
|
+
routePath = lastSegment.split(".").join("/");
|
|
85
|
+
}
|
|
86
|
+
routePath = replaceDynamicPath(routePath);
|
|
87
|
+
const route = {
|
|
88
|
+
path: routePath === null || routePath === void 0 ? void 0 : routePath.replace(/\$$/, "?"),
|
|
89
|
+
children: [],
|
|
90
|
+
isRoot
|
|
91
|
+
};
|
|
92
|
+
let pageLoaderFile = "";
|
|
93
|
+
let pageRoute = null;
|
|
94
|
+
let pageConfigFile = "";
|
|
95
|
+
let pageClientData = "";
|
|
96
|
+
let pageData = "";
|
|
97
|
+
let pageAction = "";
|
|
98
|
+
let splatLoaderFile = "";
|
|
99
|
+
let splatRoute = null;
|
|
100
|
+
let splatConfigFile = "";
|
|
101
|
+
let splatClientData = "";
|
|
102
|
+
let splatData = "";
|
|
103
|
+
let splatAction = "";
|
|
104
|
+
const items = await fs.readdir(dirname);
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
const itemPath = path.join(dirname, item);
|
|
107
|
+
const itemPathWithAlias = getPathWithoutExt(replaceWithAlias(alias.basename, itemPath, alias.name));
|
|
108
|
+
const extname = path.extname(item);
|
|
109
|
+
const itemWithoutExt = item.slice(0, -extname.length);
|
|
110
|
+
const isDirectory2 = (await fs.stat(itemPath)).isDirectory();
|
|
111
|
+
if (isDirectory2) {
|
|
112
|
+
const childRoute = await walk(itemPath, rootDir, alias, entryName, isMainEntry, oldVersion);
|
|
113
|
+
if (childRoute && !Array.isArray(childRoute)) {
|
|
114
|
+
var _route_children;
|
|
115
|
+
(_route_children = route.children) === null || _route_children === void 0 ? void 0 : _route_children.push(childRoute);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (extname && (!JS_EXTENSIONS.includes(extname) || !conventionNames.includes(itemWithoutExt))) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (itemWithoutExt === NESTED_ROUTE.LAYOUT_LOADER_FILE) {
|
|
122
|
+
if (!route.loader) {
|
|
123
|
+
route.loader = itemPathWithAlias;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (itemWithoutExt === NESTED_ROUTE.LAYOUT_CLIENT_LOADER) {
|
|
127
|
+
route.clientData = itemPathWithAlias;
|
|
128
|
+
}
|
|
129
|
+
if (itemWithoutExt === NESTED_ROUTE.LAYOUT_DATA_FILE) {
|
|
130
|
+
route.data = itemPathWithAlias;
|
|
131
|
+
if (await hasAction(itemPath)) {
|
|
132
|
+
route.action = itemPathWithAlias;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (itemWithoutExt === NESTED_ROUTE.LAYOUT_CONFIG_FILE) {
|
|
136
|
+
if (!route.config) {
|
|
137
|
+
route.config = itemPathWithAlias;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (itemWithoutExt === NESTED_ROUTE.LAYOUT_FILE) {
|
|
141
|
+
route._component = itemPathWithAlias;
|
|
142
|
+
}
|
|
143
|
+
if (itemWithoutExt === NESTED_ROUTE.PAGE_LOADER_FILE) {
|
|
144
|
+
pageLoaderFile = itemPathWithAlias;
|
|
145
|
+
}
|
|
146
|
+
if (itemWithoutExt === NESTED_ROUTE.PAGE_CLIENT_LOADER) {
|
|
147
|
+
pageClientData = itemPathWithAlias;
|
|
148
|
+
}
|
|
149
|
+
if (itemWithoutExt === NESTED_ROUTE.PAGE_DATA_FILE) {
|
|
150
|
+
pageData = itemPathWithAlias;
|
|
151
|
+
if (await hasAction(itemPath)) {
|
|
152
|
+
pageAction = itemPathWithAlias;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (itemWithoutExt === NESTED_ROUTE.PAGE_CONFIG_FILE) {
|
|
156
|
+
pageConfigFile = itemPathWithAlias;
|
|
157
|
+
}
|
|
158
|
+
if (itemWithoutExt === NESTED_ROUTE.PAGE_FILE) {
|
|
159
|
+
var _route_children1;
|
|
160
|
+
pageRoute = createIndexRoute({
|
|
161
|
+
_component: itemPathWithAlias
|
|
162
|
+
}, rootDir, itemPath, entryName, isMainEntry);
|
|
163
|
+
if (pageLoaderFile) {
|
|
164
|
+
pageRoute.loader = pageLoaderFile;
|
|
165
|
+
}
|
|
166
|
+
if (pageConfigFile) {
|
|
167
|
+
pageRoute.config = pageConfigFile;
|
|
168
|
+
}
|
|
169
|
+
if (pageData) {
|
|
170
|
+
pageRoute.data = pageData;
|
|
171
|
+
}
|
|
172
|
+
if (pageClientData) {
|
|
173
|
+
pageRoute.clientData = pageClientData;
|
|
174
|
+
}
|
|
175
|
+
if (pageAction) {
|
|
176
|
+
pageRoute.action = pageAction;
|
|
177
|
+
}
|
|
178
|
+
(_route_children1 = route.children) === null || _route_children1 === void 0 ? void 0 : _route_children1.push(pageRoute);
|
|
179
|
+
}
|
|
180
|
+
if (itemWithoutExt === NESTED_ROUTE.SPLATE_LOADER_FILE) {
|
|
181
|
+
splatLoaderFile = itemPathWithAlias;
|
|
182
|
+
}
|
|
183
|
+
if (itemWithoutExt === NESTED_ROUTE.SPLATE_CLIENT_DATA) {
|
|
184
|
+
splatClientData = itemPathWithAlias;
|
|
185
|
+
}
|
|
186
|
+
if (itemWithoutExt === NESTED_ROUTE.SPLATE_CONFIG_FILE) {
|
|
187
|
+
if (!route.config) {
|
|
188
|
+
splatConfigFile = replaceWithAlias(alias.basename, itemPath, alias.name);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (itemWithoutExt === NESTED_ROUTE.SPLATE_DATA_FILE) {
|
|
192
|
+
splatData = itemPathWithAlias;
|
|
193
|
+
if (await hasAction(itemPath)) {
|
|
194
|
+
splatAction = itemPathWithAlias;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (itemWithoutExt === NESTED_ROUTE.SPLATE_FILE) {
|
|
198
|
+
var _route_children2;
|
|
199
|
+
splatRoute = createRoute({
|
|
200
|
+
_component: itemPathWithAlias,
|
|
201
|
+
path: "*"
|
|
202
|
+
}, rootDir, itemPath, entryName, isMainEntry);
|
|
203
|
+
if (splatLoaderFile) {
|
|
204
|
+
splatRoute.loader = splatLoaderFile;
|
|
205
|
+
}
|
|
206
|
+
if (splatClientData) {
|
|
207
|
+
splatRoute.clientData = splatClientData;
|
|
208
|
+
}
|
|
209
|
+
if (splatData) {
|
|
210
|
+
splatRoute.data = splatData;
|
|
211
|
+
}
|
|
212
|
+
if (splatConfigFile) {
|
|
213
|
+
splatRoute.config = splatConfigFile;
|
|
214
|
+
}
|
|
215
|
+
if (splatAction) {
|
|
216
|
+
splatRoute.action = splatAction;
|
|
217
|
+
}
|
|
218
|
+
(_route_children2 = route.children) === null || _route_children2 === void 0 ? void 0 : _route_children2.push(splatRoute);
|
|
219
|
+
}
|
|
220
|
+
if (itemWithoutExt === NESTED_ROUTE.LOADING_FILE) {
|
|
221
|
+
route.loading = itemPathWithAlias;
|
|
222
|
+
}
|
|
223
|
+
if (itemWithoutExt === NESTED_ROUTE.ERROR_FILE) {
|
|
224
|
+
route.error = itemPathWithAlias;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
let finalRoute = createRoute(route, rootDir, path.join(dirname, `${NESTED_ROUTE.LAYOUT_FILE}.ts`), entryName, isMainEntry);
|
|
228
|
+
if (isPathlessLayout) {
|
|
229
|
+
delete finalRoute.path;
|
|
230
|
+
}
|
|
231
|
+
const childRoutes = finalRoute.children = (_finalRoute_children = finalRoute.children) === null || _finalRoute_children === void 0 ? void 0 : _finalRoute_children.filter((childRoute) => childRoute);
|
|
232
|
+
if (childRoutes && childRoutes.length === 0 && !finalRoute.index && !finalRoute._component) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
if (childRoutes && childRoutes.length === 1 && !finalRoute._component) {
|
|
236
|
+
const childRoute = childRoutes[0];
|
|
237
|
+
if (childRoute.path === "*") {
|
|
238
|
+
const path2 = `${finalRoute.path || ""}/${childRoute.path || ""}`;
|
|
239
|
+
finalRoute = {
|
|
240
|
+
...childRoute,
|
|
241
|
+
path: path2
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (isRoot && !finalRoute._component) {
|
|
246
|
+
throw new Error("The root layout component is required, make sure the routes/layout.tsx file exists.");
|
|
247
|
+
}
|
|
248
|
+
if (isRoot && !oldVersion) {
|
|
249
|
+
const optimizedRoutes = optimizeRoute(finalRoute);
|
|
250
|
+
return optimizedRoutes;
|
|
251
|
+
}
|
|
252
|
+
return finalRoute;
|
|
253
|
+
};
|
|
254
|
+
export {
|
|
255
|
+
getRouteId,
|
|
256
|
+
optimizeRoute,
|
|
257
|
+
walk
|
|
258
|
+
};
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { fs, getEntryOptions, isSSGEntry, slash } from "@modern-js/utils";
|
|
3
|
+
import { ROUTE_MODULES } from "@modern-js/utils/universal/constants";
|
|
4
|
+
import { TEMP_LOADERS_DIR } from "../constants";
|
|
5
|
+
import { getServerLoadersFile } from "./utils";
|
|
6
|
+
const routesForServer = ({ routes }) => {
|
|
7
|
+
const loaders = [];
|
|
8
|
+
const actions = [];
|
|
9
|
+
const loadersMap = {};
|
|
10
|
+
const traverseRouteTree = (route) => {
|
|
11
|
+
let children;
|
|
12
|
+
if ("children" in route && route.children) {
|
|
13
|
+
var _route_children;
|
|
14
|
+
children = route === null || route === void 0 ? void 0 : (_route_children = route.children) === null || _route_children === void 0 ? void 0 : _route_children.map(traverseRouteTree);
|
|
15
|
+
}
|
|
16
|
+
let loader;
|
|
17
|
+
let action;
|
|
18
|
+
if (route.type === "nested") {
|
|
19
|
+
if (route.loader || route.data) {
|
|
20
|
+
loaders.push(route.loader);
|
|
21
|
+
const loaderId = loaders.length - 1;
|
|
22
|
+
loader = `loader_${loaderId}`;
|
|
23
|
+
const inline = Boolean(route.data);
|
|
24
|
+
loadersMap[loader] = {
|
|
25
|
+
loaderId,
|
|
26
|
+
routeId: route.id,
|
|
27
|
+
filePath: route.data || route.loader,
|
|
28
|
+
clientData: Boolean(route.clientData),
|
|
29
|
+
route,
|
|
30
|
+
inline
|
|
31
|
+
};
|
|
32
|
+
if (route.action) {
|
|
33
|
+
actions.push(route.action);
|
|
34
|
+
action = `action_${loaders.length - 1}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const finalRoute = {
|
|
39
|
+
...route,
|
|
40
|
+
loader,
|
|
41
|
+
action,
|
|
42
|
+
children
|
|
43
|
+
};
|
|
44
|
+
return finalRoute;
|
|
45
|
+
};
|
|
46
|
+
let routesCode = `
|
|
47
|
+
export const routes = [
|
|
48
|
+
`;
|
|
49
|
+
for (const route of routes) {
|
|
50
|
+
if ("type" in route) {
|
|
51
|
+
const keywords = [
|
|
52
|
+
"loader",
|
|
53
|
+
"action"
|
|
54
|
+
];
|
|
55
|
+
const regs = keywords.map(createMatchReg);
|
|
56
|
+
const newRoute = traverseRouteTree(route);
|
|
57
|
+
const routeStr = JSON.stringify(newRoute, null, 2);
|
|
58
|
+
routesCode += regs.reduce((acc, reg) => acc.replace(reg, "$1$2"), routeStr).replace(/\\"/g, '"');
|
|
59
|
+
} else {
|
|
60
|
+
routesCode += `${JSON.stringify(route, null, 2)}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
routesCode += `
|
|
64
|
+
];`;
|
|
65
|
+
let importLoadersCode = "";
|
|
66
|
+
for (const [key, loaderInfo] of Object.entries(loadersMap)) {
|
|
67
|
+
if (loaderInfo.inline) {
|
|
68
|
+
const { route } = loaderInfo;
|
|
69
|
+
if (route.action) {
|
|
70
|
+
importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${slash(loaderInfo.filePath)}";
|
|
71
|
+
`;
|
|
72
|
+
} else {
|
|
73
|
+
importLoadersCode += `import { loader as ${key} } from "${slash(loaderInfo.filePath)}";
|
|
74
|
+
`;
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
importLoadersCode += `import ${key} from "${slash(loaderInfo.filePath)}";
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return `
|
|
82
|
+
${importLoadersCode}
|
|
83
|
+
${routesCode}
|
|
84
|
+
`;
|
|
85
|
+
};
|
|
86
|
+
const createMatchReg = (keyword) => new RegExp(`("${keyword}":\\s)"([^
|
|
87
|
+
]+)"`, "g");
|
|
88
|
+
const fileSystemRoutes = async ({ routes, ssrMode, nestedRoutesEntry, entryName, internalDirectory, splitRouteChunks = true }) => {
|
|
89
|
+
const components = [];
|
|
90
|
+
const loadings = [];
|
|
91
|
+
const errors = [];
|
|
92
|
+
const loaders = [];
|
|
93
|
+
const loadersMap = {};
|
|
94
|
+
const configs = [];
|
|
95
|
+
const configsMap = {};
|
|
96
|
+
const loadersMapFile = path.join(internalDirectory, entryName, TEMP_LOADERS_DIR, "map.json");
|
|
97
|
+
const importLazyCode = `
|
|
98
|
+
import { lazy } from "react";
|
|
99
|
+
import loadable, { lazy as loadableLazy } from "@modern-js/runtime/loadable"
|
|
100
|
+
`;
|
|
101
|
+
let rootLayoutCode = ``;
|
|
102
|
+
const getDataLoaderPath = ({ loaderId, clientData, action, inline, routeId }) => {
|
|
103
|
+
if (!ssrMode) {
|
|
104
|
+
return "";
|
|
105
|
+
}
|
|
106
|
+
const clientDataStr = clientData ? `&clientData=${clientData}` : "";
|
|
107
|
+
if (nestedRoutesEntry) {
|
|
108
|
+
return `?loaderId=${loaderId}${clientDataStr}&action=${action ? slash(action) : action}&inline=${inline}&routeId=${routeId}`;
|
|
109
|
+
}
|
|
110
|
+
return "";
|
|
111
|
+
};
|
|
112
|
+
const traverseRouteTree = (route) => {
|
|
113
|
+
let children;
|
|
114
|
+
if ("children" in route && route.children) {
|
|
115
|
+
var _route_children;
|
|
116
|
+
children = route === null || route === void 0 ? void 0 : (_route_children = route.children) === null || _route_children === void 0 ? void 0 : _route_children.map(traverseRouteTree);
|
|
117
|
+
}
|
|
118
|
+
let loading;
|
|
119
|
+
let error;
|
|
120
|
+
let loader;
|
|
121
|
+
let action;
|
|
122
|
+
let config;
|
|
123
|
+
let component = "";
|
|
124
|
+
let lazyImport = null;
|
|
125
|
+
if (route.type === "nested") {
|
|
126
|
+
if (route.loading) {
|
|
127
|
+
loadings.push(route.loading);
|
|
128
|
+
loading = `loading_${loadings.length - 1}`;
|
|
129
|
+
}
|
|
130
|
+
if (route.error) {
|
|
131
|
+
errors.push(route.error);
|
|
132
|
+
error = `error_${errors.length - 1}`;
|
|
133
|
+
}
|
|
134
|
+
if (route.loader || route.data) {
|
|
135
|
+
loaders.push(route.loader);
|
|
136
|
+
const loaderId = loaders.length - 1;
|
|
137
|
+
loader = `loader_${loaderId}`;
|
|
138
|
+
const inline = Boolean(route.data);
|
|
139
|
+
loadersMap[loader] = {
|
|
140
|
+
loaderId,
|
|
141
|
+
routeId: route.id,
|
|
142
|
+
filePath: route.data || route.loader,
|
|
143
|
+
clientData: Boolean(route.clientData),
|
|
144
|
+
route,
|
|
145
|
+
inline
|
|
146
|
+
};
|
|
147
|
+
loader = `loader_${loaderId}`;
|
|
148
|
+
if (route.action) {
|
|
149
|
+
action = `action_${loaderId}`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (typeof route.config === "string") {
|
|
153
|
+
configs.push(route.config);
|
|
154
|
+
const configId = configs.length - 1;
|
|
155
|
+
config = `config_${configId}`;
|
|
156
|
+
configsMap[config] = route.config;
|
|
157
|
+
}
|
|
158
|
+
if (route._component) {
|
|
159
|
+
if (splitRouteChunks) {
|
|
160
|
+
if (route.isRoot) {
|
|
161
|
+
lazyImport = `() => import('${route._component}').then(routeModule => handleRouteModule(routeModule, "${route.id}")).catch(handleRouteModuleError) `;
|
|
162
|
+
rootLayoutCode = `import RootLayout from '${route._component}'`;
|
|
163
|
+
component = `RootLayout`;
|
|
164
|
+
} else if (ssrMode === "string") {
|
|
165
|
+
lazyImport = `() => import(/* webpackChunkName: "${route.id}" */ '${route._component}').then(routeModule => handleRouteModule(routeModule, "${route.id}")).catch(handleRouteModuleError) `;
|
|
166
|
+
component = `loadable(${lazyImport})`;
|
|
167
|
+
} else {
|
|
168
|
+
lazyImport = `() => import(/* webpackChunkName: "${route.id}" */ '${route._component}').then(routeModule => handleRouteModule(routeModule, "${route.id}")).catch(handleRouteModuleError) `;
|
|
169
|
+
component = `lazy(${lazyImport})`;
|
|
170
|
+
}
|
|
171
|
+
} else if (ssrMode === "string") {
|
|
172
|
+
components.push(route._component);
|
|
173
|
+
component = `component_${components.length - 1}`;
|
|
174
|
+
} else {
|
|
175
|
+
lazyImport = `() => import(/* webpackMode: "eager" */ '${route._component}').then(routeModule => handleRouteModule(routeModule, "${route.id}")).catch(handleRouteModuleError) `;
|
|
176
|
+
component = `lazy(${lazyImport})`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} else if (route._component) {
|
|
180
|
+
if (splitRouteChunks) {
|
|
181
|
+
lazyImport = `() => import('${route._component}')`;
|
|
182
|
+
component = `loadable(${lazyImport})`;
|
|
183
|
+
} else {
|
|
184
|
+
components.push(route._component);
|
|
185
|
+
component = `component_${components.length - 1}`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const finalRoute = {
|
|
189
|
+
...route,
|
|
190
|
+
lazyImport,
|
|
191
|
+
loading,
|
|
192
|
+
loader,
|
|
193
|
+
action,
|
|
194
|
+
config,
|
|
195
|
+
error,
|
|
196
|
+
children
|
|
197
|
+
};
|
|
198
|
+
if (route._component) {
|
|
199
|
+
finalRoute.component = component;
|
|
200
|
+
}
|
|
201
|
+
if (route.type === "nested" && route._component && (route.loader || route.data)) {
|
|
202
|
+
finalRoute.shouldRevalidate = `createShouldRevalidate("${route.id}")`;
|
|
203
|
+
}
|
|
204
|
+
return finalRoute;
|
|
205
|
+
};
|
|
206
|
+
let routeComponentsCode = `
|
|
207
|
+
export const routes = [
|
|
208
|
+
`;
|
|
209
|
+
for (const route of routes) {
|
|
210
|
+
if ("type" in route) {
|
|
211
|
+
const newRoute = traverseRouteTree(route);
|
|
212
|
+
const routeStr = JSON.stringify(newRoute, null, 2);
|
|
213
|
+
const keywords = [
|
|
214
|
+
"component",
|
|
215
|
+
"lazyImport",
|
|
216
|
+
"shouldRevalidate",
|
|
217
|
+
"loader",
|
|
218
|
+
"action",
|
|
219
|
+
"loading",
|
|
220
|
+
"error",
|
|
221
|
+
"config"
|
|
222
|
+
];
|
|
223
|
+
const regs = keywords.map(createMatchReg);
|
|
224
|
+
const newRouteStr = regs.reduce((acc, reg) => acc.replace(reg, "$1$2"), routeStr).replace(/"(RootLayout)"/g, "$1").replace(/\\"/g, '"');
|
|
225
|
+
routeComponentsCode += `${newRouteStr},`;
|
|
226
|
+
} else {
|
|
227
|
+
const component = `loadable(() => import('${route._component}'))`;
|
|
228
|
+
const finalRoute = {
|
|
229
|
+
...route,
|
|
230
|
+
component
|
|
231
|
+
};
|
|
232
|
+
const keywords = [
|
|
233
|
+
"component",
|
|
234
|
+
"lazyImport"
|
|
235
|
+
];
|
|
236
|
+
const routeStr = JSON.stringify(finalRoute, null, 2);
|
|
237
|
+
const regs = keywords.map(createMatchReg);
|
|
238
|
+
const newRouteStr = regs.reduce((acc, reg) => acc.replace(reg, "$1$2"), routeStr).replace(/\\"/g, '"');
|
|
239
|
+
routeComponentsCode += `${newRouteStr},`;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
routeComponentsCode += `
|
|
243
|
+
];`;
|
|
244
|
+
const importLoadingCode = loadings.map((loading, index) => {
|
|
245
|
+
return `import loading_${index} from '${loading}';
|
|
246
|
+
`;
|
|
247
|
+
}).join("");
|
|
248
|
+
const importComponentsCode = components.map((component, index) => {
|
|
249
|
+
return `import component_${index} from '${component}';
|
|
250
|
+
`;
|
|
251
|
+
}).join("");
|
|
252
|
+
const importErrorComponentsCode = errors.map((error, index) => {
|
|
253
|
+
return `import error_${index} from '${error}';
|
|
254
|
+
`;
|
|
255
|
+
}).join("");
|
|
256
|
+
let importLoadersCode = "";
|
|
257
|
+
for (const [key, loaderInfo] of Object.entries(loadersMap)) {
|
|
258
|
+
if (loaderInfo.inline) {
|
|
259
|
+
const { route } = loaderInfo;
|
|
260
|
+
if (route.action) {
|
|
261
|
+
importLoadersCode += `import { loader as ${key}, action as action_${loaderInfo.loaderId} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
|
|
262
|
+
loaderId: key,
|
|
263
|
+
clientData: loaderInfo.clientData,
|
|
264
|
+
action: route.action,
|
|
265
|
+
inline: loaderInfo.inline,
|
|
266
|
+
routeId: loaderInfo.routeId
|
|
267
|
+
})}";
|
|
268
|
+
`;
|
|
269
|
+
} else {
|
|
270
|
+
importLoadersCode += `import { loader as ${key} } from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
|
|
271
|
+
loaderId: key,
|
|
272
|
+
clientData: loaderInfo.clientData,
|
|
273
|
+
action: false,
|
|
274
|
+
inline: loaderInfo.inline,
|
|
275
|
+
routeId: route.id
|
|
276
|
+
})}";
|
|
277
|
+
`;
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
importLoadersCode += `import ${key} from "${slash(loaderInfo.filePath)}${getDataLoaderPath({
|
|
281
|
+
loaderId: key,
|
|
282
|
+
clientData: loaderInfo.clientData,
|
|
283
|
+
action: false,
|
|
284
|
+
inline: loaderInfo.inline,
|
|
285
|
+
routeId: loaderInfo.routeId
|
|
286
|
+
})}";
|
|
287
|
+
`;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
let importConfigsCode = "";
|
|
291
|
+
for (const [key, configPath] of Object.entries(configsMap)) {
|
|
292
|
+
importConfigsCode += `import * as ${key} from "${slash(configPath)}";
|
|
293
|
+
`;
|
|
294
|
+
}
|
|
295
|
+
await fs.ensureFile(loadersMapFile);
|
|
296
|
+
await fs.writeJSON(loadersMapFile, loadersMap);
|
|
297
|
+
const importRuntimeRouterCode = `
|
|
298
|
+
import { createShouldRevalidate, handleRouteModule, handleRouteModuleError} from '@modern-js/runtime/router';
|
|
299
|
+
`;
|
|
300
|
+
const routeModulesCode = `
|
|
301
|
+
if(typeof document !== 'undefined'){
|
|
302
|
+
window.${ROUTE_MODULES} = {}
|
|
303
|
+
}
|
|
304
|
+
`;
|
|
305
|
+
return `
|
|
306
|
+
${importLazyCode}
|
|
307
|
+
${importComponentsCode}
|
|
308
|
+
${importRuntimeRouterCode}
|
|
309
|
+
${rootLayoutCode}
|
|
310
|
+
${importLoadingCode}
|
|
311
|
+
${importErrorComponentsCode}
|
|
312
|
+
${importLoadersCode}
|
|
313
|
+
${importConfigsCode}
|
|
314
|
+
${routeModulesCode}
|
|
315
|
+
${routeComponentsCode}
|
|
316
|
+
`;
|
|
317
|
+
};
|
|
318
|
+
function ssrLoaderCombinedModule(entrypoints, entrypoint, config, appContext) {
|
|
319
|
+
const { entryName, isMainEntry } = entrypoint;
|
|
320
|
+
const { packageName, internalDirectory } = appContext;
|
|
321
|
+
const ssr = getEntryOptions(entryName, isMainEntry, config.server.ssr, config.server.ssrByEntries, packageName);
|
|
322
|
+
const ssg = isSSGEntry(config, entryName, entrypoints);
|
|
323
|
+
if (entrypoint.nestedRoutesEntry && (ssr || ssg)) {
|
|
324
|
+
const serverLoaderRuntime = require.resolve("@modern-js/plugin-data-loader/runtime");
|
|
325
|
+
const serverLoadersFile = getServerLoadersFile(internalDirectory, entryName);
|
|
326
|
+
const combinedModule = `export * from "${slash(serverLoaderRuntime)}"; export * from "${slash(serverLoadersFile)}"`;
|
|
327
|
+
return combinedModule;
|
|
328
|
+
}
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
export {
|
|
332
|
+
fileSystemRoutes,
|
|
333
|
+
routesForServer,
|
|
334
|
+
ssrLoaderCombinedModule
|
|
335
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { normalizeToPosixPath, fs as fse, JS_EXTENSIONS } from "@modern-js/utils";
|
|
4
|
+
import { transform } from "esbuild";
|
|
5
|
+
import { parse } from "es-module-lexer";
|
|
6
|
+
import { ACTION_EXPORT_NAME, LOADER_EXPORT_NAME } from "../constants";
|
|
7
|
+
const walkDirectory = (dir) => fs.readdirSync(dir).reduce((previous, filename) => {
|
|
8
|
+
const filePath = path.join(dir, filename);
|
|
9
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
10
|
+
return [
|
|
11
|
+
...previous,
|
|
12
|
+
...walkDirectory(filePath)
|
|
13
|
+
];
|
|
14
|
+
} else {
|
|
15
|
+
return [
|
|
16
|
+
...previous,
|
|
17
|
+
filePath
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
}, []);
|
|
21
|
+
const isPageComponentFile = (filePath) => {
|
|
22
|
+
if (/\.(d|test|spec|e2e)\.(js|jsx|ts|tsx)$/.test(filePath)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if ([
|
|
26
|
+
".js",
|
|
27
|
+
".jsx",
|
|
28
|
+
".ts",
|
|
29
|
+
".tsx"
|
|
30
|
+
].includes(path.extname(filePath))) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
};
|
|
35
|
+
const replaceWithAlias = (base, filePath, alias) => {
|
|
36
|
+
if (filePath.includes(base)) {
|
|
37
|
+
return normalizeToPosixPath(path.join(alias, path.relative(base, filePath)));
|
|
38
|
+
} else {
|
|
39
|
+
return filePath;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const parseModule = async ({ source, filename }) => {
|
|
43
|
+
let content = source;
|
|
44
|
+
if (JS_EXTENSIONS.some((ext) => filename.endsWith(ext))) {
|
|
45
|
+
const result = await transform(content, {
|
|
46
|
+
loader: path.extname(filename).slice(1),
|
|
47
|
+
format: "esm"
|
|
48
|
+
});
|
|
49
|
+
content = result.code;
|
|
50
|
+
}
|
|
51
|
+
return parse(content);
|
|
52
|
+
};
|
|
53
|
+
const hasLoader = async (filename, source) => {
|
|
54
|
+
let content = source;
|
|
55
|
+
if (!source) {
|
|
56
|
+
content = (await fse.readFile(filename, "utf-8")).toString();
|
|
57
|
+
}
|
|
58
|
+
if (content) {
|
|
59
|
+
const [, moduleExports] = await parseModule({
|
|
60
|
+
source: content.toString(),
|
|
61
|
+
filename
|
|
62
|
+
});
|
|
63
|
+
return moduleExports.some((e) => e.n === LOADER_EXPORT_NAME);
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
};
|
|
67
|
+
const hasAction = async (filename, source) => {
|
|
68
|
+
let content = source;
|
|
69
|
+
if (!source) {
|
|
70
|
+
content = (await fse.readFile(filename, "utf-8")).toString();
|
|
71
|
+
}
|
|
72
|
+
if (content) {
|
|
73
|
+
const [, moduleExports] = await parseModule({
|
|
74
|
+
source: content.toString(),
|
|
75
|
+
filename
|
|
76
|
+
});
|
|
77
|
+
return moduleExports.some((e) => e.n === ACTION_EXPORT_NAME);
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
};
|
|
81
|
+
const getServerLoadersFile = (internalDirectory, entryName) => {
|
|
82
|
+
return path.join(internalDirectory, entryName, "route-server-loaders.js");
|
|
83
|
+
};
|
|
84
|
+
const getServerCombinedModueFile = (internalDirectory, entryName) => {
|
|
85
|
+
return path.join(internalDirectory, entryName, "server-loader-combined.js");
|
|
86
|
+
};
|
|
87
|
+
const getPathWithoutExt = (filename) => {
|
|
88
|
+
const extname = path.extname(filename);
|
|
89
|
+
return filename.slice(0, -extname.length);
|
|
90
|
+
};
|
|
91
|
+
export {
|
|
92
|
+
getPathWithoutExt,
|
|
93
|
+
getServerCombinedModueFile,
|
|
94
|
+
getServerLoadersFile,
|
|
95
|
+
hasAction,
|
|
96
|
+
hasLoader,
|
|
97
|
+
isPageComponentFile,
|
|
98
|
+
parseModule,
|
|
99
|
+
replaceWithAlias,
|
|
100
|
+
walkDirectory
|
|
101
|
+
};
|