@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,202 @@
|
|
|
1
|
+
import { createFilter, } from "vite";
|
|
2
|
+
import fg from "fast-glob";
|
|
3
|
+
import { compile } from "./compile.js";
|
|
4
|
+
import xxHash32 from "./xxhash32.js";
|
|
5
|
+
const DEFAULT_INCLUDE = "src/**/*.{jsx,tsx,ts,js,mjs,cjs}";
|
|
6
|
+
const DEFAULT_EXCLUDE = "node_modules/**/*.{jsx,tsx,ts,js,mjs,cjs}";
|
|
7
|
+
const DIRECTIVE = "use server";
|
|
8
|
+
// Dev-only virtual module used by fns/handler.ts to lazily resolve a server
|
|
9
|
+
// function id back to its owning module when the function was never evaluated
|
|
10
|
+
// in the server environment (e.g. its route was only client-side navigated to).
|
|
11
|
+
const LOOKUP_ID = "solid-start:server-fn-lookup";
|
|
12
|
+
function createManifest() {
|
|
13
|
+
return {
|
|
14
|
+
server: new Set(),
|
|
15
|
+
client: new Set(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function createDeferredPromise() {
|
|
19
|
+
let resolve;
|
|
20
|
+
let reject;
|
|
21
|
+
return {
|
|
22
|
+
reference: new Promise((res, rej) => {
|
|
23
|
+
resolve = res;
|
|
24
|
+
reject = rej;
|
|
25
|
+
}),
|
|
26
|
+
resolve(value) {
|
|
27
|
+
resolve(value);
|
|
28
|
+
},
|
|
29
|
+
reject(value) {
|
|
30
|
+
reject(value);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
class Debouncer {
|
|
35
|
+
source;
|
|
36
|
+
promise;
|
|
37
|
+
timeout;
|
|
38
|
+
constructor(source) {
|
|
39
|
+
this.source = source;
|
|
40
|
+
this.promise = createDeferredPromise();
|
|
41
|
+
this.defer();
|
|
42
|
+
}
|
|
43
|
+
defer() {
|
|
44
|
+
if (this.timeout) {
|
|
45
|
+
clearTimeout(this.timeout);
|
|
46
|
+
this.timeout = undefined;
|
|
47
|
+
}
|
|
48
|
+
this.timeout = setTimeout(() => {
|
|
49
|
+
this.promise.resolve(this.source());
|
|
50
|
+
}, 1000);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function mergeManifestRecord(source, target) {
|
|
54
|
+
const current = source.size;
|
|
55
|
+
for (const entry of target) {
|
|
56
|
+
source.add(entry);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
invalidPreload: current !== source.size,
|
|
60
|
+
invalidated: [...source],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function invalidateModule(moduleGraph, path) {
|
|
64
|
+
const target = moduleGraph.getModuleById(path);
|
|
65
|
+
if (target) {
|
|
66
|
+
moduleGraph.invalidateModule(target);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function invalidateModules(server, result, manifest) {
|
|
70
|
+
if (server) {
|
|
71
|
+
if (result.invalidPreload) {
|
|
72
|
+
// Environments are not limited to "client"/"ssr": plugins like nitro
|
|
73
|
+
// render in their own environment (e.g. "nitro"), so invalidate everywhere.
|
|
74
|
+
for (const environment of Object.values(server.environments)) {
|
|
75
|
+
invalidateModule(environment.moduleGraph, manifest);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function serverFunctionsPlugin(options) {
|
|
81
|
+
const filter = createFilter(options.filter?.include || DEFAULT_INCLUDE, options.filter?.exclude || DEFAULT_EXCLUDE);
|
|
82
|
+
let env;
|
|
83
|
+
const manifest = createManifest();
|
|
84
|
+
const preload = {
|
|
85
|
+
server: undefined,
|
|
86
|
+
client: undefined,
|
|
87
|
+
};
|
|
88
|
+
let currentServer;
|
|
89
|
+
const clientOptions = {
|
|
90
|
+
directive: DIRECTIVE,
|
|
91
|
+
definitions: {
|
|
92
|
+
register: {
|
|
93
|
+
kind: "named",
|
|
94
|
+
name: "createServerReference",
|
|
95
|
+
source: options.runtime.client,
|
|
96
|
+
},
|
|
97
|
+
clone: {
|
|
98
|
+
kind: "named",
|
|
99
|
+
name: "cloneServerReference",
|
|
100
|
+
source: options.runtime.client,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
const serverOptions = {
|
|
105
|
+
directive: DIRECTIVE,
|
|
106
|
+
definitions: {
|
|
107
|
+
register: {
|
|
108
|
+
kind: "named",
|
|
109
|
+
name: "createServerReference",
|
|
110
|
+
source: options.runtime.server,
|
|
111
|
+
},
|
|
112
|
+
clone: {
|
|
113
|
+
kind: "named",
|
|
114
|
+
name: "cloneServerReference",
|
|
115
|
+
source: options.runtime.server,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
return [
|
|
120
|
+
{
|
|
121
|
+
name: "solid-start:server-functions/setup",
|
|
122
|
+
enforce: "pre",
|
|
123
|
+
configResolved(config) {
|
|
124
|
+
env = config.mode !== "production" ? "development" : "production";
|
|
125
|
+
},
|
|
126
|
+
configureServer(server) {
|
|
127
|
+
currentServer = server;
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "solid-start:server-functions/preload",
|
|
132
|
+
enforce: "pre",
|
|
133
|
+
resolveId(source) {
|
|
134
|
+
if (source === options.manifest) {
|
|
135
|
+
return { id: options.manifest, moduleSideEffects: true };
|
|
136
|
+
}
|
|
137
|
+
if (source.startsWith(LOOKUP_ID)) {
|
|
138
|
+
return { id: source, moduleSideEffects: true };
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
},
|
|
142
|
+
async load(id) {
|
|
143
|
+
const mode = this.environment.config.consumer;
|
|
144
|
+
if (id === options.manifest) {
|
|
145
|
+
const current = new Debouncer(() => [...manifest[mode]].map(entry => `import "${entry}";`).join("\n"));
|
|
146
|
+
preload[mode] = current;
|
|
147
|
+
const result = await current.promise.reference;
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
if (id.startsWith(LOOKUP_ID)) {
|
|
151
|
+
if (this.environment.mode !== "dev") {
|
|
152
|
+
throw new Error(`${LOOKUP_ID} is only available in dev`);
|
|
153
|
+
}
|
|
154
|
+
const functionId = new URLSearchParams(id.slice(LOOKUP_ID.length + 1)).get("id");
|
|
155
|
+
// dev function ids are `${xxHash32(file)}-${count}-${name}`
|
|
156
|
+
const hash = functionId?.split("-")[0];
|
|
157
|
+
if (!hash)
|
|
158
|
+
return "export {};";
|
|
159
|
+
// Look through the files already discovered by the transform first;
|
|
160
|
+
// fall back to scanning the project so a function is found even when
|
|
161
|
+
// the browser kept a chunk from before a dev server restart.
|
|
162
|
+
let files = [...manifest.server].filter(file => xxHash32(file).toString(16) === hash);
|
|
163
|
+
if (files.length === 0) {
|
|
164
|
+
files = fg
|
|
165
|
+
.sync(DEFAULT_INCLUDE, { cwd: this.environment.config.root, absolute: true })
|
|
166
|
+
.filter(file => filter(file) && xxHash32(file).toString(16) === hash);
|
|
167
|
+
}
|
|
168
|
+
return files.map(file => `import ${JSON.stringify(file)};`).join("\n") || "export {};";
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "solid-start:server-functions/compiler",
|
|
175
|
+
enforce: "pre",
|
|
176
|
+
async transform(code, fileId) {
|
|
177
|
+
const mode = this.environment.config.consumer;
|
|
178
|
+
const [id] = fileId.split("?");
|
|
179
|
+
if (!filter(id)) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
const result = await compile(id, code, {
|
|
183
|
+
...(mode === "server" ? serverOptions : clientOptions),
|
|
184
|
+
mode,
|
|
185
|
+
env,
|
|
186
|
+
});
|
|
187
|
+
if (result.valid) {
|
|
188
|
+
const preloader = preload[mode];
|
|
189
|
+
if (preloader) {
|
|
190
|
+
preloader.defer();
|
|
191
|
+
}
|
|
192
|
+
invalidateModules(currentServer, mergeManifestRecord(manifest.server, new Set([id])), options.manifest);
|
|
193
|
+
return {
|
|
194
|
+
code: result.code || "",
|
|
195
|
+
map: result.map,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
];
|
|
202
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function isStatementTopLevel(path) {
|
|
2
|
+
let blockParent = path.scope.getBlockParent();
|
|
3
|
+
const programParent = path.scope.getProgramParent();
|
|
4
|
+
// a FunctionDeclaration binding refers to itself as the block parent
|
|
5
|
+
if (blockParent.path === path) {
|
|
6
|
+
blockParent = blockParent.parent;
|
|
7
|
+
}
|
|
8
|
+
return programParent === blockParent;
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type * as t from "@babel/types";
|
|
2
|
+
type TypeFilter<V extends t.Node> = (node: t.Node) => node is V;
|
|
3
|
+
export declare function isPathValid<V extends t.Node>(path: unknown, key: TypeFilter<V>): path is babel.NodePath<V>;
|
|
4
|
+
export type NestedExpression = t.ParenthesizedExpression | t.TypeCastExpression | t.TSAsExpression | t.TSSatisfiesExpression | t.TSNonNullExpression | t.TSInstantiationExpression | t.TSTypeAssertion;
|
|
5
|
+
export declare function isNestedExpression(node: t.Node): node is NestedExpression;
|
|
6
|
+
type TypeCheck<K> = K extends TypeFilter<infer U> ? U : never;
|
|
7
|
+
export declare function unwrapNode<K extends (value: t.Node) => boolean>(node: t.Node, key: K): TypeCheck<K> | undefined;
|
|
8
|
+
export declare function unwrapPath<V extends t.Node>(path: unknown, key: TypeFilter<V>): babel.NodePath<V> | undefined;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function isPathValid(path, key) {
|
|
2
|
+
const node = path.node;
|
|
3
|
+
return node ? key(node) : false;
|
|
4
|
+
}
|
|
5
|
+
export function isNestedExpression(node) {
|
|
6
|
+
switch (node.type) {
|
|
7
|
+
case "ParenthesizedExpression":
|
|
8
|
+
case "TypeCastExpression":
|
|
9
|
+
case "TSAsExpression":
|
|
10
|
+
case "TSSatisfiesExpression":
|
|
11
|
+
case "TSNonNullExpression":
|
|
12
|
+
case "TSTypeAssertion":
|
|
13
|
+
case "TSInstantiationExpression":
|
|
14
|
+
return true;
|
|
15
|
+
default:
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function unwrapNode(node, key) {
|
|
20
|
+
if (key(node)) {
|
|
21
|
+
return node;
|
|
22
|
+
}
|
|
23
|
+
if (isNestedExpression(node)) {
|
|
24
|
+
return unwrapNode(node.expression, key);
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
export function unwrapPath(path, key) {
|
|
29
|
+
if (isPathValid(path, key)) {
|
|
30
|
+
return path;
|
|
31
|
+
}
|
|
32
|
+
if (isPathValid(path, isNestedExpression)) {
|
|
33
|
+
return unwrapPath(path.get("expression"), key);
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type * as babel from "@babel/core";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
|
+
import type { ImportDefinition } from "./types.ts";
|
|
4
|
+
export interface StateContext {
|
|
5
|
+
env: "production" | "development";
|
|
6
|
+
mode: "server" | "client";
|
|
7
|
+
directive: string;
|
|
8
|
+
hash: string;
|
|
9
|
+
count: number;
|
|
10
|
+
imports: Map<string, t.Identifier>;
|
|
11
|
+
valid: boolean;
|
|
12
|
+
definitions: {
|
|
13
|
+
register: ImportDefinition;
|
|
14
|
+
clone: ImportDefinition;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface State extends babel.PluginPass {
|
|
18
|
+
opts: StateContext;
|
|
19
|
+
}
|
|
20
|
+
export declare function directivesPlugin(): babel.PluginObj<State>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { bubbleFunctionDeclaration } from "./bubble-function-declaration.js";
|
|
3
|
+
import { generateUniqueName } from "./generate-unique-name.js";
|
|
4
|
+
import { getDescriptiveName } from "./get-descriptive-name.js";
|
|
5
|
+
import { getImportIdentifier } from "./get-import-identifier.js";
|
|
6
|
+
import { getRootStatementPath } from "./get-root-statement-path.js";
|
|
7
|
+
import { isStatementTopLevel } from "./is-statement-top-level.js";
|
|
8
|
+
import { isPathValid, unwrapPath } from "./paths.js";
|
|
9
|
+
import { removeUnusedVariables } from "./remove-unused-variables.js";
|
|
10
|
+
function isValidFunction(node) {
|
|
11
|
+
return t.isArrowFunctionExpression(node) || t.isFunctionExpression(node);
|
|
12
|
+
}
|
|
13
|
+
function isDirectiveValid(ctx, directives) {
|
|
14
|
+
for (let i = 0, len = directives.length; i < len; i++) {
|
|
15
|
+
if (directives[i].value.value === ctx.directive) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function cleanDirectives(path, target) {
|
|
22
|
+
const newDirectives = [];
|
|
23
|
+
for (let i = 0, len = path.node.directives.length; i < len; i++) {
|
|
24
|
+
const current = path.node.directives[i];
|
|
25
|
+
if (current.value.value !== target) {
|
|
26
|
+
newDirectives.push(current);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
path.node.directives = newDirectives;
|
|
30
|
+
}
|
|
31
|
+
function cleanFunctionDirectives(ctx, path) {
|
|
32
|
+
const body = path.get("body");
|
|
33
|
+
if (isPathValid(body, t.isBlockStatement)) {
|
|
34
|
+
cleanDirectives(body, ctx.directive);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function isFunctionDirectiveValid(ctx, path) {
|
|
38
|
+
const body = path.get("body");
|
|
39
|
+
if (isPathValid(body, t.isBlockStatement)) {
|
|
40
|
+
return isDirectiveValid(ctx, body.node.directives);
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function createID(ctx, name) {
|
|
45
|
+
const base = `${ctx.hash}-${ctx.count++}`;
|
|
46
|
+
if (ctx.env === "development") {
|
|
47
|
+
return `${base}-${name}`;
|
|
48
|
+
}
|
|
49
|
+
return base;
|
|
50
|
+
}
|
|
51
|
+
function transformFunction(ctx, path, direct) {
|
|
52
|
+
if (!direct) {
|
|
53
|
+
if (!isFunctionDirectiveValid(ctx, path)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
cleanFunctionDirectives(ctx, path);
|
|
57
|
+
}
|
|
58
|
+
// First, get root statement
|
|
59
|
+
const rootStatement = getRootStatementPath(path);
|
|
60
|
+
// Create a unique ID for the function
|
|
61
|
+
const fnID = createID(ctx, getDescriptiveName(path, "anonymous"));
|
|
62
|
+
if (ctx.mode === "server") {
|
|
63
|
+
// Create a "source" function on the root-level
|
|
64
|
+
const sourceReference = t.callExpression(getImportIdentifier(ctx.imports, path, ctx.definitions.register), [t.stringLiteral(fnID), path.node]);
|
|
65
|
+
const sourceID = generateUniqueName(path, "serverFn");
|
|
66
|
+
rootStatement.insertBefore(t.variableDeclaration("const", [t.variableDeclarator(sourceID, sourceReference)]));
|
|
67
|
+
// Clone the source function to replace the server function
|
|
68
|
+
path.replaceWith(t.callExpression(getImportIdentifier(ctx.imports, path, ctx.definitions.clone), [sourceID]));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// Otherwise, clone the function based on its ID
|
|
72
|
+
path.replaceWith(t.callExpression(getImportIdentifier(ctx.imports, path, ctx.definitions.clone), [
|
|
73
|
+
t.stringLiteral(fnID),
|
|
74
|
+
]));
|
|
75
|
+
}
|
|
76
|
+
path.scope.crawl();
|
|
77
|
+
}
|
|
78
|
+
function traceBinding(path, name) {
|
|
79
|
+
const current = path.scope.getBinding(name);
|
|
80
|
+
if (!current) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
switch (current.kind) {
|
|
84
|
+
case "const":
|
|
85
|
+
case "let":
|
|
86
|
+
case "var": {
|
|
87
|
+
if (isPathValid(current.path, t.isVariableDeclarator)) {
|
|
88
|
+
// Check if left is identifier
|
|
89
|
+
const left = unwrapPath(current.path.get("id"), t.isIdentifier);
|
|
90
|
+
if (left) {
|
|
91
|
+
const right = unwrapPath(current.path.get("init"), t.isIdentifier);
|
|
92
|
+
if (right) {
|
|
93
|
+
return traceBinding(path, right.node.name);
|
|
94
|
+
}
|
|
95
|
+
// Only valid for functions
|
|
96
|
+
const func = unwrapPath(current.path.get("init"), isValidFunction);
|
|
97
|
+
if (func) {
|
|
98
|
+
return current;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
case "hoisted":
|
|
105
|
+
case "local":
|
|
106
|
+
case "module":
|
|
107
|
+
case "param":
|
|
108
|
+
case "unknown":
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function transformBindingForServer(ctx, binding) {
|
|
113
|
+
if (isPathValid(binding.path, t.isVariableDeclarator)) {
|
|
114
|
+
const right = unwrapPath(binding.path.get("init"), isValidFunction);
|
|
115
|
+
if (right) {
|
|
116
|
+
transformFunction(ctx, right, true);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function transformModuleLevelDirective(ctx, program) {
|
|
121
|
+
cleanDirectives(program, ctx.directive);
|
|
122
|
+
program.traverse({
|
|
123
|
+
FunctionDeclaration(child) {
|
|
124
|
+
// We only need to move top-level functions
|
|
125
|
+
if (isStatementTopLevel(child)) {
|
|
126
|
+
bubbleFunctionDeclaration(child);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
program.scope.crawl();
|
|
131
|
+
if (ctx.mode === "server") {
|
|
132
|
+
// Trace bindings
|
|
133
|
+
const bindings = new Set();
|
|
134
|
+
program.traverse({
|
|
135
|
+
ExportDefaultDeclaration(path) {
|
|
136
|
+
const id = unwrapPath(path.get("declaration"), t.isIdentifier);
|
|
137
|
+
if (id) {
|
|
138
|
+
const binding = traceBinding(path, id.node.name);
|
|
139
|
+
if (binding) {
|
|
140
|
+
bindings.add(binding);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
ExportNamedDeclaration(path) {
|
|
145
|
+
if (path.node.source || path.node.exportKind === "type") {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
for (const specifier of path.get("specifiers")) {
|
|
149
|
+
if (isPathValid(specifier, t.isExportSpecifier)) {
|
|
150
|
+
const binding = traceBinding(specifier, specifier.node.local.name);
|
|
151
|
+
if (binding) {
|
|
152
|
+
bindings.add(binding);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const declarations = path.get("declaration");
|
|
157
|
+
if (isPathValid(declarations, t.isVariableDeclaration)) {
|
|
158
|
+
for (const declaration of declarations.get("declarations")) {
|
|
159
|
+
// Check if left is identifier
|
|
160
|
+
const left = unwrapPath(declaration.get("id"), t.isIdentifier);
|
|
161
|
+
if (left) {
|
|
162
|
+
const binding = traceBinding(left, left.node.name);
|
|
163
|
+
if (binding) {
|
|
164
|
+
bindings.add(binding);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
for (const binding of bindings) {
|
|
172
|
+
transformBindingForServer(ctx, binding);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Trace bindings
|
|
177
|
+
const uniqueBindings = new Set();
|
|
178
|
+
const exportedBindings = new Map();
|
|
179
|
+
program.traverse({
|
|
180
|
+
ExportDefaultDeclaration(path) {
|
|
181
|
+
const id = unwrapPath(path.get("declaration"), t.isIdentifier);
|
|
182
|
+
if (id) {
|
|
183
|
+
const binding = traceBinding(path, id.node.name);
|
|
184
|
+
if (binding) {
|
|
185
|
+
uniqueBindings.add(binding);
|
|
186
|
+
exportedBindings.set("default", binding);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
ExportNamedDeclaration(path) {
|
|
191
|
+
if (path.node.source || path.node.exportKind === "type") {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
for (const specifier of path.get("specifiers")) {
|
|
195
|
+
if (isPathValid(specifier, t.isExportSpecifier)) {
|
|
196
|
+
const binding = traceBinding(specifier, specifier.node.local.name);
|
|
197
|
+
if (binding) {
|
|
198
|
+
const key = t.isIdentifier(specifier.node.exported)
|
|
199
|
+
? specifier.node.exported.name
|
|
200
|
+
: specifier.node.exported.value;
|
|
201
|
+
uniqueBindings.add(binding);
|
|
202
|
+
exportedBindings.set(key, binding);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const declarations = path.get("declaration");
|
|
207
|
+
if (isPathValid(declarations, t.isVariableDeclaration)) {
|
|
208
|
+
for (const declaration of declarations.get("declarations")) {
|
|
209
|
+
// Check if left is identifier
|
|
210
|
+
const left = unwrapPath(declaration.get("id"), t.isIdentifier);
|
|
211
|
+
if (left) {
|
|
212
|
+
const binding = traceBinding(left, left.node.name);
|
|
213
|
+
if (binding) {
|
|
214
|
+
uniqueBindings.add(binding);
|
|
215
|
+
exportedBindings.set(left.node.name, binding);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
// generate ids for each unique binding
|
|
223
|
+
const sourceIDs = new Map();
|
|
224
|
+
for (const binding of uniqueBindings) {
|
|
225
|
+
if (isPathValid(binding.path, t.isVariableDeclarator)) {
|
|
226
|
+
const init = unwrapPath(binding.path.get("init"), isValidFunction);
|
|
227
|
+
if (init) {
|
|
228
|
+
sourceIDs.set(binding, createID(ctx, getDescriptiveName(init, "anonymous")));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// clear body
|
|
233
|
+
program.node.body = [];
|
|
234
|
+
const declarations = [];
|
|
235
|
+
const specifiers = [];
|
|
236
|
+
const declarationMap = new Map();
|
|
237
|
+
// Declare all client functions
|
|
238
|
+
for (const [exported, binding] of exportedBindings) {
|
|
239
|
+
let currentIdentifier = declarationMap.get(binding);
|
|
240
|
+
if (!currentIdentifier) {
|
|
241
|
+
currentIdentifier = generateUniqueName(program, "fn");
|
|
242
|
+
const fnID = sourceIDs.get(binding);
|
|
243
|
+
if (fnID) {
|
|
244
|
+
declarations.push(t.variableDeclarator(currentIdentifier, t.callExpression(getImportIdentifier(ctx.imports, program, ctx.definitions.clone), [
|
|
245
|
+
t.stringLiteral(fnID),
|
|
246
|
+
])));
|
|
247
|
+
declarationMap.set(binding, currentIdentifier);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (currentIdentifier) {
|
|
251
|
+
specifiers.push(t.exportSpecifier(currentIdentifier, t.stringLiteral(exported)));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const body = [];
|
|
255
|
+
if (declarations.length > 0) {
|
|
256
|
+
body.push(t.variableDeclaration("const", declarations));
|
|
257
|
+
}
|
|
258
|
+
if (specifiers.length > 0) {
|
|
259
|
+
body.push(t.exportNamedDeclaration(null, specifiers, null));
|
|
260
|
+
}
|
|
261
|
+
program.pushContainer("body", body);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
export function directivesPlugin() {
|
|
265
|
+
return {
|
|
266
|
+
name: "solid-start:directives",
|
|
267
|
+
visitor: {
|
|
268
|
+
Program(program, ctx) {
|
|
269
|
+
const isModuleLevel = isDirectiveValid(ctx.opts, program.node.directives);
|
|
270
|
+
if (isModuleLevel) {
|
|
271
|
+
transformModuleLevelDirective(ctx.opts, program);
|
|
272
|
+
ctx.opts.valid = true;
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// First, bubble up function declarations
|
|
276
|
+
program.traverse({
|
|
277
|
+
FunctionDeclaration(child) {
|
|
278
|
+
// if (isFunctionDirectiveValid(ctx.opts, child)) {
|
|
279
|
+
bubbleFunctionDeclaration(child);
|
|
280
|
+
// }
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
program.scope.crawl();
|
|
284
|
+
// Now we transform each function
|
|
285
|
+
program.traverse({
|
|
286
|
+
ArrowFunctionExpression(path) {
|
|
287
|
+
transformFunction(ctx.opts, path, false);
|
|
288
|
+
},
|
|
289
|
+
FunctionExpression(path) {
|
|
290
|
+
transformFunction(ctx.opts, path, false);
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
program.scope.crawl();
|
|
294
|
+
if (ctx.opts.count > 0) {
|
|
295
|
+
ctx.opts.valid = true;
|
|
296
|
+
removeUnusedVariables(program);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { isPathValid } from "./paths.js";
|
|
3
|
+
function isInvalidForRemoval(path) {
|
|
4
|
+
if (isPathValid(path, t.isCatchClause)) {
|
|
5
|
+
// This case is for `catch (error)` blocks
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
// This one is for destructured variables
|
|
9
|
+
let target = path;
|
|
10
|
+
if (isPathValid(path, t.isVariableDeclarator)) {
|
|
11
|
+
target = path.get('id');
|
|
12
|
+
}
|
|
13
|
+
return isPathValid(target, t.isObjectPattern) || isPathValid(target, t.isArrayPattern);
|
|
14
|
+
}
|
|
15
|
+
export function removeUnusedVariables(program) {
|
|
16
|
+
// TODO(Alexis):
|
|
17
|
+
// This implementation is simple but slow
|
|
18
|
+
// We repeat removing unused variables from each pass
|
|
19
|
+
// until no potential unused variables are left.
|
|
20
|
+
// There might be a simpler implementation.
|
|
21
|
+
let dirty = true;
|
|
22
|
+
while (dirty) {
|
|
23
|
+
dirty = false;
|
|
24
|
+
program.traverse({
|
|
25
|
+
BindingIdentifier(path) {
|
|
26
|
+
const binding = path.scope.getBinding(path.node.name);
|
|
27
|
+
if (binding) {
|
|
28
|
+
switch (binding.kind) {
|
|
29
|
+
case "const":
|
|
30
|
+
case "let":
|
|
31
|
+
case "var":
|
|
32
|
+
case "hoisted":
|
|
33
|
+
case "module":
|
|
34
|
+
if (binding.references === 0 && !binding.path.removed) {
|
|
35
|
+
const parent = binding.path.parentPath;
|
|
36
|
+
if (isPathValid(parent, t.isImportDeclaration)) {
|
|
37
|
+
if (parent.node.specifiers.length === 1) {
|
|
38
|
+
parent.remove();
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
binding.path.remove();
|
|
42
|
+
}
|
|
43
|
+
dirty = true;
|
|
44
|
+
}
|
|
45
|
+
else if (!(isInvalidForRemoval(binding.path))) {
|
|
46
|
+
binding.path.remove();
|
|
47
|
+
dirty = true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
case "local":
|
|
52
|
+
case "param":
|
|
53
|
+
case "unknown":
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
VariableDeclaration(path) {
|
|
59
|
+
if (path.node.declarations.length === 0) {
|
|
60
|
+
path.remove();
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
program.scope.crawl();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
export interface NamedImportDefinition {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
kind: "named";
|
|
3
|
+
name: string;
|
|
4
|
+
source: string;
|
|
5
5
|
}
|
|
6
|
-
|
|
7
6
|
export interface DefaultImportDefinition {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
kind: "default";
|
|
8
|
+
source: string;
|
|
10
9
|
}
|
|
11
|
-
|
|
12
10
|
export type ImportDefinition = DefaultImportDefinition | NamedImportDefinition;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|