solid-tag-runtime 0.0.1
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/ARCHITECTURE.md +608 -0
- package/README.md +324 -0
- package/index.d.ts +119 -0
- package/package.json +55 -0
- package/src/compiler.js +77 -0
- package/src/errors.js +32 -0
- package/src/index.js +21 -0
- package/src/runtime.js +591 -0
- package/src/url-backend.js +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# solid-tag-runtime
|
|
2
|
+
|
|
3
|
+
`solid-tag-runtime` is a small runtime module system for applications that want to load, compose, and execute Solid JSX modules dynamically in the browser.
|
|
4
|
+
|
|
5
|
+
It builds on [`solid-tag`](https://www.npmjs.com/package/solid-tag):
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
JSX source modules
|
|
9
|
+
↓
|
|
10
|
+
solid-tag
|
|
11
|
+
↓
|
|
12
|
+
JavaScript containing html``
|
|
13
|
+
↓
|
|
14
|
+
solid-tag-runtime module linker
|
|
15
|
+
↓
|
|
16
|
+
@solidjs/html + the host application's Solid runtime
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The package is intentionally runtime-oriented. It is not a build plugin and does not require a traditional application compilation workflow for the dynamic modules it executes.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install solid-tag-runtime solid-tag
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`solid-tag-runtime` does **not** install its own copy of Solid. A host application can expose its already-loaded Solid modules with `defineModule()` so dynamically loaded components share the same reactive runtime.
|
|
28
|
+
|
|
29
|
+
## Create a runtime
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { createRuntime } from "solid-tag-runtime";
|
|
33
|
+
|
|
34
|
+
const runtime = createRuntime();
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For a real Solid application, register the host runtime:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import * as Solid from "solid-js";
|
|
41
|
+
import * as SolidWeb from "@solidjs/web";
|
|
42
|
+
import html from "@solidjs/html";
|
|
43
|
+
|
|
44
|
+
const runtime = createRuntime({
|
|
45
|
+
modules: {
|
|
46
|
+
"solid-js": Solid,
|
|
47
|
+
"@solidjs/web": SolidWeb,
|
|
48
|
+
"@solidjs/html": { default: html },
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This is important: dynamic modules now use the **same** `solid-js`, `@solidjs/web`, and `@solidjs/html` instances as the host application.
|
|
54
|
+
|
|
55
|
+
## Define and import runtime modules
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
runtime.define(
|
|
59
|
+
"/ui/Button.jsx",
|
|
60
|
+
`
|
|
61
|
+
export function Button(props) {
|
|
62
|
+
return (
|
|
63
|
+
<button onClick={props.onClick}>
|
|
64
|
+
{props.children}
|
|
65
|
+
</button>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
`,
|
|
69
|
+
);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
A second module can import the first one normally:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
runtime.define(
|
|
76
|
+
"/features/Counter.jsx",
|
|
77
|
+
`
|
|
78
|
+
import { createSignal } from "solid-js";
|
|
79
|
+
import { Button } from "../ui/Button.jsx";
|
|
80
|
+
|
|
81
|
+
export function Counter() {
|
|
82
|
+
const [count, setCount] = createSignal(0);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<Button onClick={() => setCount(value => value + 1)}>
|
|
86
|
+
Count: {count()}
|
|
87
|
+
</Button>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
`,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const counterModule = await runtime.import("/features/Counter.jsx");
|
|
94
|
+
|
|
95
|
+
counterModule.Counter;
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The runtime compiles and links the dependency graph automatically.
|
|
99
|
+
|
|
100
|
+
## `toModule()`
|
|
101
|
+
|
|
102
|
+
For one-off source strings:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
const module = await runtime.toModule(`
|
|
106
|
+
export function MyComponent(props) {
|
|
107
|
+
return <>{props.message} {props.name}</>;
|
|
108
|
+
}
|
|
109
|
+
`);
|
|
110
|
+
|
|
111
|
+
const MyComponent = module.MyComponent;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`toModule()` creates an anonymous runtime module, compiles it with `solid-tag`, evaluates it as a real ES module, and returns the module namespace.
|
|
115
|
+
|
|
116
|
+
It is asynchronous because the runtime preserves ES-module-style evaluation rather than using `new Function()`.
|
|
117
|
+
|
|
118
|
+
## `toComponent()`
|
|
119
|
+
|
|
120
|
+
For the common single-component case:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const MyComponent = await runtime.toComponent(
|
|
124
|
+
`
|
|
125
|
+
export function MyComponent(props) {
|
|
126
|
+
return <div>{props.message}</div>;
|
|
127
|
+
}
|
|
128
|
+
`,
|
|
129
|
+
{ exportName: "MyComponent" },
|
|
130
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
For a default export:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const Counter = await runtime.toComponent(`
|
|
137
|
+
export default function Counter() {
|
|
138
|
+
return <button>Count</button>;
|
|
139
|
+
}
|
|
140
|
+
`);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Inject application values as modules
|
|
144
|
+
|
|
145
|
+
The runtime deliberately does not rewrite unresolved identifiers into a magical scope object.
|
|
146
|
+
|
|
147
|
+
Instead, application scope can be expressed as a normal module:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
const [count, setCount] = createSignal(0);
|
|
151
|
+
|
|
152
|
+
runtime.defineModule("@app/state", {
|
|
153
|
+
count,
|
|
154
|
+
setCount,
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Runtime source imports those references normally:
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
import { count, setCount } from "@app/state";
|
|
162
|
+
|
|
163
|
+
export function Counter() {
|
|
164
|
+
return (
|
|
165
|
+
<button onClick={() => setCount(value => value + 1)}>
|
|
166
|
+
{count()}
|
|
167
|
+
</button>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
This works for:
|
|
173
|
+
|
|
174
|
+
- Solid signals and setters
|
|
175
|
+
- stores
|
|
176
|
+
- components
|
|
177
|
+
- callbacks
|
|
178
|
+
- services
|
|
179
|
+
- data objects
|
|
180
|
+
- application utilities
|
|
181
|
+
|
|
182
|
+
The values cross the boundary as actual JavaScript references; they are not serialized.
|
|
183
|
+
|
|
184
|
+
## Expose existing components
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
runtime.defineModule("@app/components", {
|
|
188
|
+
Button,
|
|
189
|
+
Dialog,
|
|
190
|
+
Card,
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Then runtime JSX can use them like any other module:
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { Button } from "@app/components";
|
|
198
|
+
|
|
199
|
+
export function SaveButton() {
|
|
200
|
+
return <Button>Save</Button>;
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## URL modules
|
|
205
|
+
|
|
206
|
+
A package or external library can be mapped to a native ESM URL:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
runtime.defineUrl(
|
|
210
|
+
"some-library",
|
|
211
|
+
"https://esm.sh/some-library@1.2.3",
|
|
212
|
+
);
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Then dynamic modules can write:
|
|
216
|
+
|
|
217
|
+
```js
|
|
218
|
+
import something from "some-library";
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Plain JavaScript modules
|
|
222
|
+
|
|
223
|
+
JSX transformation can be disabled per module:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
runtime.define(
|
|
227
|
+
"/config.js",
|
|
228
|
+
`export const value = 42;`,
|
|
229
|
+
{ format: "js" },
|
|
230
|
+
);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
This is useful when the same runtime graph contains both JSX-backed modules and ordinary JavaScript modules.
|
|
234
|
+
|
|
235
|
+
## Compilation without execution
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
runtime.define("/App.jsx", source);
|
|
239
|
+
|
|
240
|
+
const compiled = await runtime.compile("/App.jsx");
|
|
241
|
+
|
|
242
|
+
console.log(compiled.code);
|
|
243
|
+
console.log(compiled.dependencies);
|
|
244
|
+
console.log(compiled.diagnostics);
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This is useful for editors, debugging tools, and inspecting the exact `html\`\`` output generated by `solid-tag`.
|
|
248
|
+
|
|
249
|
+
## Module graph introspection
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
runtime.modules();
|
|
253
|
+
runtime.dependencies("/App.jsx");
|
|
254
|
+
runtime.dependents("/ui/Button.jsx");
|
|
255
|
+
runtime.getModuleInfo("/App.jsx");
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Updating modules
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
runtime.update("/ui/Button.jsx", newButtonSource);
|
|
262
|
+
|
|
263
|
+
const app = await runtime.import("/App.jsx");
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Updating a module invalidates its compiled URL and its dependent runtime modules. Re-importing produces a newly linked graph.
|
|
267
|
+
|
|
268
|
+
Existing references to an older module namespace/component are not mutated. Applications that implement live editing should import the updated entry module again.
|
|
269
|
+
|
|
270
|
+
## Custom resolution
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
const runtime = createRuntime({
|
|
274
|
+
resolve(specifier, importer) {
|
|
275
|
+
if (specifier.startsWith("@ui/")) {
|
|
276
|
+
return `/ui/${specifier.slice(4)}`;
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Default runtime resolution supports:
|
|
283
|
+
|
|
284
|
+
- exact virtual module IDs
|
|
285
|
+
- relative virtual imports
|
|
286
|
+
- absolute virtual paths
|
|
287
|
+
- registered URL modules
|
|
288
|
+
- native/bare imports when `allowNativeImports` is enabled
|
|
289
|
+
|
|
290
|
+
## Native imports
|
|
291
|
+
|
|
292
|
+
`allowNativeImports` defaults to `true`.
|
|
293
|
+
|
|
294
|
+
This means an unresolved bare import can be left for the browser's native module resolver/import map:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
const runtime = createRuntime({
|
|
298
|
+
allowNativeImports: true,
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Set it to `false` when all module dependencies must be explicitly registered with the runtime.
|
|
303
|
+
|
|
304
|
+
## Runtime lifecycle
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
runtime.invalidate("/App.jsx");
|
|
308
|
+
runtime.dispose();
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`dispose()` revokes generated module URLs and clears the host-module registry for that runtime instance.
|
|
312
|
+
|
|
313
|
+
## Current limitations
|
|
314
|
+
|
|
315
|
+
The first version deliberately keeps module semantics constrained:
|
|
316
|
+
|
|
317
|
+
- circular dependencies between runtime-defined source modules are not supported yet
|
|
318
|
+
- generated modules normally use Blob URLs in browsers, so CSP must permit the chosen execution strategy
|
|
319
|
+
- host-module export bridges expose the export values present when the bridge module is created; redefining the host module invalidates dependents
|
|
320
|
+
- module updates create new module identities; already-held namespaces/components remain the old version
|
|
321
|
+
- TypeScript/TSX parsing depends on what the underlying `solid-tag` compiler supports
|
|
322
|
+
- this package is **not a security sandbox**; loaded source executes with the privileges of the page
|
|
323
|
+
|
|
324
|
+
See [`ARCHITECTURE.md`](./ARCHITECTURE.md) for the detailed design and decision log.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export type ModuleFormat = "jsx" | "js";
|
|
2
|
+
|
|
3
|
+
export interface ModuleNamespaceLike {
|
|
4
|
+
readonly [key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface CompilerImportReference {
|
|
8
|
+
specifier: string;
|
|
9
|
+
start: number;
|
|
10
|
+
end: number;
|
|
11
|
+
kind?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface RuntimeCompiler {
|
|
15
|
+
analyze(source: string, context?: { id?: string; format?: ModuleFormat }): {
|
|
16
|
+
imports?: CompilerImportReference[];
|
|
17
|
+
needsHtmlRuntime?: boolean;
|
|
18
|
+
};
|
|
19
|
+
transform(source: string, context?: {
|
|
20
|
+
id?: string;
|
|
21
|
+
format?: ModuleFormat;
|
|
22
|
+
htmlImportSource?: string;
|
|
23
|
+
}): {
|
|
24
|
+
code: string;
|
|
25
|
+
diagnostics?: unknown[];
|
|
26
|
+
changed?: boolean;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ModuleUrlBackend {
|
|
31
|
+
readonly kind?: string;
|
|
32
|
+
create(code: string, id?: string): string;
|
|
33
|
+
revoke?(url: string): void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface RuntimeOptions {
|
|
37
|
+
compiler?: RuntimeCompiler;
|
|
38
|
+
compilerOptions?: Record<string, unknown>;
|
|
39
|
+
modules?: Record<string, ModuleNamespaceLike | Function>;
|
|
40
|
+
urls?: Record<string, string>;
|
|
41
|
+
allowNativeImports?: boolean;
|
|
42
|
+
resolve?: (specifier: string, importer: string | null, runtime: SolidTagRuntime) => string | void;
|
|
43
|
+
moduleUrlBackend?: ModuleUrlBackend;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface DefineOptions {
|
|
47
|
+
format?: ModuleFormat;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ToModuleOptions extends DefineOptions {
|
|
51
|
+
id?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface ToComponentOptions extends ToModuleOptions {
|
|
55
|
+
exportName?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ModuleInfo {
|
|
59
|
+
id: string;
|
|
60
|
+
kind: "source" | "host" | "url";
|
|
61
|
+
state: string;
|
|
62
|
+
version: number;
|
|
63
|
+
format?: ModuleFormat;
|
|
64
|
+
dependencies: string[];
|
|
65
|
+
dependents: string[];
|
|
66
|
+
url?: string;
|
|
67
|
+
diagnostics: unknown[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface CompileResult {
|
|
71
|
+
id: string;
|
|
72
|
+
kind: "source" | "host" | "url";
|
|
73
|
+
code?: string;
|
|
74
|
+
url?: string;
|
|
75
|
+
dependencies: string[];
|
|
76
|
+
diagnostics: unknown[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface SolidTagRuntime {
|
|
80
|
+
define(id: string, source: string, options?: DefineOptions): string;
|
|
81
|
+
update(id: string, source: string, options?: DefineOptions): string;
|
|
82
|
+
defineModule(id: string, namespace: ModuleNamespaceLike | Function): string;
|
|
83
|
+
defineUrl(id: string, url: string): string;
|
|
84
|
+
import(id: string): Promise<ModuleNamespaceLike>;
|
|
85
|
+
compile(id: string): Promise<CompileResult>;
|
|
86
|
+
toModule(source: string, options?: ToModuleOptions): Promise<ModuleNamespaceLike>;
|
|
87
|
+
toComponent<T extends Function = Function>(source: string, options?: ToComponentOptions): Promise<T>;
|
|
88
|
+
has(id: string): boolean;
|
|
89
|
+
invalidate(id: string, options?: { dependents?: boolean }): string[];
|
|
90
|
+
modules(): ModuleInfo[];
|
|
91
|
+
dependencies(id: string): string[];
|
|
92
|
+
dependents(id: string): string[];
|
|
93
|
+
getModuleInfo(id: string): ModuleInfo | undefined;
|
|
94
|
+
resolve(specifier: string, importer?: string | null): string;
|
|
95
|
+
dispose(): void;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export declare function createRuntime(options?: RuntimeOptions): SolidTagRuntime;
|
|
99
|
+
export declare function createRuntimeCore(options: RuntimeOptions & { compiler: RuntimeCompiler }): SolidTagRuntime;
|
|
100
|
+
export declare function createSolidTagCompiler(options?: {
|
|
101
|
+
tag?: string;
|
|
102
|
+
transformOptions?: Record<string, unknown>;
|
|
103
|
+
}): RuntimeCompiler;
|
|
104
|
+
|
|
105
|
+
export declare function createDefaultModuleUrlBackend(): ModuleUrlBackend;
|
|
106
|
+
export declare function createBlobModuleUrlBackend(): ModuleUrlBackend;
|
|
107
|
+
export declare function createDataModuleUrlBackend(): ModuleUrlBackend;
|
|
108
|
+
|
|
109
|
+
export declare class SolidTagRuntimeError extends Error {}
|
|
110
|
+
export declare class ModuleResolutionError extends SolidTagRuntimeError {
|
|
111
|
+
specifier: string;
|
|
112
|
+
importer: string | null;
|
|
113
|
+
}
|
|
114
|
+
export declare class CircularDependencyError extends SolidTagRuntimeError {
|
|
115
|
+
cycle: string[];
|
|
116
|
+
}
|
|
117
|
+
export declare class ModuleCompileError extends SolidTagRuntimeError {
|
|
118
|
+
id: string;
|
|
119
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "solid-tag-runtime",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Runtime module system for JSX modules compiled with solid-tag and executed through @solidjs/html",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
|
+
"import": "./src/index.js",
|
|
10
|
+
"default": "./src/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./compiler": {
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"import": "./src/compiler.js",
|
|
15
|
+
"default": "./src/compiler.js"
|
|
16
|
+
},
|
|
17
|
+
"./runtime": {
|
|
18
|
+
"types": "./index.d.ts",
|
|
19
|
+
"import": "./src/runtime.js",
|
|
20
|
+
"default": "./src/runtime.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"main": "./src/index.js",
|
|
24
|
+
"module": "./src/index.js",
|
|
25
|
+
"types": "./index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"src",
|
|
28
|
+
"index.d.ts",
|
|
29
|
+
"README.md",
|
|
30
|
+
"ARCHITECTURE.md"
|
|
31
|
+
],
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"solid-tag": "^0.0.1"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"test": "node ./test/run.mjs",
|
|
38
|
+
"pack:check": "npm pack --dry-run"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"solid",
|
|
42
|
+
"solidjs",
|
|
43
|
+
"jsx",
|
|
44
|
+
"runtime",
|
|
45
|
+
"module",
|
|
46
|
+
"tagged-template",
|
|
47
|
+
"browser"
|
|
48
|
+
],
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/compiler.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { parseJSX, transformModule } from "solid-tag";
|
|
2
|
+
|
|
3
|
+
export function createSolidTagCompiler(options = {}) {
|
|
4
|
+
const {
|
|
5
|
+
tag = "html",
|
|
6
|
+
transformOptions = {},
|
|
7
|
+
} = options;
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
analyze(source) {
|
|
11
|
+
const ast = parseJSX(source);
|
|
12
|
+
const imports = [];
|
|
13
|
+
let needsHtmlRuntime = false;
|
|
14
|
+
walk(ast, node => {
|
|
15
|
+
if (node.type === "JSXElement" || node.type === "JSXFragment") needsHtmlRuntime = true;
|
|
16
|
+
if (
|
|
17
|
+
(node.type === "ImportDeclaration" ||
|
|
18
|
+
node.type === "ExportNamedDeclaration" ||
|
|
19
|
+
node.type === "ExportAllDeclaration") &&
|
|
20
|
+
node.source &&
|
|
21
|
+
typeof node.source.value === "string"
|
|
22
|
+
) {
|
|
23
|
+
imports.push({
|
|
24
|
+
specifier: node.source.value,
|
|
25
|
+
start: node.source.start,
|
|
26
|
+
end: node.source.end,
|
|
27
|
+
kind: node.type,
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
node.type === "ImportExpression" &&
|
|
34
|
+
node.source &&
|
|
35
|
+
(node.source.type === "Literal" || node.source.type === "StringLiteral") &&
|
|
36
|
+
typeof node.source.value === "string"
|
|
37
|
+
) {
|
|
38
|
+
imports.push({
|
|
39
|
+
specifier: node.source.value,
|
|
40
|
+
start: node.source.start,
|
|
41
|
+
end: node.source.end,
|
|
42
|
+
kind: "ImportExpression",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return { imports, needsHtmlRuntime };
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
transform(source, context = {}) {
|
|
51
|
+
return transformModule(source, {
|
|
52
|
+
...transformOptions,
|
|
53
|
+
tag,
|
|
54
|
+
injectHtmlImport: true,
|
|
55
|
+
htmlImportSource: context.htmlImportSource ?? "@solidjs/html",
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function walk(node, visit) {
|
|
62
|
+
if (!node || typeof node !== "object") return;
|
|
63
|
+
visit(node);
|
|
64
|
+
|
|
65
|
+
for (const [key, value] of Object.entries(node)) {
|
|
66
|
+
if (key === "loc" || key === "range" || key === "parent") continue;
|
|
67
|
+
if (!value) continue;
|
|
68
|
+
|
|
69
|
+
if (Array.isArray(value)) {
|
|
70
|
+
for (const child of value) {
|
|
71
|
+
if (child && typeof child === "object" && typeof child.type === "string") walk(child, visit);
|
|
72
|
+
}
|
|
73
|
+
} else if (typeof value === "object" && typeof value.type === "string") {
|
|
74
|
+
walk(value, visit);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/errors.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class SolidTagRuntimeError extends Error {
|
|
2
|
+
constructor(message, options = {}) {
|
|
3
|
+
super(message, options);
|
|
4
|
+
this.name = "SolidTagRuntimeError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class ModuleResolutionError extends SolidTagRuntimeError {
|
|
9
|
+
constructor(specifier, importer, message) {
|
|
10
|
+
super(message ?? `Could not resolve module ${JSON.stringify(specifier)} from ${JSON.stringify(importer ?? "<runtime>")}.`);
|
|
11
|
+
this.name = "ModuleResolutionError";
|
|
12
|
+
this.specifier = specifier;
|
|
13
|
+
this.importer = importer ?? null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class CircularDependencyError extends SolidTagRuntimeError {
|
|
18
|
+
constructor(cycle) {
|
|
19
|
+
super(`Circular virtual module dependency is not supported yet: ${cycle.join(" -> ")}`);
|
|
20
|
+
this.name = "CircularDependencyError";
|
|
21
|
+
this.cycle = [...cycle];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class ModuleCompileError extends SolidTagRuntimeError {
|
|
26
|
+
constructor(id, cause) {
|
|
27
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
28
|
+
super(`Failed to compile module ${JSON.stringify(id)}: ${detail}`, { cause });
|
|
29
|
+
this.name = "ModuleCompileError";
|
|
30
|
+
this.id = id;
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createSolidTagCompiler } from "./compiler.js";
|
|
2
|
+
import { createRuntime as createRuntimeCore } from "./runtime.js";
|
|
3
|
+
|
|
4
|
+
export function createRuntime(options = {}) {
|
|
5
|
+
const compiler = options.compiler ?? createSolidTagCompiler(options.compilerOptions);
|
|
6
|
+
return createRuntimeCore({ ...options, compiler });
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { createSolidTagCompiler } from "./compiler.js";
|
|
10
|
+
export { createRuntime as createRuntimeCore } from "./runtime.js";
|
|
11
|
+
export {
|
|
12
|
+
createDefaultModuleUrlBackend,
|
|
13
|
+
createBlobModuleUrlBackend,
|
|
14
|
+
createDataModuleUrlBackend,
|
|
15
|
+
} from "./url-backend.js";
|
|
16
|
+
export {
|
|
17
|
+
SolidTagRuntimeError,
|
|
18
|
+
ModuleResolutionError,
|
|
19
|
+
CircularDependencyError,
|
|
20
|
+
ModuleCompileError,
|
|
21
|
+
} from "./errors.js";
|