@solidjs/start 2.0.0-beta.1 → 2.0.0-beta.10
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 +64 -0
- package/dist/client/StartClient.d.ts +7 -0
- package/{src/client/StartClient.tsx → dist/client/StartClient.jsx} +7 -15
- package/dist/client/index.jsx +2 -0
- package/dist/client/mount.d.ts +1 -0
- package/dist/client/mount.js +1 -0
- package/dist/client/spa/index.d.ts +4 -0
- package/dist/client/spa/index.jsx +5 -0
- package/dist/config/boundary-modules.d.ts +14 -0
- package/dist/config/boundary-modules.js +41 -0
- package/dist/config/constants.d.ts +16 -0
- package/dist/config/constants.js +16 -0
- package/dist/config/dev-server.d.ts +4 -0
- package/dist/config/dev-server.js +146 -0
- package/dist/config/env.d.ts +19 -0
- package/dist/config/env.js +85 -0
- package/dist/config/fs-router.d.ts +37 -0
- package/dist/config/fs-router.js +148 -0
- package/dist/config/fs-routes/fs-watcher.d.ts +3 -0
- package/dist/config/fs-routes/fs-watcher.js +53 -0
- package/dist/config/fs-routes/index.d.ts +7 -0
- package/dist/config/fs-routes/index.js +107 -0
- package/dist/config/fs-routes/router.d.ts +43 -0
- package/dist/config/fs-routes/router.js +146 -0
- package/dist/config/fs-routes/tree-shake.d.ts +2 -0
- package/dist/config/fs-routes/tree-shake.js +305 -0
- package/dist/config/index.d.ts +25 -0
- package/dist/config/index.js +252 -0
- package/dist/config/lazy.d.ts +3 -0
- package/dist/config/lazy.js +114 -0
- package/dist/config/manifest.d.ts +3 -0
- package/dist/config/manifest.js +109 -0
- package/dist/config/utils.d.ts +4 -0
- package/dist/config/utils.js +6 -0
- package/dist/config/vite-utils.d.ts +21 -0
- package/dist/config/vite-utils.js +85 -0
- package/dist/directives/bubble-function-declaration.d.ts +3 -0
- package/dist/directives/bubble-function-declaration.js +23 -0
- package/dist/directives/compile.d.ts +9 -0
- package/dist/directives/compile.js +40 -0
- package/dist/directives/generate-unique-name.d.ts +3 -0
- package/dist/directives/generate-unique-name.js +16 -0
- package/dist/directives/get-descriptive-name.d.ts +2 -0
- package/dist/directives/get-descriptive-name.js +37 -0
- package/dist/directives/get-import-identifier.d.ts +4 -0
- package/dist/directives/get-import-identifier.js +19 -0
- package/dist/directives/get-root-statement-path.d.ts +2 -0
- package/dist/directives/get-root-statement-path.js +12 -0
- package/dist/directives/index.d.ts +14 -0
- package/dist/directives/index.js +202 -0
- package/dist/directives/is-statement-top-level.d.ts +3 -0
- package/dist/directives/is-statement-top-level.js +9 -0
- package/dist/directives/paths.d.ts +9 -0
- package/dist/directives/paths.js +36 -0
- package/dist/directives/plugin.d.ts +21 -0
- package/dist/directives/plugin.js +302 -0
- package/dist/directives/remove-unused-variables.d.ts +3 -0
- package/dist/directives/remove-unused-variables.js +66 -0
- package/{src/directives/types.ts → dist/directives/types.d.ts} +5 -7
- package/dist/directives/types.js +1 -0
- package/dist/directives/xxhash32.d.ts +6 -0
- package/dist/directives/xxhash32.js +193 -0
- package/dist/fns/client.d.ts +3 -0
- package/dist/fns/client.js +106 -0
- package/dist/fns/handler.d.ts +5 -0
- package/dist/fns/handler.js +305 -0
- package/dist/fns/registration.d.ts +3 -0
- package/dist/fns/registration.js +15 -0
- package/dist/fns/serialization.d.ts +6 -0
- package/dist/fns/serialization.js +208 -0
- package/dist/fns/server.d.ts +7 -0
- package/dist/fns/server.js +38 -0
- package/dist/fns/shared.d.ts +17 -0
- package/dist/fns/shared.js +105 -0
- package/dist/http/http.d.ts +81 -0
- package/dist/http/http.js +129 -0
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +6 -0
- package/{src/index.tsx → dist/index.d.ts} +0 -2
- package/dist/index.jsx +6 -0
- package/dist/middleware/index.d.ts +39 -0
- package/dist/middleware/index.js +60 -0
- package/dist/router.d.ts +6 -0
- package/dist/router.jsx +29 -0
- package/dist/server/StartServer.d.ts +9 -0
- package/dist/server/StartServer.jsx +34 -0
- package/dist/server/assets/PatchVirtualDevStyles.d.ts +4 -0
- package/{src/server/assets/PatchVirtualDevStyles.tsx → dist/server/assets/PatchVirtualDevStyles.jsx} +7 -10
- package/dist/server/assets/index.d.ts +2 -0
- package/dist/server/assets/index.js +52 -0
- package/dist/server/assets/render.d.ts +19 -0
- package/dist/server/assets/render.jsx +14 -0
- package/dist/server/collect-styles.d.ts +3 -0
- package/dist/server/collect-styles.js +57 -0
- package/dist/server/fetchEvent.d.ts +7 -0
- package/dist/server/fetchEvent.js +26 -0
- package/dist/server/handler.d.ts +6 -0
- package/dist/server/handler.js +218 -0
- package/dist/server/index.d.ts +9 -0
- package/{src/server/index.tsx → dist/server/index.jsx} +4 -19
- package/dist/server/manifest/client-manifest.d.ts +9 -0
- package/dist/server/manifest/client-manifest.js +6 -0
- package/dist/server/manifest/dev-client-manifest.d.ts +4 -0
- package/dist/server/manifest/dev-client-manifest.js +24 -0
- package/dist/server/manifest/dev-ssr-manifest.d.ts +5 -0
- package/dist/server/manifest/dev-ssr-manifest.js +23 -0
- package/dist/server/manifest/prod-client-manifest.d.ts +5 -0
- package/dist/server/manifest/prod-client-manifest.js +26 -0
- package/dist/server/manifest/prod-ssr-manifest.d.ts +6 -0
- package/dist/server/manifest/prod-ssr-manifest.js +85 -0
- package/dist/server/manifest/ssr-manifest.d.ts +4 -0
- package/dist/server/manifest/ssr-manifest.js +6 -0
- package/dist/server/routes.d.ts +23 -0
- package/dist/server/routes.js +74 -0
- package/dist/server/spa/StartServer.d.ts +9 -0
- package/dist/server/spa/StartServer.jsx +25 -0
- package/dist/server/spa/handler.d.ts +8 -0
- package/dist/server/spa/handler.js +20 -0
- package/{src/server/spa/index.tsx → dist/server/spa/index.d.ts} +0 -1
- package/dist/server/spa/index.jsx +5 -0
- package/dist/server/types.d.ts +75 -0
- package/dist/server/types.js +1 -0
- package/dist/server/util.d.ts +2 -0
- package/dist/server/util.js +8 -0
- package/dist/server/web-stream.d.ts +9 -0
- package/dist/server/web-stream.js +26 -0
- package/dist/shared/ErrorBoundary.d.ts +3 -0
- package/dist/shared/ErrorBoundary.jsx +36 -0
- package/dist/shared/GET.d.ts +5 -0
- package/dist/shared/GET.js +8 -0
- package/dist/shared/HttpHeader.d.ts +10 -0
- package/dist/shared/HttpHeader.jsx +38 -0
- package/dist/shared/HttpStatusCode.d.ts +9 -0
- package/dist/shared/HttpStatusCode.js +18 -0
- package/dist/shared/clientOnly.d.ts +12 -0
- package/dist/shared/clientOnly.js +27 -0
- package/dist/shared/dev-overlay/CodeView.d.ts +7 -0
- package/dist/shared/dev-overlay/CodeView.jsx +62 -0
- package/dist/shared/dev-overlay/DevOverlayDialog.d.ts +9 -0
- package/dist/shared/dev-overlay/DevOverlayDialog.jsx +226 -0
- package/dist/shared/dev-overlay/createStackFrame.d.ts +9 -0
- package/dist/shared/dev-overlay/createStackFrame.js +56 -0
- package/dist/shared/dev-overlay/download.d.ts +1 -0
- package/dist/shared/dev-overlay/download.js +6 -0
- package/dist/shared/dev-overlay/get-source-map.d.ts +2 -0
- package/dist/shared/dev-overlay/get-source-map.js +25 -0
- package/dist/shared/dev-overlay/icons.d.ts +28 -0
- package/dist/shared/dev-overlay/icons.jsx +150 -0
- package/dist/shared/dev-overlay/index.d.ts +5 -0
- package/dist/shared/dev-overlay/index.jsx +39 -0
- package/dist/shared/lazy.d.ts +3 -0
- package/dist/shared/lazy.js +42 -0
- package/dist/shared/serverFunction.d.ts +6 -0
- package/dist/shared/serverFunction.js +8 -0
- package/dist/utils/debounce.d.ts +4 -0
- package/dist/utils/debounce.js +10 -0
- package/env.d.ts +12 -0
- package/package.json +10 -5
- package/scripts/build.js +0 -15
- package/scripts/validate-imports.js +0 -316
- package/src/client/mount.ts +0 -1
- package/src/client/spa/index.tsx +0 -9
- package/src/config/constants.ts +0 -19
- package/src/config/dev-server.ts +0 -161
- package/src/config/env.ts +0 -105
- package/src/config/fs-router.ts +0 -162
- package/src/config/fs-routes/fs-watcher.ts +0 -66
- package/src/config/fs-routes/index.ts +0 -136
- package/src/config/fs-routes/router.ts +0 -184
- package/src/config/fs-routes/tree-shake.ts +0 -324
- package/src/config/index.ts +0 -239
- package/src/config/lazy.ts +0 -132
- package/src/config/manifest.ts +0 -120
- package/src/config/utils.ts +0 -5
- package/src/config/vite-utils.ts +0 -113
- package/src/directives/bubble-function-declaration.ts +0 -33
- package/src/directives/compile.ts +0 -54
- package/src/directives/generate-unique-name.ts +0 -22
- package/src/directives/get-descriptive-name.ts +0 -39
- package/src/directives/get-import-identifier.ts +0 -34
- package/src/directives/get-root-statement-path.ts +0 -14
- package/src/directives/index.ts +0 -233
- package/src/directives/is-statement-top-level.ts +0 -13
- package/src/directives/paths.ts +0 -63
- package/src/directives/plugin.ts +0 -389
- package/src/directives/remove-unused-variables.ts +0 -70
- package/src/directives/xxhash32.ts +0 -214
- package/src/env.d.ts +0 -17
- package/src/fns/client.ts +0 -141
- package/src/fns/handler.spec.ts +0 -85
- package/src/fns/handler.ts +0 -287
- package/src/fns/registration.ts +0 -19
- package/src/fns/serialization.ts +0 -250
- package/src/fns/server.ts +0 -46
- package/src/fns/shared.ts +0 -116
- package/src/http/index.ts +0 -216
- package/src/internal.d.ts +0 -14
- package/src/middleware/index.ts +0 -92
- package/src/router.tsx +0 -37
- package/src/server/StartServer.tsx +0 -58
- package/src/server/assets/index.ts +0 -70
- package/src/server/assets/render.tsx +0 -46
- package/src/server/collect-styles.ts +0 -70
- package/src/server/fetchEvent.spec.ts +0 -85
- package/src/server/fetchEvent.ts +0 -36
- package/src/server/handler.ts +0 -261
- package/src/server/manifest/client-manifest.ts +0 -8
- package/src/server/manifest/dev-client-manifest.ts +0 -21
- package/src/server/manifest/dev-ssr-manifest.ts +0 -23
- package/src/server/manifest/prod-client-manifest.ts +0 -21
- package/src/server/manifest/prod-ssr-manifest.ts +0 -109
- package/src/server/manifest/ssr-manifest.ts +0 -10
- package/src/server/routes.ts +0 -126
- package/src/server/spa/StartServer.tsx +0 -42
- package/src/server/spa/handler.ts +0 -29
- package/src/server/types.ts +0 -82
- package/src/server/util.ts +0 -12
- package/src/shared/ErrorBoundary.tsx +0 -52
- package/src/shared/GET.ts +0 -8
- package/src/shared/HttpHeader.tsx +0 -42
- package/src/shared/HttpStatusCode.ts +0 -27
- package/src/shared/clientOnly.ts +0 -44
- package/src/shared/dev-overlay/CodeView.tsx +0 -90
- package/src/shared/dev-overlay/DevOverlayDialog.tsx +0 -316
- package/src/shared/dev-overlay/createStackFrame.ts +0 -74
- package/src/shared/dev-overlay/download.ts +0 -6
- package/src/shared/dev-overlay/env.d.ts +0 -4
- package/src/shared/dev-overlay/get-source-map.ts +0 -33
- package/src/shared/dev-overlay/icons.tsx +0 -456
- package/src/shared/dev-overlay/index.tsx +0 -63
- package/src/shared/lazy.ts +0 -52
- package/src/shared/serverFunction.ts +0 -10
- package/src/utils/debounce.ts +0 -10
- package/src/virtual.d.ts +0 -27
- package/tsconfig.json +0 -24
- package/vitest.config.ts +0 -9
- /package/{src/client/index.tsx → dist/client/index.d.ts} +0 -0
- /package/{src → dist}/shared/dev-overlay/styles.css +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { analyzeModule, BaseFileSystemRouter, cleanPath, } from "./fs-routes/router.js";
|
|
2
|
+
export class SolidStartClientFileRouter extends BaseFileSystemRouter {
|
|
3
|
+
toPath(src) {
|
|
4
|
+
const routePath = cleanPath(src, this.config)
|
|
5
|
+
// remove the initial slash
|
|
6
|
+
.slice(1)
|
|
7
|
+
.replace(/index$/, "")
|
|
8
|
+
.replace(/\[([^/]+)\]/g, (_, m) => {
|
|
9
|
+
if (m.length > 3 && m.startsWith("...")) {
|
|
10
|
+
return `*${m.slice(3)}`;
|
|
11
|
+
}
|
|
12
|
+
if (m.length > 2 && m.startsWith("[") && m.endsWith("]")) {
|
|
13
|
+
return `:${m.slice(1, -1)}?`;
|
|
14
|
+
}
|
|
15
|
+
return `:${m}`;
|
|
16
|
+
});
|
|
17
|
+
return routePath?.length > 0 ? `/${routePath}` : "/";
|
|
18
|
+
}
|
|
19
|
+
toRoute(src) {
|
|
20
|
+
const path = this.toPath(src);
|
|
21
|
+
if (src.endsWith(".md") || src.endsWith(".mdx")) {
|
|
22
|
+
return {
|
|
23
|
+
page: true,
|
|
24
|
+
$component: {
|
|
25
|
+
src: src,
|
|
26
|
+
pick: ["$css"],
|
|
27
|
+
},
|
|
28
|
+
$$route: undefined,
|
|
29
|
+
path,
|
|
30
|
+
// filePath: src
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const exports = analyzeModule(src);
|
|
34
|
+
const exportNames = exports.map(getExportName);
|
|
35
|
+
const localExportNames = exports.map(getLocalExportName).filter(name => name !== undefined);
|
|
36
|
+
const hasDefault = exportNames.includes("default");
|
|
37
|
+
const hasRouteConfig = exportNames.includes("route");
|
|
38
|
+
if (hasDefault) {
|
|
39
|
+
return {
|
|
40
|
+
page: true,
|
|
41
|
+
$component: {
|
|
42
|
+
src: src,
|
|
43
|
+
pick: [...localExportNames.filter(name => name !== "route"), "default", "$css"],
|
|
44
|
+
},
|
|
45
|
+
$$route: hasRouteConfig
|
|
46
|
+
? {
|
|
47
|
+
src: src,
|
|
48
|
+
pick: ["route"],
|
|
49
|
+
}
|
|
50
|
+
: undefined,
|
|
51
|
+
path,
|
|
52
|
+
// filePath: src
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const HTTP_METHODS = ["HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"];
|
|
58
|
+
function getExportName(entry) {
|
|
59
|
+
return entry.exportName.name ?? "default";
|
|
60
|
+
}
|
|
61
|
+
function getLocalExportName(entry) {
|
|
62
|
+
const name = getExportName(entry);
|
|
63
|
+
if (name === "default")
|
|
64
|
+
return;
|
|
65
|
+
return name === (entry.localName.name ?? entry.importName.name ?? name) ? name : undefined;
|
|
66
|
+
}
|
|
67
|
+
function createHTTPHandlers(src, exports) {
|
|
68
|
+
const handlers = {};
|
|
69
|
+
for (const exp of exports) {
|
|
70
|
+
if (HTTP_METHODS.includes(exp)) {
|
|
71
|
+
handlers[`$${exp}`] = {
|
|
72
|
+
src: src,
|
|
73
|
+
pick: [exp],
|
|
74
|
+
};
|
|
75
|
+
if (exp === "GET" && !exports.includes("HEAD")) {
|
|
76
|
+
handlers.$HEAD = {
|
|
77
|
+
src: src,
|
|
78
|
+
pick: [exp],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return handlers;
|
|
84
|
+
}
|
|
85
|
+
export class SolidStartServerFileRouter extends BaseFileSystemRouter {
|
|
86
|
+
constructor(config) {
|
|
87
|
+
super(config);
|
|
88
|
+
}
|
|
89
|
+
toPath(src) {
|
|
90
|
+
const routePath = cleanPath(src, this.config)
|
|
91
|
+
// remove the initial slash
|
|
92
|
+
.slice(1)
|
|
93
|
+
.replace(/index$/, "")
|
|
94
|
+
.replace(/\[([^/]+)\]/g, (_, m) => {
|
|
95
|
+
if (m.length > 3 && m.startsWith("...")) {
|
|
96
|
+
return `*${m.slice(3)}`;
|
|
97
|
+
}
|
|
98
|
+
if (m.length > 2 && m.startsWith("[") && m.endsWith("]")) {
|
|
99
|
+
return `:${m.slice(1, -1)}?`;
|
|
100
|
+
}
|
|
101
|
+
return `:${m}`;
|
|
102
|
+
});
|
|
103
|
+
return routePath?.length > 0 ? `/${routePath}` : "/";
|
|
104
|
+
}
|
|
105
|
+
toRoute(src) {
|
|
106
|
+
const path = this.toPath(src);
|
|
107
|
+
if (src.endsWith(".md") || src.endsWith(".mdx")) {
|
|
108
|
+
return {
|
|
109
|
+
page: true,
|
|
110
|
+
$component: {
|
|
111
|
+
src: src,
|
|
112
|
+
pick: ["$css"],
|
|
113
|
+
},
|
|
114
|
+
$$route: undefined,
|
|
115
|
+
path,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const exports = analyzeModule(src);
|
|
119
|
+
const exportNames = exports.map(getExportName);
|
|
120
|
+
const localExportNames = exports.map(getLocalExportName).filter(name => name !== undefined);
|
|
121
|
+
const hasRouteConfig = exportNames.includes("route");
|
|
122
|
+
const hasDefault = exportNames.includes("default");
|
|
123
|
+
const hasAPIRoutes = exportNames.some(name => HTTP_METHODS.includes(name));
|
|
124
|
+
if (hasDefault || hasAPIRoutes) {
|
|
125
|
+
return {
|
|
126
|
+
page: hasDefault,
|
|
127
|
+
$component: !this.config.dataOnly && hasDefault
|
|
128
|
+
? {
|
|
129
|
+
src: src,
|
|
130
|
+
pick: [
|
|
131
|
+
...localExportNames.filter(name => name !== "route" && !HTTP_METHODS.includes(name)),
|
|
132
|
+
"default",
|
|
133
|
+
"$css",
|
|
134
|
+
],
|
|
135
|
+
}
|
|
136
|
+
: undefined,
|
|
137
|
+
$$route: hasRouteConfig
|
|
138
|
+
? {
|
|
139
|
+
src: src,
|
|
140
|
+
pick: ["route"],
|
|
141
|
+
}
|
|
142
|
+
: undefined,
|
|
143
|
+
...createHTTPHandlers(src, exportNames),
|
|
144
|
+
path,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { debounce } from "../../utils/debounce.js";
|
|
2
|
+
import { VITE_ENVIRONMENTS } from "../constants.js";
|
|
3
|
+
import { moduleId } from "./index.js";
|
|
4
|
+
function setupWatcher(watcher, routes) {
|
|
5
|
+
watcher.on("unlink", path => routes.removeRoute(path));
|
|
6
|
+
watcher.on("add", path => routes.addRoute(path));
|
|
7
|
+
watcher.on("change", path => routes.updateRoute(path));
|
|
8
|
+
}
|
|
9
|
+
function createRoutesReloader(server, routes, environment) {
|
|
10
|
+
const devEnv = server.environments[environment];
|
|
11
|
+
if (!devEnv?.moduleGraph)
|
|
12
|
+
return;
|
|
13
|
+
/**
|
|
14
|
+
* Debounce catches multiple route changes in a row
|
|
15
|
+
* Short timeout for inexpensive invalidations
|
|
16
|
+
*/
|
|
17
|
+
const invalidateModule = debounce((mod) => {
|
|
18
|
+
devEnv.moduleGraph.invalidateModule(mod);
|
|
19
|
+
}, 0);
|
|
20
|
+
/**
|
|
21
|
+
* Long debounce timeout for expensive reloads
|
|
22
|
+
*/
|
|
23
|
+
const reloadModule = debounce((mod) => {
|
|
24
|
+
devEnv.reloadModule(mod);
|
|
25
|
+
}, 200);
|
|
26
|
+
return routes.on("reload", function handleRoutesReload(evt) {
|
|
27
|
+
const mod = devEnv.moduleGraph.getModuleById(moduleId);
|
|
28
|
+
if (!mod) {
|
|
29
|
+
devEnv.hot.send({ type: "full-reload" });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (environment === VITE_ENVIRONMENTS.client && evt.detail.type !== "update") {
|
|
33
|
+
// Client has to be reloaded when routes are added or removed
|
|
34
|
+
reloadModule(mod);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
invalidateModule(mod);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export const fileSystemWatcher = (routers) => {
|
|
42
|
+
const plugin = {
|
|
43
|
+
name: "fs-watcher",
|
|
44
|
+
async configureServer(server) {
|
|
45
|
+
for (const environment of [VITE_ENVIRONMENTS.server, VITE_ENVIRONMENTS.client]) {
|
|
46
|
+
const router = routers[environment];
|
|
47
|
+
setupWatcher(server.watcher, router);
|
|
48
|
+
createRoutesReloader(server, router, environment);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
return plugin;
|
|
53
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PluginOption } from "vite";
|
|
2
|
+
import type { BaseFileSystemRouter } from "./router.ts";
|
|
3
|
+
export declare const moduleId = "solid-start:routes";
|
|
4
|
+
export interface FsRoutesArgs {
|
|
5
|
+
routers: Record<"client" | "ssr", BaseFileSystemRouter>;
|
|
6
|
+
}
|
|
7
|
+
export declare function fsRoutes({ routers }: FsRoutesArgs): Array<PluginOption>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { fileSystemWatcher } from "./fs-watcher.js";
|
|
3
|
+
import { treeShake } from "./tree-shake.js";
|
|
4
|
+
export const moduleId = "solid-start:routes";
|
|
5
|
+
export function fsRoutes({ routers }) {
|
|
6
|
+
globalThis.ROUTERS = routers;
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
name: "solid-start-fs-routes",
|
|
10
|
+
enforce: "pre",
|
|
11
|
+
resolveId(id) {
|
|
12
|
+
if (id === moduleId)
|
|
13
|
+
return id;
|
|
14
|
+
},
|
|
15
|
+
async load(id) {
|
|
16
|
+
const root = this.environment.config.root;
|
|
17
|
+
const isBuild = this.environment.mode === "build";
|
|
18
|
+
if (id !== moduleId)
|
|
19
|
+
return;
|
|
20
|
+
const js = jsCode();
|
|
21
|
+
const router = globalThis.ROUTERS[this.environment.name];
|
|
22
|
+
const routes = await router.getRoutes();
|
|
23
|
+
let routesCode = JSON.stringify(routes ?? [], (k, v) => {
|
|
24
|
+
if (v === undefined)
|
|
25
|
+
return undefined;
|
|
26
|
+
if (k.startsWith("$$")) {
|
|
27
|
+
const buildId = `${v.src}?${v.pick.map((p) => `pick=${p}`).join("&")}`;
|
|
28
|
+
/**
|
|
29
|
+
* @type {{ [key: string]: string }}
|
|
30
|
+
*/
|
|
31
|
+
const refs = {};
|
|
32
|
+
for (var pick of v.pick) {
|
|
33
|
+
refs[pick] = js.addNamedImport(pick, buildId);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
require: `_$() => ({ ${Object.entries(refs)
|
|
37
|
+
.map(([pick, namedImport]) => `'${pick}': ${namedImport}`)
|
|
38
|
+
.join(", ")} })$_`,
|
|
39
|
+
// src: isBuild ? relative(root, buildId) : buildId
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else if (k.startsWith("$")) {
|
|
43
|
+
const buildId = `${v.src}?${v.pick.map((p) => `pick=${p}`).join("&")}`;
|
|
44
|
+
return {
|
|
45
|
+
src: relative(root, buildId),
|
|
46
|
+
build: isBuild ? `_$() => import('${buildId}')$_` : undefined,
|
|
47
|
+
import: `_$() => import('${buildId}')$_`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return v;
|
|
51
|
+
});
|
|
52
|
+
routesCode = routesCode.replaceAll('"_$(', "(").replaceAll(')$_"', ")");
|
|
53
|
+
const code = `
|
|
54
|
+
${js.getImportStatements()}
|
|
55
|
+
export default ${routesCode}`;
|
|
56
|
+
return code;
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
treeShake(),
|
|
60
|
+
fileSystemWatcher(routers),
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
function jsCode() {
|
|
64
|
+
const imports = new Map();
|
|
65
|
+
let vars = 0;
|
|
66
|
+
function addImport(p) {
|
|
67
|
+
let id = imports.get(p);
|
|
68
|
+
if (!id) {
|
|
69
|
+
id = {};
|
|
70
|
+
imports.set(p, id);
|
|
71
|
+
}
|
|
72
|
+
const d = "routeData" + vars++;
|
|
73
|
+
id["default"] = d;
|
|
74
|
+
return d;
|
|
75
|
+
}
|
|
76
|
+
function addNamedImport(name, p) {
|
|
77
|
+
let id = imports.get(p);
|
|
78
|
+
if (!id) {
|
|
79
|
+
id = {};
|
|
80
|
+
imports.set(p, id);
|
|
81
|
+
}
|
|
82
|
+
const d = "routeData" + vars++;
|
|
83
|
+
id[name] = d;
|
|
84
|
+
return d;
|
|
85
|
+
}
|
|
86
|
+
const getNamedExport = (p) => {
|
|
87
|
+
const id = imports.get(p);
|
|
88
|
+
delete id["default"];
|
|
89
|
+
return Object.keys(id).length > 0
|
|
90
|
+
? `{ ${Object.keys(id)
|
|
91
|
+
.map(k => `${k} as ${id[k]}`)
|
|
92
|
+
.join(", ")} }`
|
|
93
|
+
: "";
|
|
94
|
+
};
|
|
95
|
+
const getImportStatements = () => {
|
|
96
|
+
return `${[...imports.keys()]
|
|
97
|
+
.map(i => `import ${imports.get(i).default
|
|
98
|
+
? `${imports.get(i).default}${Object.keys(imports.get(i)).length > 1 ? ", " : ""}`
|
|
99
|
+
: ""} ${getNamedExport(i)} from '${i}';`)
|
|
100
|
+
.join("\n")}`;
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
addImport,
|
|
104
|
+
addNamedImport,
|
|
105
|
+
getImportStatements,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type StaticExportEntry } from "oxc-parser";
|
|
2
|
+
import { pathToRegexp } from "path-to-regexp";
|
|
3
|
+
export { pathToRegexp };
|
|
4
|
+
export declare const glob: (path: string) => string[];
|
|
5
|
+
export type FileSystemRouterConfig = {
|
|
6
|
+
dir: string;
|
|
7
|
+
extensions: string[];
|
|
8
|
+
};
|
|
9
|
+
type Route = {
|
|
10
|
+
path: string;
|
|
11
|
+
} & Record<string, any>;
|
|
12
|
+
export declare function cleanPath(src: string, config: FileSystemRouterConfig): string;
|
|
13
|
+
export declare function analyzeModule(src: string): StaticExportEntry[];
|
|
14
|
+
type RouterEvent = CustomEvent<{
|
|
15
|
+
route: string;
|
|
16
|
+
type: "update" | "remove" | "add";
|
|
17
|
+
}>;
|
|
18
|
+
export declare class BaseFileSystemRouter extends EventTarget {
|
|
19
|
+
routes: Route[];
|
|
20
|
+
config: FileSystemRouterConfig;
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param {} config
|
|
24
|
+
*/
|
|
25
|
+
constructor(config: FileSystemRouterConfig);
|
|
26
|
+
glob(): string;
|
|
27
|
+
buildRoutes(): Promise<any[]>;
|
|
28
|
+
isRoute(src: string): boolean;
|
|
29
|
+
toPath(src: string): void;
|
|
30
|
+
toRoute(src: string): Route | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* To be attached by vite plugin to the vite dev server
|
|
33
|
+
*/
|
|
34
|
+
update: undefined;
|
|
35
|
+
_addRoute(route: Route): boolean;
|
|
36
|
+
addRoute(src: string): Promise<void>;
|
|
37
|
+
reload(route: string, type: "update" | "remove" | "add"): void;
|
|
38
|
+
updateRoute(src_: string): Promise<void>;
|
|
39
|
+
removeRoute(src: string): void;
|
|
40
|
+
on(type: string, cb: (evt: RouterEvent) => void): () => void;
|
|
41
|
+
buildRoutesPromise?: Promise<any[]>;
|
|
42
|
+
getRoutes(): Promise<Route[]>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fg from "fast-glob";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import micromatch from "micromatch";
|
|
4
|
+
import { posix } from "node:path";
|
|
5
|
+
import { parseSync } from "oxc-parser";
|
|
6
|
+
import { pathToRegexp } from "path-to-regexp";
|
|
7
|
+
import { normalizePath } from "vite";
|
|
8
|
+
export { pathToRegexp };
|
|
9
|
+
export const glob = (path) => fg.sync(path, { absolute: true });
|
|
10
|
+
export function cleanPath(src, config) {
|
|
11
|
+
return src
|
|
12
|
+
.slice(config.dir.length)
|
|
13
|
+
.replace(new RegExp(`\.(${(config.extensions ?? []).join("|")})$`), "");
|
|
14
|
+
}
|
|
15
|
+
export function analyzeModule(src) {
|
|
16
|
+
const result = parseSync(src, fs.readFileSync(src, "utf-8"), { lang: "tsx" });
|
|
17
|
+
const error = result.errors[0];
|
|
18
|
+
if (error)
|
|
19
|
+
throw new SyntaxError(`Failed to parse ${src}:\n${error.codeframe || error.message}`);
|
|
20
|
+
return result.module.staticExports.flatMap(({ entries }) => entries.filter(entry => !entry.isType && entry.exportName.kind !== "None"));
|
|
21
|
+
}
|
|
22
|
+
export class BaseFileSystemRouter extends EventTarget {
|
|
23
|
+
routes;
|
|
24
|
+
config;
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* @param {} config
|
|
28
|
+
*/
|
|
29
|
+
constructor(config) {
|
|
30
|
+
super();
|
|
31
|
+
this.routes = [];
|
|
32
|
+
this.config = config;
|
|
33
|
+
}
|
|
34
|
+
glob() {
|
|
35
|
+
return (posix.join(fg.convertPathToPattern(this.config.dir), "**/*") +
|
|
36
|
+
`.{${this.config.extensions.join(",")}}`);
|
|
37
|
+
}
|
|
38
|
+
async buildRoutes() {
|
|
39
|
+
for (var src of glob(this.glob())) {
|
|
40
|
+
await this.addRoute(src);
|
|
41
|
+
}
|
|
42
|
+
return this.routes;
|
|
43
|
+
}
|
|
44
|
+
isRoute(src) {
|
|
45
|
+
return Boolean(micromatch(src, this.glob())?.length);
|
|
46
|
+
}
|
|
47
|
+
toPath(src) {
|
|
48
|
+
throw new Error("Not implemented");
|
|
49
|
+
}
|
|
50
|
+
toRoute(src) {
|
|
51
|
+
let path = this.toPath(src);
|
|
52
|
+
if (path === undefined)
|
|
53
|
+
return;
|
|
54
|
+
const exports = analyzeModule(src);
|
|
55
|
+
if (!exports.find(entry => entry.exportName.kind === "Default")) {
|
|
56
|
+
console.warn("No default export", src);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
$component: {
|
|
60
|
+
src: src,
|
|
61
|
+
pick: ["default", "$css"],
|
|
62
|
+
},
|
|
63
|
+
path,
|
|
64
|
+
// filePath: src
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* To be attached by vite plugin to the vite dev server
|
|
69
|
+
*/
|
|
70
|
+
update = undefined;
|
|
71
|
+
_addRoute(route) {
|
|
72
|
+
const idx = this.routes.findIndex(r => r.path === route.path);
|
|
73
|
+
if (idx >= 0)
|
|
74
|
+
this.routes.splice(idx, 1);
|
|
75
|
+
this.routes.push(route);
|
|
76
|
+
return idx >= 0;
|
|
77
|
+
}
|
|
78
|
+
async addRoute(src) {
|
|
79
|
+
src = normalizePath(src);
|
|
80
|
+
if (this.isRoute(src)) {
|
|
81
|
+
try {
|
|
82
|
+
const route = this.toRoute(src);
|
|
83
|
+
if (route) {
|
|
84
|
+
this._addRoute(route);
|
|
85
|
+
this.reload(route.path, "add");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
console.error(e);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
reload(route, type) {
|
|
94
|
+
this.dispatchEvent(new CustomEvent("reload", {
|
|
95
|
+
detail: {
|
|
96
|
+
route,
|
|
97
|
+
type,
|
|
98
|
+
},
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
async updateRoute(src_) {
|
|
102
|
+
const src = normalizePath(src_);
|
|
103
|
+
if (this.isRoute(src)) {
|
|
104
|
+
try {
|
|
105
|
+
const route = this.toRoute(src);
|
|
106
|
+
if (route) {
|
|
107
|
+
const updated = this._addRoute(route);
|
|
108
|
+
this.reload(route.path, updated ? "update" : "add");
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.removeRoute(src_);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
console.error(e);
|
|
116
|
+
}
|
|
117
|
+
// this.update?.();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
removeRoute(src) {
|
|
121
|
+
src = normalizePath(src);
|
|
122
|
+
if (this.isRoute(src)) {
|
|
123
|
+
const path = this.toPath(src);
|
|
124
|
+
if (path === undefined) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const idx = this.routes.findIndex(r => r.path === path);
|
|
128
|
+
if (idx === -1)
|
|
129
|
+
return;
|
|
130
|
+
this.routes.splice(idx, 1);
|
|
131
|
+
this.reload(path, "remove");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
on(type, cb) {
|
|
135
|
+
this.addEventListener(type, cb);
|
|
136
|
+
return () => this.removeEventListener(type, cb);
|
|
137
|
+
}
|
|
138
|
+
buildRoutesPromise;
|
|
139
|
+
async getRoutes() {
|
|
140
|
+
if (!this.buildRoutesPromise) {
|
|
141
|
+
this.buildRoutesPromise = this.buildRoutes();
|
|
142
|
+
}
|
|
143
|
+
await this.buildRoutesPromise;
|
|
144
|
+
return this.routes;
|
|
145
|
+
}
|
|
146
|
+
}
|