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/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
# solid-tag-runtime Architecture
|
|
2
|
+
|
|
3
|
+
This file is the engineering handoff and design record for `solid-tag-runtime`.
|
|
4
|
+
|
|
5
|
+
**Maintenance rule:** update this document whenever we change the public runtime API, module record model, module resolution/linking semantics, execution backend, compiler adapter contract, caching/invalidation behavior, supported source formats, host-module behavior, or an important architectural invariant.
|
|
6
|
+
|
|
7
|
+
## 1. Purpose
|
|
8
|
+
|
|
9
|
+
`solid-tag-runtime` provides a runtime ES-module-like environment for source modules that may contain ordinary Solid JSX.
|
|
10
|
+
|
|
11
|
+
It is intentionally separate from `solid-tag`:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
solid-tag
|
|
15
|
+
syntax transformation
|
|
16
|
+
JSX → @solidjs/html tagged templates
|
|
17
|
+
|
|
18
|
+
solid-tag-runtime
|
|
19
|
+
module definition
|
|
20
|
+
dependency resolution
|
|
21
|
+
linking
|
|
22
|
+
execution
|
|
23
|
+
caching
|
|
24
|
+
invalidation
|
|
25
|
+
host-module injection
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The runtime's primary abstraction is a **module**, not a component. Components are normal exports of modules.
|
|
29
|
+
|
|
30
|
+
## 2. Goals
|
|
31
|
+
|
|
32
|
+
The runtime should allow applications to:
|
|
33
|
+
|
|
34
|
+
1. define JSX source modules from strings
|
|
35
|
+
2. import those modules and receive module namespace objects
|
|
36
|
+
3. allow one runtime module to import another runtime module
|
|
37
|
+
4. expose the host application's existing Solid runtime to dynamic source
|
|
38
|
+
5. expose host components, signals, callbacks, services, and data as modules
|
|
39
|
+
6. reuse compiled/evaluated modules through caching
|
|
40
|
+
7. invalidate and rebuild a module graph when source changes
|
|
41
|
+
8. inspect dependencies and compiled source
|
|
42
|
+
9. support normal JavaScript modules in the same graph
|
|
43
|
+
10. keep the JSX compiler replaceable behind a narrow adapter
|
|
44
|
+
|
|
45
|
+
## 3. Non-goals for the first version
|
|
46
|
+
|
|
47
|
+
The initial package does not attempt to provide:
|
|
48
|
+
|
|
49
|
+
- a Vite/Rollup/esbuild integration
|
|
50
|
+
- a security sandbox
|
|
51
|
+
- Node package resolution
|
|
52
|
+
- automatic npm installation
|
|
53
|
+
- automatic unresolved-variable scope rewriting
|
|
54
|
+
- circular runtime source-module support
|
|
55
|
+
- transparent live replacement of already-held component references
|
|
56
|
+
- full HMR propagation semantics
|
|
57
|
+
- script-tag discovery/registration
|
|
58
|
+
|
|
59
|
+
These may be added later without changing the module-first public model.
|
|
60
|
+
|
|
61
|
+
## 4. Package relationship
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
Application
|
|
65
|
+
│
|
|
66
|
+
├── host Solid runtime
|
|
67
|
+
│ ├── solid-js
|
|
68
|
+
│ ├── @solidjs/web
|
|
69
|
+
│ └── @solidjs/html
|
|
70
|
+
│
|
|
71
|
+
└── solid-tag-runtime
|
|
72
|
+
│
|
|
73
|
+
├── solid-tag
|
|
74
|
+
│ └── JSX → html``
|
|
75
|
+
│
|
|
76
|
+
└── runtime module graph
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`solid-tag-runtime` depends on `solid-tag` but deliberately does not depend on or bundle its own copy of Solid.
|
|
80
|
+
|
|
81
|
+
The host application can register its existing Solid namespaces:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
runtime.defineModule("solid-js", Solid);
|
|
85
|
+
runtime.defineModule("@solidjs/web", SolidWeb);
|
|
86
|
+
runtime.defineModule("@solidjs/html", { default: html });
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This avoids duplicate Solid runtimes.
|
|
90
|
+
|
|
91
|
+
## 5. Public API model
|
|
92
|
+
|
|
93
|
+
The first API surface is centered on `createRuntime()`:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const runtime = createRuntime(options);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Source modules
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
runtime.define(id, source, options?);
|
|
103
|
+
runtime.update(id, source, options?);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Host namespace modules
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
runtime.defineModule(id, namespace);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### URL/native modules
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
runtime.defineUrl(id, url);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Loading
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
await runtime.import(id);
|
|
122
|
+
await runtime.toModule(source, options?);
|
|
123
|
+
await runtime.toComponent(source, options?);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Tooling/introspection
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
await runtime.compile(id);
|
|
130
|
+
runtime.modules();
|
|
131
|
+
runtime.dependencies(id);
|
|
132
|
+
runtime.dependents(id);
|
|
133
|
+
runtime.getModuleInfo(id);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Lifecycle
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
runtime.invalidate(id);
|
|
140
|
+
runtime.dispose();
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## 6. Module kinds
|
|
144
|
+
|
|
145
|
+
The runtime currently has three module record kinds.
|
|
146
|
+
|
|
147
|
+
### 6.1 Source module
|
|
148
|
+
|
|
149
|
+
A string containing JavaScript with optional JSX:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
runtime.define("/Button.jsx", source);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Source modules are analyzed, linked, optionally transformed with `solid-tag`, converted to a module URL, and evaluated by the native module loader.
|
|
156
|
+
|
|
157
|
+
### 6.2 Host module
|
|
158
|
+
|
|
159
|
+
An already-existing namespace/object from the application:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
runtime.defineModule("@app/components", {
|
|
163
|
+
Button,
|
|
164
|
+
Card,
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The runtime generates a tiny bridge ES module which reads those values from a runtime-specific registry on `globalThis` and re-exports them.
|
|
169
|
+
|
|
170
|
+
The bridge lets native dynamic modules import application-owned JavaScript references without serializing them.
|
|
171
|
+
|
|
172
|
+
### 6.3 URL module
|
|
173
|
+
|
|
174
|
+
A module ID mapped directly to a URL:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
runtime.defineUrl("lib", "https://example.test/lib.js");
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The runtime rewrites imports of `lib` to that URL and lets the native module loader handle it.
|
|
181
|
+
|
|
182
|
+
## 7. Source formats
|
|
183
|
+
|
|
184
|
+
### `jsx`
|
|
185
|
+
|
|
186
|
+
Default.
|
|
187
|
+
|
|
188
|
+
The runtime links imports, then passes source through the compiler adapter. The default compiler adapter is `solid-tag` and injects `@solidjs/html` when JSX is transformed.
|
|
189
|
+
|
|
190
|
+
### `js`
|
|
191
|
+
|
|
192
|
+
No JSX transformation. Imports are still resolved and rewritten through the runtime module graph.
|
|
193
|
+
|
|
194
|
+
This permits ordinary JavaScript and JSX modules to coexist in one graph.
|
|
195
|
+
|
|
196
|
+
## 8. Compiler adapter boundary
|
|
197
|
+
|
|
198
|
+
The runtime engine itself does not depend on Acorn or the `solid-tag` AST.
|
|
199
|
+
|
|
200
|
+
It requires a compiler adapter with two operations:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
interface RuntimeCompiler {
|
|
204
|
+
analyze(source, context): {
|
|
205
|
+
imports: ImportReference[];
|
|
206
|
+
needsHtmlRuntime?: boolean;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
transform(source, context): {
|
|
210
|
+
code: string;
|
|
211
|
+
diagnostics?: unknown[];
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
The default adapter lives in `src/compiler.js` and uses:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
solid-tag.parseJSX()
|
|
220
|
+
solid-tag.transformModule()
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Why this boundary exists
|
|
224
|
+
|
|
225
|
+
It allows future compiler implementations without rewriting the runtime module system.
|
|
226
|
+
|
|
227
|
+
Possible future adapters include:
|
|
228
|
+
|
|
229
|
+
- a TSX-capable `solid-tag` backend
|
|
230
|
+
- another JSX parser
|
|
231
|
+
- pre-tagged source processing
|
|
232
|
+
- reverse/tagged transformations for tooling
|
|
233
|
+
|
|
234
|
+
The module graph must remain independent of parser details.
|
|
235
|
+
|
|
236
|
+
## 9. Linking pipeline
|
|
237
|
+
|
|
238
|
+
For a source module `/features/Counter.jsx`:
|
|
239
|
+
|
|
240
|
+
```text
|
|
241
|
+
source
|
|
242
|
+
↓
|
|
243
|
+
compiler.analyze()
|
|
244
|
+
↓
|
|
245
|
+
collect static imports / re-exports / literal dynamic imports
|
|
246
|
+
↓
|
|
247
|
+
resolve each specifier
|
|
248
|
+
↓
|
|
249
|
+
ensure virtual dependencies have module URLs
|
|
250
|
+
↓
|
|
251
|
+
rewrite import string literals to linked URLs
|
|
252
|
+
↓
|
|
253
|
+
solid-tag transformation (for JSX format)
|
|
254
|
+
↓
|
|
255
|
+
create native module URL
|
|
256
|
+
↓
|
|
257
|
+
import(moduleUrl)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Example graph:
|
|
261
|
+
|
|
262
|
+
```text
|
|
263
|
+
/features/Counter.jsx
|
|
264
|
+
├── solid-js → host bridge module
|
|
265
|
+
├── @solidjs/html → host bridge module
|
|
266
|
+
└── ../ui/Button.jsx → compiled virtual source URL
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## 10. Resolution rules
|
|
270
|
+
|
|
271
|
+
Resolution order is conceptually:
|
|
272
|
+
|
|
273
|
+
1. custom `resolve()` callback
|
|
274
|
+
2. exact registered module ID
|
|
275
|
+
3. absolute URL
|
|
276
|
+
4. absolute virtual path
|
|
277
|
+
5. relative path resolved against the importing virtual module
|
|
278
|
+
6. unresolved bare import left native when `allowNativeImports === true`
|
|
279
|
+
7. otherwise resolution error
|
|
280
|
+
|
|
281
|
+
Relative virtual resolution uses POSIX-style paths regardless of the host operating system.
|
|
282
|
+
|
|
283
|
+
This keeps module IDs stable in browsers and on Windows hosts.
|
|
284
|
+
|
|
285
|
+
## 11. Native ESM execution backend
|
|
286
|
+
|
|
287
|
+
The first execution backend deliberately relies on the JavaScript engine's native ESM evaluator rather than `new Function()`.
|
|
288
|
+
|
|
289
|
+
Browser default:
|
|
290
|
+
|
|
291
|
+
```text
|
|
292
|
+
compiled source
|
|
293
|
+
↓
|
|
294
|
+
Blob
|
|
295
|
+
↓
|
|
296
|
+
blob: URL
|
|
297
|
+
↓
|
|
298
|
+
import(blobUrl)
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Node/test default:
|
|
302
|
+
|
|
303
|
+
```text
|
|
304
|
+
compiled source
|
|
305
|
+
↓
|
|
306
|
+
data:text/javascript URL
|
|
307
|
+
↓
|
|
308
|
+
import(dataUrl)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The URL creation mechanism is abstracted by `ModuleUrlBackend` so another execution strategy can be supplied later.
|
|
312
|
+
|
|
313
|
+
### Why native modules
|
|
314
|
+
|
|
315
|
+
Benefits:
|
|
316
|
+
|
|
317
|
+
- real module namespace objects
|
|
318
|
+
- native `import` / `export` behavior for the supported graph
|
|
319
|
+
- top-level code is evaluated as a module
|
|
320
|
+
- no `eval` / `new Function()` runtime wrapper
|
|
321
|
+
- clean `toModule()` semantics
|
|
322
|
+
|
|
323
|
+
## 12. Circular dependency limitation
|
|
324
|
+
|
|
325
|
+
Virtual source module cycles are explicitly rejected in v0.0.1.
|
|
326
|
+
|
|
327
|
+
Reason: the current linker must know the final URL of dependencies before it can create a module's immutable Blob/data URL. A cycle requires module identities to exist before final source URLs can be constructed.
|
|
328
|
+
|
|
329
|
+
Example currently rejected:
|
|
330
|
+
|
|
331
|
+
```text
|
|
332
|
+
/A.jsx → /B.jsx → /A.jsx
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Future options:
|
|
336
|
+
|
|
337
|
+
1. runtime linker/backend instead of native URL rewriting
|
|
338
|
+
2. service-worker-backed stable virtual URLs
|
|
339
|
+
3. an internal module server
|
|
340
|
+
4. another backend capable of stable preallocated module identities
|
|
341
|
+
|
|
342
|
+
Do not add ad-hoc cycle handling that breaks module semantics; change the backend deliberately.
|
|
343
|
+
|
|
344
|
+
## 13. Host module bridges
|
|
345
|
+
|
|
346
|
+
`defineModule()` stores the namespace in a runtime-specific registry:
|
|
347
|
+
|
|
348
|
+
```text
|
|
349
|
+
globalThis.__solidTagRuntimeHostModules__
|
|
350
|
+
↓
|
|
351
|
+
runtimeId
|
|
352
|
+
↓
|
|
353
|
+
moduleId
|
|
354
|
+
↓
|
|
355
|
+
namespace object
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
A generated bridge module re-exports identifier-safe properties.
|
|
359
|
+
|
|
360
|
+
### Important invariant
|
|
361
|
+
|
|
362
|
+
Host values are passed as **references**, not serialized copies.
|
|
363
|
+
|
|
364
|
+
This is what allows dynamic source to import:
|
|
365
|
+
|
|
366
|
+
- signal accessor functions
|
|
367
|
+
- setters
|
|
368
|
+
- stores
|
|
369
|
+
- components
|
|
370
|
+
- callbacks
|
|
371
|
+
- objects/services
|
|
372
|
+
|
|
373
|
+
### Current limitation
|
|
374
|
+
|
|
375
|
+
The ES module bridge captures each exported property value when the bridge module evaluates. Mutating the namespace object later does not create ESM live bindings.
|
|
376
|
+
|
|
377
|
+
To replace exports, call `defineModule()` again. This invalidates dependent runtime modules.
|
|
378
|
+
|
|
379
|
+
## 14. Scope injection design choice
|
|
380
|
+
|
|
381
|
+
The runtime does not automatically turn unknown identifiers into scope lookups.
|
|
382
|
+
|
|
383
|
+
Rejected initial design:
|
|
384
|
+
|
|
385
|
+
```tsx
|
|
386
|
+
<div>{hostVariable}</div>
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
with compiler magic rewriting `hostVariable` to `scope.hostVariable`.
|
|
390
|
+
|
|
391
|
+
Chosen design:
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
runtime.defineModule("@app/scope", {
|
|
395
|
+
hostVariable,
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
and runtime source explicitly imports it:
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
import { hostVariable } from "@app/scope";
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Reasons:
|
|
406
|
+
|
|
407
|
+
- explicit dependencies
|
|
408
|
+
- no lexical-scope guessing
|
|
409
|
+
- easier module graph introspection
|
|
410
|
+
- actual JavaScript references cross the boundary
|
|
411
|
+
- components and state use the same mechanism
|
|
412
|
+
- fewer compiler responsibilities
|
|
413
|
+
|
|
414
|
+
A future convenience API may create scope modules automatically, but it should still compile down to module semantics.
|
|
415
|
+
|
|
416
|
+
## 15. Dependency graph
|
|
417
|
+
|
|
418
|
+
Each record tracks:
|
|
419
|
+
|
|
420
|
+
```text
|
|
421
|
+
record.dependencies
|
|
422
|
+
record.dependents
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
When linking `/App.jsx` imports `/Button.jsx`:
|
|
426
|
+
|
|
427
|
+
```text
|
|
428
|
+
/App.jsx.dependencies includes /Button.jsx
|
|
429
|
+
/Button.jsx.dependents includes /App.jsx
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
These edges power invalidation and tooling.
|
|
433
|
+
|
|
434
|
+
## 16. Caching
|
|
435
|
+
|
|
436
|
+
A source module caches:
|
|
437
|
+
|
|
438
|
+
- analyzed/linked compiled source
|
|
439
|
+
- generated module URL
|
|
440
|
+
- import promise
|
|
441
|
+
- loaded namespace when directly imported through the runtime
|
|
442
|
+
|
|
443
|
+
Repeated imports use the same module URL/import promise until invalidated.
|
|
444
|
+
|
|
445
|
+
Native ESM also caches imports by URL.
|
|
446
|
+
|
|
447
|
+
## 17. Invalidation and updates
|
|
448
|
+
|
|
449
|
+
Updating a module invalidates:
|
|
450
|
+
|
|
451
|
+
1. that module's generated URL/import cache
|
|
452
|
+
2. dependent runtime modules recursively
|
|
453
|
+
|
|
454
|
+
The next `runtime.import(entry)` rebuilds the affected graph with new URLs.
|
|
455
|
+
|
|
456
|
+
### Important invariant
|
|
457
|
+
|
|
458
|
+
Already-held module namespaces/components are not mutated.
|
|
459
|
+
|
|
460
|
+
Example:
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
const old = await runtime.import("/App.jsx");
|
|
464
|
+
runtime.update("/Button.jsx", newSource);
|
|
465
|
+
const fresh = await runtime.import("/App.jsx");
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
`old.App` remains the old module identity. `fresh.App` comes from the rebuilt graph.
|
|
469
|
+
|
|
470
|
+
This is deliberate and matches the immutable identity of native evaluated modules.
|
|
471
|
+
|
|
472
|
+
## 18. `toModule()` semantics
|
|
473
|
+
|
|
474
|
+
`toModule(source)` is sugar for:
|
|
475
|
+
|
|
476
|
+
```text
|
|
477
|
+
generate anonymous module ID
|
|
478
|
+
↓
|
|
479
|
+
runtime.define(id, source)
|
|
480
|
+
↓
|
|
481
|
+
runtime.import(id)
|
|
482
|
+
↓
|
|
483
|
+
return module namespace
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
It is asynchronous by design.
|
|
487
|
+
|
|
488
|
+
## 19. `toComponent()` semantics
|
|
489
|
+
|
|
490
|
+
`toComponent()` calls `toModule()` and returns a selected callable export.
|
|
491
|
+
|
|
492
|
+
Default:
|
|
493
|
+
|
|
494
|
+
```text
|
|
495
|
+
exportName = "default"
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Named exports require an explicit `exportName`.
|
|
499
|
+
|
|
500
|
+
The runtime does not guess between multiple component exports.
|
|
501
|
+
|
|
502
|
+
## 20. Security model
|
|
503
|
+
|
|
504
|
+
`solid-tag-runtime` is **not a sandbox**.
|
|
505
|
+
|
|
506
|
+
Dynamic source executes as JavaScript in the page/module environment and has whatever capabilities its imports/globals provide.
|
|
507
|
+
|
|
508
|
+
Do not use this package to execute untrusted hostile code without a separate isolation mechanism such as a suitably sandboxed iframe/worker/process boundary.
|
|
509
|
+
|
|
510
|
+
## 21. CSP considerations
|
|
511
|
+
|
|
512
|
+
The browser backend currently uses Blob module URLs by default.
|
|
513
|
+
|
|
514
|
+
Applications with strict Content Security Policy may need:
|
|
515
|
+
|
|
516
|
+
- an allowed `blob:` module policy, or
|
|
517
|
+
- a custom `ModuleUrlBackend`, or
|
|
518
|
+
- a future stable virtual-module backend
|
|
519
|
+
|
|
520
|
+
The public module API should not depend on Blob URLs so this backend can change later.
|
|
521
|
+
|
|
522
|
+
## 22. Future directions
|
|
523
|
+
|
|
524
|
+
Potential additions, in rough architectural order:
|
|
525
|
+
|
|
526
|
+
### Stable/cycle-capable module backend
|
|
527
|
+
|
|
528
|
+
Needed before claiming full ESM graph compatibility.
|
|
529
|
+
|
|
530
|
+
### URL fetching/loading
|
|
531
|
+
|
|
532
|
+
Possible API:
|
|
533
|
+
|
|
534
|
+
```ts
|
|
535
|
+
await runtime.load("/App.jsx");
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
with configurable fetch/source providers.
|
|
539
|
+
|
|
540
|
+
### Script-tag module registration
|
|
541
|
+
|
|
542
|
+
Possible declarative zero-build API:
|
|
543
|
+
|
|
544
|
+
```html
|
|
545
|
+
<script type="solid-jsx" module="/Button.jsx">...</script>
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
implemented as a thin source-provider layer over the same runtime graph.
|
|
549
|
+
|
|
550
|
+
### Runtime update/HMR helpers
|
|
551
|
+
|
|
552
|
+
Graph invalidation already exists. Future APIs can add lifecycle hooks and entry re-rendering without changing module identity rules.
|
|
553
|
+
|
|
554
|
+
### Tagged-source modules
|
|
555
|
+
|
|
556
|
+
A format for source that already contains `html\`\`` templates and only needs module linking/execution.
|
|
557
|
+
|
|
558
|
+
### TSX compiler adapter
|
|
559
|
+
|
|
560
|
+
The runtime compiler boundary allows a future TSX-capable transformer without coupling module linking to TypeScript or another parser.
|
|
561
|
+
|
|
562
|
+
### Bidirectional JSX/tagged tooling
|
|
563
|
+
|
|
564
|
+
If `solid-tag` later gains tagged-template → JSX transformation, runtime/editor tooling can expose source views without changing module execution semantics.
|
|
565
|
+
|
|
566
|
+
## 23. Decision log
|
|
567
|
+
|
|
568
|
+
### 2026-10-02 — Separate runtime package
|
|
569
|
+
|
|
570
|
+
Decision: create `solid-tag-runtime` instead of adding module execution to `solid-tag`.
|
|
571
|
+
|
|
572
|
+
Reason: keep syntax transformation small and reusable while allowing the runtime package to grow a module graph, execution backend, caching, and lifecycle APIs.
|
|
573
|
+
|
|
574
|
+
### 2026-10-02 — Modules are the primary abstraction
|
|
575
|
+
|
|
576
|
+
Decision: components are module exports; there is no separate component registry at the linker level.
|
|
577
|
+
|
|
578
|
+
Reason: normal imports/exports naturally solve component composition and also work for utilities, state, and services.
|
|
579
|
+
|
|
580
|
+
### 2026-10-02 — Host Solid is injected as modules
|
|
581
|
+
|
|
582
|
+
Decision: do not bundle a private Solid runtime in `solid-tag-runtime`.
|
|
583
|
+
|
|
584
|
+
Reason: dynamically compiled components must share the host application's reactive ownership/runtime graph.
|
|
585
|
+
|
|
586
|
+
### 2026-10-02 — Scope is represented as modules
|
|
587
|
+
|
|
588
|
+
Decision: prefer `defineModule("@app/scope", values)` plus explicit imports instead of compiler rewriting of unresolved identifiers.
|
|
589
|
+
|
|
590
|
+
Reason: explicit, inspectable dependency semantics and fewer compiler responsibilities.
|
|
591
|
+
|
|
592
|
+
### 2026-10-02 — Native ESM URL backend first
|
|
593
|
+
|
|
594
|
+
Decision: use Blob URLs in browsers and data URLs in Node/tests.
|
|
595
|
+
|
|
596
|
+
Reason: preserve real module namespaces and avoid `new Function()` while the API remains backend-independent.
|
|
597
|
+
|
|
598
|
+
### 2026-10-02 — Circular virtual dependencies deferred
|
|
599
|
+
|
|
600
|
+
Decision: reject cycles rather than emulate them incorrectly.
|
|
601
|
+
|
|
602
|
+
Reason: the current immutable URL linker cannot assign stable module identities before the full cyclic graph is linked.
|
|
603
|
+
|
|
604
|
+
### 2026-10-02 — Compiler adapter boundary
|
|
605
|
+
|
|
606
|
+
Decision: the runtime engine consumes `analyze()` and `transform()` rather than importing parser internals directly.
|
|
607
|
+
|
|
608
|
+
Reason: preserve the option to add TSX, tagged-source, or alternative transformer backends later.
|