solid-tag-runtime 0.0.12 → 0.0.14
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 +243 -39
- package/README.md +122 -885
- package/docs/README.md +26 -0
- package/docs/api/compile-cache.md +103 -0
- package/docs/api/html.md +89 -0
- package/docs/api/runtime.md +87 -0
- package/docs/api/solid.md +71 -0
- package/docs/compile-cache.md +271 -0
- package/docs/getting-started.md +112 -0
- package/docs/html-runtime.md +120 -0
- package/docs/lifecycle-events.md +77 -0
- package/docs/modules.md +93 -0
- package/docs/rendering.md +71 -0
- package/docs/solid-render.md +111 -0
- package/docs/solid-runtime-setup.md +181 -0
- package/docs/wrapperless-delegation.md +81 -0
- package/examples/basic.js +41 -0
- package/examples/compile-cache.js +35 -0
- package/examples/main.tsx +318 -0
- package/examples/render.html +79 -0
- package/examples/solid-runtime.js +24 -0
- package/index.d.ts +183 -27
- package/package.json +11 -3
- package/solid.d.ts +77 -0
- package/src/compile-cache.js +340 -0
- package/src/compiler.js +86 -38
- package/src/html/delegated-events.js +69 -0
- package/src/html/delegation-host.js +29 -0
- package/src/index.js +6 -0
- package/src/render.js +4 -0
- package/src/runtime.js +656 -74
- package/src/solid/import-map.js +29 -0
- package/src/solid/index.js +67 -0
- package/src/solid/integration.js +30 -0
- package/src/solid/packages.js +24 -0
- package/src/solid/providers/esm-sh.js +81 -0
- package/src/solid/providers/index.js +22 -0
- package/src/solid/providers/jsdelivr.js +45 -0
- package/src/solid/resolve.js +287 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -44,7 +44,9 @@ The runtime should allow applications to:
|
|
|
44
44
|
11. support normal JavaScript modules in the same graph
|
|
45
45
|
12. declaratively mount runtime component exports through the HTML adapter
|
|
46
46
|
13. reuse existing runtime modules through a light-DOM `solid-render` custom element
|
|
47
|
-
14.
|
|
47
|
+
14. optionally resolve a coherent standard Solid package family without teaching the core runtime about providers
|
|
48
|
+
15. lazily establish Solid 2 delegated-event infrastructure for wrapperless range mounts while preserving independent reactive roots
|
|
49
|
+
16. keep the JSX compiler replaceable behind a narrow adapter
|
|
48
50
|
|
|
49
51
|
## 3. Current non-goals
|
|
50
52
|
|
|
@@ -58,6 +60,8 @@ The initial package does not attempt to provide:
|
|
|
58
60
|
- circular runtime source-module support
|
|
59
61
|
- transparent live replacement of already-held component references
|
|
60
62
|
- full HMR propagation semantics
|
|
63
|
+
- provider/CDN policy inside the core `createRuntime()` implementation
|
|
64
|
+
- automatic import-map mutation
|
|
61
65
|
|
|
62
66
|
These may be added later without changing the module-first public model. HTML script discovery was added in `0.0.2` as a separate browser adapter rather than as a responsibility of the core module engine.
|
|
63
67
|
|
|
@@ -69,7 +73,11 @@ Application
|
|
|
69
73
|
├── host Solid runtime
|
|
70
74
|
│ ├── solid-js
|
|
71
75
|
│ ├── @solidjs/web
|
|
72
|
-
│
|
|
76
|
+
│ ├── @solidjs/html
|
|
77
|
+
│ └── @solidjs/signals
|
|
78
|
+
│
|
|
79
|
+
├── solid-tag-runtime/solid (optional setup/provider integration)
|
|
80
|
+
│ └── resolves host namespaces, then calls the normal runtime
|
|
73
81
|
│
|
|
74
82
|
└── solid-tag-runtime
|
|
75
83
|
│
|
|
@@ -153,6 +161,39 @@ runtime.dispose();
|
|
|
153
161
|
|
|
154
162
|
Lifecycle subscriptions are synchronous observational notifications. They do not intercept or modify runtime behavior. Resolution behavior remains customizable through `resolve()`, compilation through the compiler adapter, and executable-module creation through `ModuleUrlBackend`.
|
|
155
163
|
|
|
164
|
+
### Optional Solid integration subpath
|
|
165
|
+
|
|
166
|
+
`solid-tag-runtime/solid` is additive and does not change the low-level runtime contract:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const modules = await loadSolidModules(options?);
|
|
170
|
+
const runtime = await createSolidRuntime(options?);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The integration resolves the canonical family:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
solid-js
|
|
177
|
+
@solidjs/web
|
|
178
|
+
@solidjs/html
|
|
179
|
+
@solidjs/signals
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`loadSolidModules()` returns ordinary namespaces compatible with the existing `modules` option. `createSolidRuntime()` composes that loader with the normal runtime and installs one private `SolidRuntimeIntegration` capability used by higher-level DOM features. Caller-provided modules win over automatic defaults.
|
|
183
|
+
|
|
184
|
+
Important boundaries:
|
|
185
|
+
|
|
186
|
+
1. `createRuntime()` remains synchronous and never performs provider/import-map work.
|
|
187
|
+
2. Provider-specific logic is isolated under `src/solid/providers/`.
|
|
188
|
+
3. Existing browser/import-map mappings are authoritative and are never rewritten.
|
|
189
|
+
4. A versioned Solid-family mapping becomes a provider/version identity anchor for generated siblings.
|
|
190
|
+
5. esm.sh generated siblings externalize authoritative mapped dependencies and pin coordinated missing dependencies when no anchor exists.
|
|
191
|
+
6. jsDelivr mixed-provider cases that cannot safely preserve core Solid identity fail rather than silently loading another runtime.
|
|
192
|
+
7. CDN fallback uses a package-tested Solid family version when no versioned anchor exists; provider `latest` is not the hidden default.
|
|
193
|
+
8. The integration layer may inspect page import maps and effective resolution, but it never mutates import maps.
|
|
194
|
+
|
|
195
|
+
The integration registry itself is a private `WeakMap<runtime, integration>`; the core module graph does not store provider metadata or DOM delegation state.
|
|
196
|
+
|
|
156
197
|
## 6. Module kinds
|
|
157
198
|
|
|
158
199
|
The runtime currently has three module record kinds.
|
|
@@ -516,79 +557,198 @@ The adapter does not transform arbitrary document HTML into JSX and does not cur
|
|
|
516
557
|
|
|
517
558
|
This avoids introducing a second template language, implicit lexical scope rules, or ambiguous ownership of already-parsed DOM.
|
|
518
559
|
|
|
560
|
+
### Wrapperless Solid 2 delegated-event integration
|
|
561
|
+
|
|
562
|
+
A bare declarative render keeps the existing marker-range ownership model:
|
|
563
|
+
|
|
564
|
+
```text
|
|
565
|
+
<script render> A <script render> B
|
|
566
|
+
↓ ↓
|
|
567
|
+
createRoot A createRoot B
|
|
568
|
+
↓ ↓
|
|
569
|
+
insert(range A) insert(range B)
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Solid 2 delegated handlers may require a DOM render/delegation context for the containing `Document`. A runtime created through `createSolidRuntime()` therefore carries a private lazy capability:
|
|
573
|
+
|
|
574
|
+
```ts
|
|
575
|
+
ensureDelegation(document);
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
The first wrapperless range mount calls it immediately before its normal `createRoot() + insert()` path. The capability:
|
|
579
|
+
|
|
580
|
+
1. creates/reuses one lightweight `render(() => undefined, document)` host keyed by **Document × `@solidjs/web` namespace identity**;
|
|
581
|
+
2. ensures the delegated event set through that same renderer namespace;
|
|
582
|
+
3. does not render application components inside the host;
|
|
583
|
+
4. does not use `runWithOwner()` and does not parent wrapperless roots under the host owner;
|
|
584
|
+
5. stays alive independently of any one marker range.
|
|
585
|
+
|
|
586
|
+
Selector rendering (`render="#target"`) remains normal container rendering. `<solid-render>` remains a persistent light-DOM container and is unchanged by this integration. Low-level runtimes created by `createRuntime()` do not receive this capability automatically.
|
|
587
|
+
|
|
588
|
+
The delegated event helper prefers `@solidjs/web.DelegatedEvents` when available and otherwise uses the standard Solid/dom-expressions delegated UI-event family. Registration is idempotent per renderer/document pair.
|
|
589
|
+
|
|
519
590
|
## 9. Compiler adapter boundary
|
|
520
591
|
|
|
521
|
-
The runtime engine
|
|
592
|
+
The runtime engine remains independent of the `solid-tag` AST. `0.0.13` formalizes a linker-ready **CompiledArtifact** boundary so compiler work can be cached before runtime-specific linking.
|
|
522
593
|
|
|
523
|
-
|
|
594
|
+
Preferred compiler contract:
|
|
524
595
|
|
|
525
596
|
```ts
|
|
526
597
|
interface RuntimeCompiler {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
598
|
+
fingerprint?: string | ((context: CompileContext) => string | Promise<string>);
|
|
599
|
+
cacheContext?: (context: CompileContext) => unknown | Promise<unknown>;
|
|
600
|
+
|
|
601
|
+
compile?(
|
|
602
|
+
source: string,
|
|
603
|
+
context: CompileContext,
|
|
604
|
+
): CompiledArtifact | Promise<CompiledArtifact>;
|
|
605
|
+
|
|
606
|
+
// Transitional compatibility path:
|
|
607
|
+
analyze?(source, context): { imports: ImportReference[] };
|
|
608
|
+
transform?(source, context): { code: string; diagnostics?: unknown[] };
|
|
536
609
|
}
|
|
537
610
|
```
|
|
538
611
|
|
|
539
|
-
The default adapter
|
|
612
|
+
The default adapter in `src/compiler.js` uses `solid-tag` and provides a stable fingerprint. JSX transformation runs **before** linking and intentionally leaves module specifiers unresolved. The resulting artifact is analyzed after transformation so import-reference offsets point into compiled JavaScript, not the original JSX source.
|
|
540
613
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
614
|
+
Conceptual artifact:
|
|
615
|
+
|
|
616
|
+
```ts
|
|
617
|
+
interface CompiledArtifact {
|
|
618
|
+
schema: 1;
|
|
619
|
+
code: string;
|
|
620
|
+
imports: ImportReference[];
|
|
621
|
+
diagnostics: unknown[];
|
|
622
|
+
sourceMap?: string;
|
|
623
|
+
}
|
|
544
624
|
```
|
|
545
625
|
|
|
626
|
+
The older `analyze()` + `transform()` pair remains supported for custom compilers. For that compatibility path the runtime transforms first, then analyzes the transformed code to construct the same artifact shape.
|
|
627
|
+
|
|
628
|
+
A custom compiler may compile normally without a fingerprint, but persistent artifact reuse is disabled because the runtime must never guess compiler identity.
|
|
629
|
+
|
|
546
630
|
### Why this boundary exists
|
|
547
631
|
|
|
548
|
-
It
|
|
632
|
+
It separates:
|
|
549
633
|
|
|
550
|
-
|
|
634
|
+
```text
|
|
635
|
+
compiler
|
|
636
|
+
syntax transformation + module-reference analysis
|
|
551
637
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
- reverse/tagged transformations for tooling
|
|
638
|
+
linker
|
|
639
|
+
runtime resolution + dependency URL rewriting
|
|
640
|
+
```
|
|
556
641
|
|
|
557
|
-
|
|
642
|
+
That boundary supports persistent compile caching and also keeps future TSX compilers, compiler workers, build-time artifacts, and alternate parsers independent from graph/link execution.
|
|
558
643
|
|
|
559
|
-
## 10.
|
|
644
|
+
## 10. Compile, cache, and linking pipeline
|
|
560
645
|
|
|
561
|
-
|
|
646
|
+
The source-module pipeline is now explicitly:
|
|
562
647
|
|
|
563
648
|
```text
|
|
564
649
|
source
|
|
565
650
|
↓
|
|
566
|
-
|
|
651
|
+
compile source syntax
|
|
567
652
|
↓
|
|
568
|
-
|
|
653
|
+
CompiledArtifact
|
|
654
|
+
│ transformed code
|
|
655
|
+
│ unresolved import specifiers
|
|
656
|
+
│ import offsets into transformed code
|
|
657
|
+
│ diagnostics/source map
|
|
658
|
+
│
|
|
659
|
+
├──────── optional persistent cache boundary
|
|
660
|
+
│
|
|
569
661
|
↓
|
|
570
|
-
resolve
|
|
662
|
+
resolve imports against current runtime graph
|
|
571
663
|
↓
|
|
572
|
-
ensure
|
|
664
|
+
ensure current dependency module URLs
|
|
573
665
|
↓
|
|
574
|
-
rewrite import
|
|
666
|
+
rewrite artifact import ranges
|
|
575
667
|
↓
|
|
576
|
-
|
|
668
|
+
linked executable JavaScript
|
|
577
669
|
↓
|
|
578
|
-
|
|
670
|
+
module URL backend
|
|
579
671
|
↓
|
|
580
|
-
import
|
|
672
|
+
native import/evaluation
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
For `/features/Counter.jsx`, the persistent artifact may still contain:
|
|
676
|
+
|
|
677
|
+
```js
|
|
678
|
+
import { createSignal } from "solid-js";
|
|
679
|
+
import html from "@solidjs/html";
|
|
680
|
+
import { Button } from "../ui/Button.jsx";
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
Only the linker turns those specifiers into current host bridges, external URLs, or generated runtime module URLs.
|
|
684
|
+
|
|
685
|
+
### Persistent compile cache
|
|
686
|
+
|
|
687
|
+
`0.0.13` adds an opt-in persistent compile cache.
|
|
688
|
+
|
|
689
|
+
The stored artifact is **pre-link**. Never persist:
|
|
690
|
+
|
|
691
|
+
- dependency Blob/data URLs
|
|
692
|
+
- linked executable source
|
|
693
|
+
- module URL backend output
|
|
694
|
+
- native module namespaces/import promises
|
|
695
|
+
- host bridge identities
|
|
696
|
+
- custom resolver output
|
|
697
|
+
|
|
698
|
+
Logical compile identity is content-addressed from:
|
|
699
|
+
|
|
700
|
+
```text
|
|
701
|
+
artifact ABI
|
|
702
|
+
+ compiler fingerprint
|
|
703
|
+
+ source format
|
|
704
|
+
+ compile-affecting context hash
|
|
705
|
+
+ exact source SHA-256
|
|
581
706
|
```
|
|
582
707
|
|
|
583
|
-
|
|
708
|
+
Module ID is excluded by default. Dependency source/version, resolver state, host values, and module URL backend are also excluded because they belong to linking/evaluation rather than compilation.
|
|
709
|
+
|
|
710
|
+
This means identical source can reuse one artifact under multiple module IDs while relative imports are still linked independently per importer.
|
|
711
|
+
|
|
712
|
+
Built-in stores:
|
|
713
|
+
|
|
714
|
+
```text
|
|
715
|
+
createIndexedDBCompileCache() recommended persistent browser backend
|
|
716
|
+
createLocalStorageCompileCache() convenience/small-artifact backend
|
|
717
|
+
createMemoryCompileCache() tests/benchmarks/process-local reuse
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
Persistent caching is configured on `createRuntime({ compileCache })` and remains fully opt-in.
|
|
721
|
+
|
|
722
|
+
### Invalidation layers
|
|
723
|
+
|
|
724
|
+
The runtime now distinguishes:
|
|
725
|
+
|
|
726
|
+
```text
|
|
727
|
+
compile artifact
|
|
728
|
+
linked executable graph
|
|
729
|
+
native evaluated module identity
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
Normal `runtime.invalidate(id)` invalidates linked/evaluated state while preserving the reusable compiled artifact. `runtime.invalidate(id, { compile: true })` additionally forces only the requested module to compile fresh on its next link. Dependents relink but retain their own compiler artifacts.
|
|
733
|
+
|
|
734
|
+
`runtime.update(id, newSource)` naturally computes a different content key for the changed source. Old persistent artifacts are not eagerly deleted because they may still be useful to another runtime, tab, module ID, or undo/revert operation.
|
|
735
|
+
|
|
736
|
+
Public `runtime.compile()` retains its existing meaning: it returns linked/executable code and URL. Internal persistent artifacts are not silently substituted into the public result.
|
|
737
|
+
|
|
738
|
+
### Cache controls
|
|
584
739
|
|
|
585
740
|
```text
|
|
586
|
-
/
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
└── ../ui/Button.jsx → compiled virtual source URL
|
|
741
|
+
use read reusable artifact; compile/write on miss
|
|
742
|
+
refresh compile requested module fresh and replace artifact
|
|
743
|
+
bypass compile requested module fresh without persistent read/write
|
|
590
744
|
```
|
|
591
745
|
|
|
746
|
+
Explicit persistent management lives under `runtime.compileCache` and is separate from graph removal/invalidation.
|
|
747
|
+
|
|
748
|
+
### Failure model
|
|
749
|
+
|
|
750
|
+
Persistent caching is an optimization. Read/write/validation/pruning failures emit compile-cache lifecycle diagnostics and fall back to normal compilation whenever possible. Explicit management operations may surface the storage error because the caller explicitly requested that storage mutation.
|
|
751
|
+
|
|
592
752
|
## 11. Resolution rules
|
|
593
753
|
|
|
594
754
|
Resolution order is conceptually:
|
|
@@ -1254,3 +1414,47 @@ Rules now enforced:
|
|
|
1254
1414
|
7. The existing graph invariant remains unchanged: all declarations in a discovered script batch are defined before entry/render execution or recovery mounts are allowed to succeed.
|
|
1255
1415
|
|
|
1256
1416
|
This separates three orderings that must all be correct: DOM parsing order, custom-element upgrade/connection timing, and runtime module-definition timing.
|
|
1417
|
+
|
|
1418
|
+
### 0.0.13 — pre-link persistent compile cache and structured documentation
|
|
1419
|
+
|
|
1420
|
+
Decision: persistent caching stores only fully syntax-compiled, linker-ready artifacts. Runtime-specific dependency resolution, generated module URLs, host bridge identity, and native evaluation remain session-local.
|
|
1421
|
+
|
|
1422
|
+
Rules now enforced:
|
|
1423
|
+
|
|
1424
|
+
1. JSX transformation happens before runtime linking; import metadata is collected against transformed code so cached offsets remain valid.
|
|
1425
|
+
2. Persistent artifact identity includes artifact ABI, compiler fingerprint, source format, compile-affecting context, and exact source SHA-256.
|
|
1426
|
+
3. Module ID, dependency versions, resolver state, host values, and URL-backend choice are not part of the default compile key.
|
|
1427
|
+
4. Identical source may therefore share an artifact across module IDs while relative imports are linked separately for each importer.
|
|
1428
|
+
5. The default `solid-tag` compiler exposes a stable fingerprint. Custom compilers without a fingerprint continue to work but persistent caching is bypassed rather than guessed.
|
|
1429
|
+
6. `runtime.invalidate()` preserves compiler artifacts by default. `{ compile: true }` forces only the requested module to compile fresh; dependents relink without forced recompilation.
|
|
1430
|
+
7. `runtime.compile(id, { cache: "use" | "refresh" | "bypass" })` controls compiler-artifact lookup while preserving the existing public linked/executable compile result.
|
|
1431
|
+
8. `runtime.compileCache.invalidate()` and `.clear()` manage stored artifacts without deleting runtime module definitions.
|
|
1432
|
+
9. IndexedDB, localStorage, and memory providers share one async store contract. Provider failures never make normal compilation unavailable. Quota-style write failures trigger pruning plus one retry; a failed retry becomes an observational cache error while the freshly compiled in-memory artifact remains usable.
|
|
1433
|
+
10. Optional `maxAge`, `maxEntries`, and `maxBytes` bounds provide deliberately simple pruning; sophisticated global LRU and cross-tab locking remain deferred.
|
|
1434
|
+
11. Compile-cache lifecycle events remain observational and integrate with the existing typed subscription system.
|
|
1435
|
+
12. Package documentation is now organized under `docs/`, with feature guides and `docs/api/` references. The root README is an entry point; this architecture file remains the engineering handoff/decision log.
|
|
1436
|
+
13. HTML documentation explicitly requires `<solid-render></solid-render>` rather than XML-style `<solid-render />`; custom elements are not HTML void elements and self-closing syntax can accidentally capture following DOM as initial `props.children`.
|
|
1437
|
+
|
|
1438
|
+
### 0.0.14 — additive Solid runtime setup and lazy wrapperless delegation
|
|
1439
|
+
|
|
1440
|
+
Decision: add `solid-tag-runtime/solid` as an opt-in integration layer while keeping `createRuntime()` provider-agnostic and synchronous.
|
|
1441
|
+
|
|
1442
|
+
Public setup layers:
|
|
1443
|
+
|
|
1444
|
+
```text
|
|
1445
|
+
createRuntime()
|
|
1446
|
+
low-level; caller supplies already-resolved namespaces
|
|
1447
|
+
|
|
1448
|
+
loadSolidModules()
|
|
1449
|
+
resolves/imports the coordinated Solid family
|
|
1450
|
+
|
|
1451
|
+
createSolidRuntime()
|
|
1452
|
+
loadSolidModules + createRuntime + private lazy Solid integration
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
Resolution rules preserve explicit/effective page mappings before provider generation. Provider-specific URL logic lives outside the core runtime. The built-in fallback policy targets the tested Solid `2.0.0-rc.13` family rather than silently following CDN `latest`. esm.sh generation uses dependency externalization/pinning to preserve one Solid identity; its family model treats `@solidjs/signals` as the Solid 2 reactive core consumed by `solid-js`, with `@solidjs/web` and `@solidjs/html` layered above it. jsDelivr mixed-provider situations that cannot be guaranteed are rejected. Import maps are read-only inputs and are never mutated.
|
|
1456
|
+
|
|
1457
|
+
Decision: fix wrapperless Solid 2 delegated events with the smallest ownership-preserving change. `createSolidRuntime()` installs `ensureDelegation(document)` but does not execute it eagerly. The first wrapperless range mount creates/reuses one document-level delegation host per `Document × @solidjs/web namespace`, ensures delegated event types, then proceeds with the existing independent `createRoot() + insert()` mount.
|
|
1458
|
+
|
|
1459
|
+
The delegation host is infrastructure only. It is not a shared application owner, is not a parent of declarative roots, is not disposed with an individual range, and does not change selector rendering or `<solid-render>` container ownership. Low-level `createRuntime()` behavior is unchanged.
|
|
1460
|
+
|