@solidjs/start 2.0.0-alpha.2 → 2.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/config/constants.d.ts +1 -1
- package/dist/config/constants.js +1 -1
- package/dist/config/dev-server.js +9 -1
- package/dist/config/env.d.ts +19 -0
- package/dist/config/env.js +81 -0
- package/dist/config/fs-routes/fs-watcher.js +14 -20
- package/dist/config/fs-routes/index.js +2 -2
- package/dist/config/fs-routes/router.js +2 -2
- package/dist/config/index.d.ts +16 -1
- package/dist/config/index.js +25 -27
- package/dist/config/lazy.js +2 -2
- package/dist/config/manifest.js +37 -4
- package/dist/config/vite-utils.d.ts +1 -1
- 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 +169 -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 +53 -0
- package/dist/directives/types.d.ts +10 -0
- package/dist/directives/xxhash32.d.ts +6 -0
- package/dist/directives/xxhash32.js +193 -0
- package/dist/{server/server-runtime.d.ts → fns/client.d.ts} +1 -1
- package/dist/fns/client.js +106 -0
- package/dist/fns/handler.d.ts +5 -0
- package/dist/{server/server-functions-handler.js → fns/handler.js} +55 -96
- package/dist/fns/registration.d.ts +2 -0
- package/dist/fns/registration.js +12 -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/{server/server-fns-runtime.js → fns/server.js} +7 -1
- package/dist/fns/shared.d.ts +17 -0
- package/dist/fns/shared.js +105 -0
- package/dist/http/index.d.ts +1 -1
- package/dist/middleware/index.d.ts +17 -0
- package/dist/middleware/index.js +15 -0
- package/dist/server/handler.d.ts +61 -3
- package/dist/server/handler.js +17 -15
- package/dist/server/spa/handler.d.ts +30 -1
- package/dist/server/types.d.ts +1 -1
- package/dist/shared/dev-overlay/CodeView.jsx +4 -4
- package/dist/shared/dev-overlay/DevOverlayDialog.jsx +34 -34
- package/dist/shared/dev-overlay/index.jsx +2 -2
- package/dist/shared/dev-overlay/styles.css +40 -40
- package/package.json +27 -20
- package/src/config/constants.ts +1 -1
- package/src/config/env.ts +105 -0
- package/src/config/fs-routes/fs-watcher.ts +17 -24
- package/src/config/fs-routes/index.ts +2 -2
- package/src/config/fs-routes/router.ts +2 -2
- package/src/config/index.ts +39 -37
- package/src/config/lazy.ts +2 -2
- package/src/config/manifest.ts +37 -7
- package/src/config/vite-utils.ts +1 -1
- package/src/directives/bubble-function-declaration.ts +33 -0
- package/src/directives/compile.ts +54 -0
- package/src/directives/generate-unique-name.ts +22 -0
- package/src/directives/get-descriptive-name.ts +39 -0
- package/src/directives/get-import-identifier.ts +34 -0
- package/src/directives/get-root-statement-path.ts +14 -0
- package/src/directives/index.ts +232 -0
- package/src/directives/is-statement-top-level.ts +13 -0
- package/src/directives/paths.ts +63 -0
- package/src/directives/plugin.ts +389 -0
- package/src/directives/remove-unused-variables.ts +55 -0
- package/src/directives/types.ts +12 -0
- package/src/directives/xxhash32.ts +214 -0
- package/src/env.d.ts +1 -1
- package/src/fns/client.ts +141 -0
- package/src/fns/handler.spec.ts +85 -0
- package/src/{server/server-functions-handler.ts → fns/handler.ts} +65 -117
- package/src/fns/registration.ts +19 -0
- package/src/fns/serialization.ts +250 -0
- package/src/{server/server-fns-runtime.ts → fns/server.ts} +17 -2
- package/src/fns/shared.ts +116 -0
- package/src/middleware/index.ts +17 -0
- package/src/server/handler.ts +18 -16
- package/src/server/types.ts +1 -1
- package/src/shared/dev-overlay/CodeView.tsx +5 -7
- package/src/shared/dev-overlay/DevOverlayDialog.tsx +34 -34
- package/src/shared/dev-overlay/get-source-map.ts +1 -1
- package/src/shared/dev-overlay/index.tsx +4 -4
- package/src/shared/dev-overlay/styles.css +40 -40
- package/tsconfig.json +1 -0
- package/dist/server/fetchEvent.spec.js +0 -65
- package/dist/server/server-fns-runtime.d.ts +0 -1
- package/dist/server/server-functions-handler.d.ts +0 -2
- package/dist/server/server-runtime.js +0 -194
- package/src/server/server-runtime.ts +0 -240
- /package/dist/{server/fetchEvent.spec.d.ts → directives/types.js} +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
EnvironmentModuleNode,
|
|
3
3
|
FSWatcher,
|
|
4
|
-
ModuleGraph,
|
|
5
|
-
ModuleNode,
|
|
6
4
|
PluginOption,
|
|
7
5
|
ViteDevServer,
|
|
8
6
|
} from "vite";
|
|
7
|
+
import { VITE_ENVIRONMENTS } from "../constants.ts";
|
|
9
8
|
import { moduleId } from "./index.ts";
|
|
10
9
|
import type { BaseFileSystemRouter } from "./router.ts";
|
|
11
10
|
|
|
@@ -32,30 +31,24 @@ function createRoutesReloader(
|
|
|
32
31
|
return () => routes.removeEventListener("reload", handleRoutesReload);
|
|
33
32
|
|
|
34
33
|
function handleRoutesReload(): void {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
} else {
|
|
47
|
-
// Handle client environment HMR reload
|
|
48
|
-
const { moduleGraph }: { moduleGraph: ModuleGraph } = server;
|
|
49
|
-
const mod: ModuleNode | undefined = moduleGraph.getModuleById(moduleId);
|
|
50
|
-
if (mod) {
|
|
51
|
-
const seen = new Set<ModuleNode>();
|
|
52
|
-
moduleGraph.invalidateModule(mod, seen);
|
|
53
|
-
server.reloadModule(mod);
|
|
54
|
-
}
|
|
34
|
+
const envName =
|
|
35
|
+
environment === "ssr" ? VITE_ENVIRONMENTS.server : VITE_ENVIRONMENTS.client;
|
|
36
|
+
const devEnv = server.environments[envName];
|
|
37
|
+
if (!devEnv?.moduleGraph) return;
|
|
38
|
+
|
|
39
|
+
const mod: EnvironmentModuleNode | undefined =
|
|
40
|
+
devEnv.moduleGraph.getModuleById(moduleId);
|
|
41
|
+
if (mod) {
|
|
42
|
+
const seen = new Set<EnvironmentModuleNode>();
|
|
43
|
+
devEnv.moduleGraph.invalidateModule(mod, seen);
|
|
55
44
|
}
|
|
56
45
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
46
|
+
if (environment !== "ssr") {
|
|
47
|
+
if (mod) {
|
|
48
|
+
devEnv.reloadModule(mod);
|
|
49
|
+
} else if (devEnv.hot) {
|
|
50
|
+
devEnv.hot.send({ type: "full-reload" });
|
|
51
|
+
}
|
|
59
52
|
}
|
|
60
53
|
}
|
|
61
54
|
}
|
|
@@ -55,8 +55,8 @@ export function fsRoutes({ routers }: FsRoutesArgs): Array<PluginOption> {
|
|
|
55
55
|
const buildId = `${v.src}?${v.pick.map((p: any) => `pick=${p}`).join("&")}`;
|
|
56
56
|
return {
|
|
57
57
|
src: relative(root, buildId),
|
|
58
|
-
build: isBuild ? `_$() => import(
|
|
59
|
-
import: `_$() => import(
|
|
58
|
+
build: isBuild ? `_$() => import('${buildId}')$_` : undefined,
|
|
59
|
+
import: `_$() => import('${buildId}')$_`,
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
return v;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { init, parse } from "es-module-lexer";
|
|
2
2
|
import esbuild from "esbuild";
|
|
3
3
|
import fg from "fast-glob";
|
|
4
|
-
import fs from "fs";
|
|
4
|
+
import fs from "node:fs";
|
|
5
5
|
import micromatch from "micromatch";
|
|
6
|
-
import { posix } from "path";
|
|
6
|
+
import { posix } from "node:path";
|
|
7
7
|
import { pathToRegexp } from "path-to-regexp";
|
|
8
8
|
|
|
9
9
|
import { normalizePath } from "vite";
|
package/src/config/index.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { TanStackServerFnPlugin } from "@tanstack/server-functions-plugin";
|
|
2
1
|
import { defu } from "defu";
|
|
3
2
|
import { globSync } from "node:fs";
|
|
4
3
|
import { extname, isAbsolute, join } from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
import { normalizePath, type PluginOption } from "vite";
|
|
4
|
+
import type { PluginOption } from "vite";
|
|
7
5
|
import solid, { type Options as SolidOptions } from "vite-plugin-solid";
|
|
8
|
-
|
|
6
|
+
import { type ServerFunctionsOptions, serverFunctionsPlugin } from "../directives/index.ts";
|
|
9
7
|
import { DEFAULT_EXTENSIONS, VIRTUAL_MODULES, VITE_ENVIRONMENTS } from "./constants.ts";
|
|
10
8
|
import { devServer } from "./dev-server.ts";
|
|
9
|
+
import { envPlugin, type EnvPluginOptions } from "./env.ts";
|
|
11
10
|
import { SolidStartClientFileRouter, SolidStartServerFileRouter } from "./fs-router.ts";
|
|
12
11
|
import { fsRoutes } from "./fs-routes/index.ts";
|
|
13
12
|
import type { BaseFileSystemRouter } from "./fs-routes/router.ts";
|
|
@@ -21,6 +20,19 @@ export interface SolidStartOptions {
|
|
|
21
20
|
routeDir?: string;
|
|
22
21
|
extensions?: string[];
|
|
23
22
|
middleware?: string;
|
|
23
|
+
serialization?: {
|
|
24
|
+
/**
|
|
25
|
+
* The serialization mode to use for server functions/actions.
|
|
26
|
+
* The "js" mode uses a custom binary format that is more efficient than JSON, but requires a custom deserializer (with `eval()`) on the client.
|
|
27
|
+
* A strong CSP should block `eval()` executions, which would prevent the "js" mode from working.
|
|
28
|
+
* The "json" mode uses JSON for serialization, which is less efficient but can be deserialized with `JSON.parse` on the client.
|
|
29
|
+
*
|
|
30
|
+
* @default "json"
|
|
31
|
+
*/
|
|
32
|
+
mode?: "js" | "json";
|
|
33
|
+
};
|
|
34
|
+
env?: EnvPluginOptions;
|
|
35
|
+
serverFunctions?: Pick<ServerFunctionsOptions, "filter">;
|
|
24
36
|
}
|
|
25
37
|
|
|
26
38
|
const absolute = (path: string, root: string) =>
|
|
@@ -80,6 +92,16 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
80
92
|
return {
|
|
81
93
|
appType: "custom",
|
|
82
94
|
build: { assetsDir: "_build/assets" },
|
|
95
|
+
optimizeDeps: {
|
|
96
|
+
// Suppress TS errors from Vite 7 types when configuring Vite 8's Rolldown
|
|
97
|
+
...({
|
|
98
|
+
rolldownOptions: {
|
|
99
|
+
transform: {
|
|
100
|
+
jsx: "react",
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
} as any),
|
|
104
|
+
},
|
|
83
105
|
environments: {
|
|
84
106
|
[VITE_ENVIRONMENTS.client]: {
|
|
85
107
|
consumer: "client",
|
|
@@ -122,6 +144,9 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
122
144
|
}
|
|
123
145
|
: {}),
|
|
124
146
|
},
|
|
147
|
+
// Depending on the package manager and dependency structure Vite externalizes @solidjs/start
|
|
148
|
+
// This makes sure that @solidjs/start goes through the Vite build process
|
|
149
|
+
noExternal: ["@solidjs/start"],
|
|
125
150
|
},
|
|
126
151
|
define: {
|
|
127
152
|
"import.meta.env.MANIFEST": `globalThis.MANIFEST`,
|
|
@@ -131,6 +156,7 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
131
156
|
"import.meta.env.START_APP_ENTRY": JSON.stringify(appEntryPath),
|
|
132
157
|
"import.meta.env.START_CLIENT_ENTRY": JSON.stringify(handlers.client),
|
|
133
158
|
"import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
|
|
159
|
+
"import.meta.env.SEROVAL_MODE": JSON.stringify(start.serialization?.mode || "json"),
|
|
134
160
|
},
|
|
135
161
|
builder: {
|
|
136
162
|
sharedPlugins: true,
|
|
@@ -163,41 +189,16 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
163
189
|
},
|
|
164
190
|
}),
|
|
165
191
|
lazy(),
|
|
192
|
+
envPlugin(options?.env),
|
|
166
193
|
// Must be placed after fsRoutes, as treeShake will remove the
|
|
167
194
|
// server fn exports added in by this plugin
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
callers: [
|
|
174
|
-
{
|
|
175
|
-
envConsumer: "client",
|
|
176
|
-
envName: VITE_ENVIRONMENTS.client,
|
|
177
|
-
getRuntimeCode: () =>
|
|
178
|
-
`import { createServerReference } from "${normalizePath(
|
|
179
|
-
fileURLToPath(new URL("../server/server-runtime", import.meta.url))
|
|
180
|
-
)}"`,
|
|
181
|
-
replacer: opts => `createServerReference('${opts.functionId}')`,
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
envConsumer: "server",
|
|
185
|
-
envName: VITE_ENVIRONMENTS.server,
|
|
186
|
-
getRuntimeCode: () =>
|
|
187
|
-
`import { createServerReference } from '${normalizePath(
|
|
188
|
-
fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url))
|
|
189
|
-
)}'`,
|
|
190
|
-
replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
|
|
191
|
-
},
|
|
192
|
-
],
|
|
193
|
-
provider: {
|
|
194
|
-
envName: VITE_ENVIRONMENTS.server,
|
|
195
|
-
getRuntimeCode: () =>
|
|
196
|
-
`import { createServerReference } from '${normalizePath(
|
|
197
|
-
fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url))
|
|
198
|
-
)}'`,
|
|
199
|
-
replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
|
|
195
|
+
serverFunctionsPlugin({
|
|
196
|
+
manifest: VIRTUAL_MODULES.serverFnManifest,
|
|
197
|
+
runtime: {
|
|
198
|
+
server: '@solidjs/start/fns/server',
|
|
199
|
+
client: '@solidjs/start/fns/client',
|
|
200
200
|
},
|
|
201
|
+
filter: options?.serverFunctions?.filter,
|
|
201
202
|
}),
|
|
202
203
|
{
|
|
203
204
|
name: "solid-start:virtual-modules",
|
|
@@ -221,8 +222,9 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
221
222
|
{
|
|
222
223
|
name: "solid-start:capture-client-bundle",
|
|
223
224
|
enforce: "post",
|
|
224
|
-
generateBundle(
|
|
225
|
+
generateBundle(options, bundle) {
|
|
225
226
|
globalThis.START_CLIENT_BUNDLE = bundle;
|
|
227
|
+
(globalThis as any).START_CLIENT_OUT_DIR = options.dir;
|
|
226
228
|
},
|
|
227
229
|
},
|
|
228
230
|
devServer(),
|
package/src/config/lazy.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { PluginItem } from "@babel/core";
|
|
2
2
|
import babel from "@babel/core";
|
|
3
3
|
import * as t from "@babel/types";
|
|
4
|
-
import { sep as osSep } from "path";
|
|
5
|
-
import { basename, relative, sep } from "path/posix";
|
|
4
|
+
import { sep as osSep } from "node:path";
|
|
5
|
+
import { basename, relative, sep } from "node:path/posix";
|
|
6
6
|
import type { PluginOption } from "vite";
|
|
7
7
|
import { VITE_ENVIRONMENTS } from "./constants.ts";
|
|
8
8
|
|
package/src/config/manifest.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { type PluginOption, type ViteDevServer, version as viteVersion } from "vite";
|
|
2
4
|
|
|
3
5
|
import { findStylesInModuleGraph } from "../server/collect-styles.ts";
|
|
4
6
|
import { VIRTUAL_MODULES } from "./constants.ts";
|
|
@@ -40,9 +42,37 @@ export function manifest(start: SolidStartOptions): PluginOption {
|
|
|
40
42
|
v => "isEntry" in v && v.isEntry,
|
|
41
43
|
);
|
|
42
44
|
if (!entry) throw new Error("No client entry found");
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
45
|
+
let rawManifest: string | undefined;
|
|
46
|
+
|
|
47
|
+
const viteMajor = parseInt(viteVersion.split('.')[0]!, 10);
|
|
48
|
+
|
|
49
|
+
const manifestKey = Object.keys(globalThis.START_CLIENT_BUNDLE).find(k => k.endsWith("manifest.json"));
|
|
50
|
+
if (manifestKey && viteMajor < 8) {
|
|
51
|
+
const manifestAsset = globalThis.START_CLIENT_BUNDLE[manifestKey] as any;
|
|
52
|
+
rawManifest = manifestAsset.source as string;
|
|
53
|
+
} else {
|
|
54
|
+
try {
|
|
55
|
+
const appRoot = (start as any).appRoot || "./src";
|
|
56
|
+
let outDir = ".solid-start/client";
|
|
57
|
+
if (devServer?.environments?.client?.config?.build?.outDir) {
|
|
58
|
+
outDir = devServer.environments.client.config.build.outDir;
|
|
59
|
+
} else if (this.environment?.config?.build?.outDir && this.environment?.config?.consumer === "client") {
|
|
60
|
+
outDir = this.environment.config.build.outDir;
|
|
61
|
+
} else if ((globalThis as any).START_CLIENT_OUT_DIR) {
|
|
62
|
+
outDir = (globalThis as any).START_CLIENT_OUT_DIR;
|
|
63
|
+
}
|
|
64
|
+
const manifestPath = path.resolve(appRoot, "..", outDir, ".vite/manifest.json");
|
|
65
|
+
rawManifest = fs.readFileSync(manifestPath, "utf-8");
|
|
66
|
+
} catch (e) {
|
|
67
|
+
throw new Error(`Manifest asset not found in bundle and could not be read from disk. Keys: ${Object.keys(globalThis.START_CLIENT_BUNDLE).join(", ")}. Error: ${e}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!rawManifest) {
|
|
72
|
+
throw new Error("Failed to extract or read raw manifest.");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
clientViteManifest = JSON.parse(rawManifest);
|
|
46
76
|
}
|
|
47
77
|
return `export const clientViteManifest = ${JSON.stringify(clientViteManifest)};`;
|
|
48
78
|
} else if (id === `\0${VIRTUAL_MODULES.middleware}`) return "export default {};";
|
|
@@ -50,11 +80,11 @@ export function manifest(start: SolidStartOptions): PluginOption {
|
|
|
50
80
|
if (this.environment.mode !== "dev")
|
|
51
81
|
throw new Error("@manifest queries are only allowed in dev");
|
|
52
82
|
|
|
53
|
-
const [
|
|
83
|
+
const [urlPath, query] = id.split("?");
|
|
54
84
|
const target = id.split("/")[2]!;
|
|
55
85
|
const params = new URLSearchParams(query);
|
|
56
|
-
if (!
|
|
57
|
-
if (
|
|
86
|
+
if (!urlPath || !query) return;
|
|
87
|
+
if (urlPath.endsWith("assets")) {
|
|
58
88
|
const id = params.get("id");
|
|
59
89
|
if (!id) {
|
|
60
90
|
throw new Error("Missing id to get assets.");
|
package/src/config/vite-utils.ts
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type * as babel from "@babel/core";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
|
+
|
|
4
|
+
export function bubbleFunctionDeclaration(path: babel.NodePath<t.FunctionDeclaration>): void {
|
|
5
|
+
const decl = path.node;
|
|
6
|
+
// Check if declaration is FunctionDeclaration
|
|
7
|
+
if (decl.id) {
|
|
8
|
+
const block = (path.findParent(current => current.isBlockStatement()) ||
|
|
9
|
+
path.scope.getProgramParent().path) as babel.NodePath<t.BlockStatement>;
|
|
10
|
+
|
|
11
|
+
if (path.parentPath.isExportNamedDeclaration()) {
|
|
12
|
+
path.parentPath.replaceWith(
|
|
13
|
+
t.exportNamedDeclaration(undefined, [t.exportSpecifier(decl.id, decl.id)]),
|
|
14
|
+
);
|
|
15
|
+
} else if (path.parentPath.isExportDefaultDeclaration()) {
|
|
16
|
+
path.replaceWith(decl.id);
|
|
17
|
+
} else {
|
|
18
|
+
path.remove();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const [tmp] = block.unshiftContainer(
|
|
22
|
+
"body",
|
|
23
|
+
t.variableDeclaration("const", [
|
|
24
|
+
t.variableDeclarator(
|
|
25
|
+
decl.id,
|
|
26
|
+
t.functionExpression(decl.id, decl.params, decl.body, decl.generator, decl.async),
|
|
27
|
+
),
|
|
28
|
+
]),
|
|
29
|
+
);
|
|
30
|
+
block.scope.registerDeclaration(tmp);
|
|
31
|
+
tmp.skip();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as babel from "@babel/core";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { directivesPlugin, type StateContext } from "./plugin.ts";
|
|
4
|
+
import xxHash32 from "./xxhash32.ts";
|
|
5
|
+
|
|
6
|
+
export interface CompileResult {
|
|
7
|
+
valid: boolean;
|
|
8
|
+
code: string;
|
|
9
|
+
map: babel.BabelFileResult["map"];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type CompileOptions = Omit<StateContext, "count" | "hash" | "imports" | "valid">;
|
|
13
|
+
|
|
14
|
+
export async function compile(
|
|
15
|
+
id: string,
|
|
16
|
+
code: string,
|
|
17
|
+
options: CompileOptions,
|
|
18
|
+
): Promise<CompileResult> {
|
|
19
|
+
const context: StateContext = {
|
|
20
|
+
...options,
|
|
21
|
+
valid: false,
|
|
22
|
+
hash: xxHash32(id).toString(16),
|
|
23
|
+
count: 0,
|
|
24
|
+
imports: new Map(),
|
|
25
|
+
};
|
|
26
|
+
const pluginOption = [directivesPlugin, context];
|
|
27
|
+
const plugins: NonNullable<NonNullable<babel.TransformOptions["parserOpts"]>["plugins"]> = [
|
|
28
|
+
"jsx",
|
|
29
|
+
];
|
|
30
|
+
if (/\.[mc]?tsx?$/i.test(id)) {
|
|
31
|
+
plugins.push("typescript");
|
|
32
|
+
}
|
|
33
|
+
const result = await babel.transformAsync(code, {
|
|
34
|
+
plugins: [pluginOption],
|
|
35
|
+
parserOpts: {
|
|
36
|
+
plugins,
|
|
37
|
+
},
|
|
38
|
+
filename: path.basename(id),
|
|
39
|
+
ast: false,
|
|
40
|
+
sourceMaps: true,
|
|
41
|
+
configFile: false,
|
|
42
|
+
babelrc: false,
|
|
43
|
+
sourceFileName: id,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (result) {
|
|
47
|
+
return {
|
|
48
|
+
valid: context.valid,
|
|
49
|
+
code: result.code || "",
|
|
50
|
+
map: result.map,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
throw new Error("invariant");
|
|
54
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type * as babel from "@babel/core";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
|
+
|
|
4
|
+
export function generateUniqueName(path: babel.NodePath, name: string): t.Identifier {
|
|
5
|
+
let uid: string;
|
|
6
|
+
let i = 1;
|
|
7
|
+
do {
|
|
8
|
+
uid = name + "_" + i;
|
|
9
|
+
i++;
|
|
10
|
+
} while (
|
|
11
|
+
path.scope.hasLabel(uid) ||
|
|
12
|
+
path.scope.hasBinding(uid) ||
|
|
13
|
+
path.scope.hasGlobal(uid) ||
|
|
14
|
+
path.scope.hasReference(uid)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const program = path.scope.getProgramParent();
|
|
18
|
+
program.references[uid] = true;
|
|
19
|
+
program.uids[uid] = true;
|
|
20
|
+
|
|
21
|
+
return t.identifier(uid);
|
|
22
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { NodePath } from "@babel/core";
|
|
2
|
+
|
|
3
|
+
export function getDescriptiveName(path: NodePath, defaultName: string): string {
|
|
4
|
+
let current: NodePath | null = path;
|
|
5
|
+
while (current) {
|
|
6
|
+
switch (current.node.type) {
|
|
7
|
+
case "FunctionDeclaration":
|
|
8
|
+
case "FunctionExpression": {
|
|
9
|
+
if (current.node.id) {
|
|
10
|
+
return current.node.id.name;
|
|
11
|
+
}
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
case "VariableDeclarator": {
|
|
15
|
+
if (current.node.id.type === "Identifier") {
|
|
16
|
+
return current.node.id.name;
|
|
17
|
+
}
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
case "ClassPrivateMethod":
|
|
21
|
+
case "ClassMethod":
|
|
22
|
+
case "ObjectMethod": {
|
|
23
|
+
switch (current.node.key.type) {
|
|
24
|
+
case "Identifier":
|
|
25
|
+
return current.node.key.name;
|
|
26
|
+
case "PrivateName":
|
|
27
|
+
return current.node.key.id.name;
|
|
28
|
+
default:
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
default:
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
current = current.parentPath;
|
|
37
|
+
}
|
|
38
|
+
return defaultName;
|
|
39
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type * as babel from "@babel/core";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
|
+
import { generateUniqueName } from "./generate-unique-name.ts";
|
|
4
|
+
import type { ImportDefinition } from "./types.ts";
|
|
5
|
+
|
|
6
|
+
export function getImportIdentifier(
|
|
7
|
+
imports: Map<string, t.Identifier>,
|
|
8
|
+
path: babel.NodePath,
|
|
9
|
+
registration: ImportDefinition,
|
|
10
|
+
): t.Identifier {
|
|
11
|
+
const name = registration.kind === "named" ? registration.name : "default";
|
|
12
|
+
const target = `${registration.source}[${name}]`;
|
|
13
|
+
const current = imports.get(target);
|
|
14
|
+
if (current) {
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
const programParent = path.scope.getProgramParent();
|
|
18
|
+
const uid = generateUniqueName(programParent.path, name);
|
|
19
|
+
programParent.registerDeclaration(
|
|
20
|
+
(programParent.path as babel.NodePath<t.Program>).unshiftContainer(
|
|
21
|
+
"body",
|
|
22
|
+
t.importDeclaration(
|
|
23
|
+
[
|
|
24
|
+
registration.kind === "named"
|
|
25
|
+
? t.importSpecifier(uid, t.identifier(registration.name))
|
|
26
|
+
: t.importDefaultSpecifier(uid),
|
|
27
|
+
],
|
|
28
|
+
t.stringLiteral(registration.source),
|
|
29
|
+
),
|
|
30
|
+
)[0],
|
|
31
|
+
);
|
|
32
|
+
imports.set(target, uid);
|
|
33
|
+
return uid;
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type * as babel from "@babel/core";
|
|
2
|
+
import * as t from "@babel/types";
|
|
3
|
+
|
|
4
|
+
export function getRootStatementPath(path: babel.NodePath): babel.NodePath {
|
|
5
|
+
let current = path.parentPath;
|
|
6
|
+
while (current) {
|
|
7
|
+
const next = current.parentPath;
|
|
8
|
+
if (next && t.isProgram(next.node)) {
|
|
9
|
+
return current;
|
|
10
|
+
}
|
|
11
|
+
current = next;
|
|
12
|
+
}
|
|
13
|
+
return path;
|
|
14
|
+
}
|