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
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Getting started
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install solid-tag-runtime solid-tag
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The runtime intentionally does not bundle its own Solid runtime.
|
|
10
|
+
|
|
11
|
+
## High-level Solid setup
|
|
12
|
+
|
|
13
|
+
For the shortest setup path:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createSolidRuntime } from "solid-tag-runtime/solid";
|
|
17
|
+
|
|
18
|
+
const runtime = await createSolidRuntime({
|
|
19
|
+
modules: {
|
|
20
|
+
"@app/state": state,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This resolves/imports the standard Solid family and installs lazy wrapperless event-delegation support.
|
|
26
|
+
|
|
27
|
+
See [Solid runtime setup](./solid-runtime-setup.md) for import-map/provider/version behavior.
|
|
28
|
+
|
|
29
|
+
## Low-level setup
|
|
30
|
+
|
|
31
|
+
If the host already owns exact namespaces, keep using the synchronous core primitive:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import * as Solid from "solid-js";
|
|
35
|
+
import * as SolidWeb from "@solidjs/web";
|
|
36
|
+
import html from "@solidjs/html";
|
|
37
|
+
import { createRuntime } from "solid-tag-runtime";
|
|
38
|
+
|
|
39
|
+
const runtime = createRuntime({
|
|
40
|
+
modules: {
|
|
41
|
+
"solid-js": Solid,
|
|
42
|
+
"@solidjs/web": SolidWeb,
|
|
43
|
+
"@solidjs/html": { default: html },
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Define and import a module
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
runtime.define("/Counter.jsx", `
|
|
52
|
+
import { createSignal } from "solid-js";
|
|
53
|
+
|
|
54
|
+
export default function Counter() {
|
|
55
|
+
const [count, setCount] = createSignal(0);
|
|
56
|
+
return (
|
|
57
|
+
<button onClick={() => setCount(value => value + 1)}>
|
|
58
|
+
{count()}
|
|
59
|
+
</button>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
`);
|
|
63
|
+
|
|
64
|
+
const module = await runtime.import("/Counter.jsx");
|
|
65
|
+
module.default;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Relative imports between runtime modules work normally.
|
|
69
|
+
|
|
70
|
+
## Browser HTML adapter
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { createHTMLRuntime } from "solid-tag-runtime/html";
|
|
74
|
+
|
|
75
|
+
const htmlRuntime = createHTMLRuntime(runtime, {
|
|
76
|
+
scope: "main",
|
|
77
|
+
root: document,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await htmlRuntime.register();
|
|
81
|
+
await htmlRuntime.observe({ registerExisting: false });
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Declarative source:
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<script
|
|
88
|
+
type="solid-jsx"
|
|
89
|
+
data-solid-runtime="main"
|
|
90
|
+
module="/App.jsx"
|
|
91
|
+
>
|
|
92
|
+
export default function App() {
|
|
93
|
+
return <h1>Hello</h1>;
|
|
94
|
+
}
|
|
95
|
+
</script>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
See [HTML runtime](./html-runtime.md), [declarative rendering](./rendering.md), and [`<solid-render>`](./solid-render.md).
|
|
99
|
+
|
|
100
|
+
## Browser import maps
|
|
101
|
+
|
|
102
|
+
Map every used package subpath explicitly:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"imports": {
|
|
107
|
+
"solid-tag-runtime": "https://esm.sh/solid-tag-runtime@0.0.14",
|
|
108
|
+
"solid-tag-runtime/html": "https://esm.sh/solid-tag-runtime@0.0.14/html",
|
|
109
|
+
"solid-tag-runtime/solid": "https://esm.sh/solid-tag-runtime@0.0.14/solid"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# HTML runtime and ownership
|
|
2
|
+
|
|
3
|
+
`solid-tag-runtime/html` adapts the core module graph to browser DOM declarations. The core runtime itself does not scan or own DOM.
|
|
4
|
+
|
|
5
|
+
## Create a controller
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createHTMLRuntime } from "solid-tag-runtime/html";
|
|
9
|
+
|
|
10
|
+
const html = createHTMLRuntime(runtime, {
|
|
11
|
+
scope: "main",
|
|
12
|
+
root: document,
|
|
13
|
+
acceptUnscoped: false,
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Register existing declarations
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
await html.register();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Observe later declarations
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
await html.observe({ registerExisting: false });
|
|
27
|
+
|
|
28
|
+
// after external DOM mutations
|
|
29
|
+
await html.flush();
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Script declarations
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<script
|
|
36
|
+
type="solid-jsx"
|
|
37
|
+
data-solid-runtime="main"
|
|
38
|
+
module="/ui/Button.jsx"
|
|
39
|
+
>
|
|
40
|
+
export function Button(props) {
|
|
41
|
+
return <button>{props.children}</button>;
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Supported source types include `solid-jsx`, `solid-js`, and `solid-module` (plus `text/...` aliases).
|
|
47
|
+
|
|
48
|
+
## `src` vs `module`
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<script
|
|
52
|
+
type="solid-jsx"
|
|
53
|
+
src="./source/Button.jsx"
|
|
54
|
+
module="/ui/Button.jsx"
|
|
55
|
+
></script>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- `src` = where source is loaded from
|
|
59
|
+
- `module` = identity in the runtime graph
|
|
60
|
+
|
|
61
|
+
## Ownership
|
|
62
|
+
|
|
63
|
+
A physical runtime script element has at most one HTML controller owner.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
await html.registerElement(script);
|
|
67
|
+
await html.append(script);
|
|
68
|
+
await html.addModule({ id: "/dynamic.js", source, format: "js" });
|
|
69
|
+
|
|
70
|
+
html.owns(script);
|
|
71
|
+
html.getModuleId(script);
|
|
72
|
+
html.getElement("/dynamic.js");
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Ownership is claimed before asynchronous source loading or DOM insertion, preventing observer/manual-registration races.
|
|
76
|
+
|
|
77
|
+
## Update and remove owned declarations
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
script.textContent = updatedSource;
|
|
81
|
+
await html.updateElement(script);
|
|
82
|
+
|
|
83
|
+
await html.removeElement(script);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Ordinary DOM removal does not implicitly delete a runtime module. The explicit controller APIs keep DOM ownership and runtime graph lifecycle synchronized.
|
|
87
|
+
|
|
88
|
+
## Multiple runtimes
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const main = createHTMLRuntime(mainRuntime, {
|
|
92
|
+
scope: "main",
|
|
93
|
+
acceptUnscoped: false,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const preview = createHTMLRuntime(previewRuntime, {
|
|
97
|
+
scope: "preview",
|
|
98
|
+
acceptUnscoped: false,
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`data-solid-runtime` is declarative routing metadata. In-memory ownership is authoritative.
|
|
103
|
+
|
|
104
|
+
## Root lifecycle
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
await html.setRoot(nextRoot);
|
|
108
|
+
await html.moveTo(nextRoot);
|
|
109
|
+
html.setAppendTarget(document.head);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`root` controls discovery/observation; `appendTarget` controls where explicit additions are inserted. Reparenting the exact same root node does not require `setRoot()`.
|
|
113
|
+
|
|
114
|
+
## Solid-aware wrapperless rendering
|
|
115
|
+
|
|
116
|
+
A low-level `createRuntime()` controller behaves exactly as before and does not install Solid-specific document infrastructure.
|
|
117
|
+
|
|
118
|
+
When the runtime comes from `createSolidRuntime()` in `solid-tag-runtime/solid`, a bare `<script render>` can lazily request the document-level delegated-event setup required by Solid 2. Each marker-range declaration still owns an independent reactive root and disposer; the delegation host is infrastructure only and is not a shared reactive owner.
|
|
119
|
+
|
|
120
|
+
See [Solid runtime setup](./solid-runtime-setup.md) and [Wrapperless delegation](./wrapperless-delegation.md).
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Lifecycle events
|
|
2
|
+
|
|
3
|
+
Lifecycle subscriptions are observational. They cannot cancel compilation, change resolution, modify source, or stop rendering.
|
|
4
|
+
|
|
5
|
+
## Core runtime
|
|
6
|
+
|
|
7
|
+
Catch all events:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const leave = runtime.subscribe(event => {
|
|
11
|
+
console.log(event.type, event);
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
One event type:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const leaveErrors = runtime.subscribe("module-error", event => {
|
|
19
|
+
console.error(event.phase, event.error);
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Several event types:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const leaveEvaluation = runtime.subscribe(
|
|
27
|
+
["module-evaluating", "module-evaluated"],
|
|
28
|
+
event => console.log(event.type, event.id),
|
|
29
|
+
);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Each call returns its own disposer.
|
|
33
|
+
|
|
34
|
+
### Core event groups
|
|
35
|
+
|
|
36
|
+
Definition/lifecycle:
|
|
37
|
+
|
|
38
|
+
- `module-defined`
|
|
39
|
+
- `module-updated`
|
|
40
|
+
- `modules-defined`
|
|
41
|
+
- `module-invalidated`
|
|
42
|
+
- `module-removed`
|
|
43
|
+
- `runtime-cleared`
|
|
44
|
+
- `runtime-disposed`
|
|
45
|
+
|
|
46
|
+
Resolution/link/evaluation:
|
|
47
|
+
|
|
48
|
+
- `module-resolving`
|
|
49
|
+
- `module-resolved`
|
|
50
|
+
- `module-linking`
|
|
51
|
+
- `module-linked`
|
|
52
|
+
- `module-compiled`
|
|
53
|
+
- `module-evaluating`
|
|
54
|
+
- `module-evaluated`
|
|
55
|
+
- `module-error`
|
|
56
|
+
|
|
57
|
+
Compile-cache events:
|
|
58
|
+
|
|
59
|
+
- `compile-cache-hit`
|
|
60
|
+
- `compile-cache-miss`
|
|
61
|
+
- `compile-cache-write`
|
|
62
|
+
- `compile-cache-refresh`
|
|
63
|
+
- `compile-cache-bypass`
|
|
64
|
+
- `compile-cache-error`
|
|
65
|
+
- `compile-cache-evict`
|
|
66
|
+
|
|
67
|
+
## HTML runtime
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
html.subscribe("element-registered", event => {
|
|
71
|
+
console.log(event.moduleId);
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
HTML events cover ownership, observation, roots, entry execution, render mounting/disposal, warnings, and errors.
|
|
76
|
+
|
|
77
|
+
Listener exceptions are isolated from runtime/HTML operations and are reported to the console rather than aborting the underlying action.
|
package/docs/modules.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Runtime modules and resolution
|
|
2
|
+
|
|
3
|
+
The primary abstraction in `solid-tag-runtime` is a module. Components are ordinary module exports.
|
|
4
|
+
|
|
5
|
+
## Source modules
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
runtime.define("/math.js", `export const answer = 42;`, {
|
|
9
|
+
format: "js",
|
|
10
|
+
});
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
JSX is the default format:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
runtime.define("/Greeting.jsx", `
|
|
17
|
+
export default function Greeting() {
|
|
18
|
+
return <p>Hello</p>;
|
|
19
|
+
}
|
|
20
|
+
`);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Host modules
|
|
24
|
+
|
|
25
|
+
Expose existing JavaScript values by reference:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
runtime.defineModule("@app/state", {
|
|
29
|
+
count,
|
|
30
|
+
setCount,
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Dynamic modules import those references normally:
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { count, setCount } from "@app/state";
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Host values are not serialized.
|
|
41
|
+
|
|
42
|
+
## URL modules
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
runtime.defineUrl(
|
|
46
|
+
"some-library",
|
|
47
|
+
"https://example.test/library.js",
|
|
48
|
+
);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Resolution
|
|
52
|
+
|
|
53
|
+
Resolution is runtime-local. The default rules are:
|
|
54
|
+
|
|
55
|
+
1. custom `resolve()` callback
|
|
56
|
+
2. exact registered ID
|
|
57
|
+
3. absolute URL
|
|
58
|
+
4. absolute virtual path
|
|
59
|
+
5. relative virtual path
|
|
60
|
+
6. unresolved bare native import when `allowNativeImports:true`
|
|
61
|
+
7. otherwise `ModuleResolutionError`
|
|
62
|
+
|
|
63
|
+
Virtual paths do not silently become network requests. Missing `/ui/Button.jsx` or `./Button.jsx` is a runtime-resolution error.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
runtime.resolve("./Button.jsx", "/ui/App.jsx");
|
|
67
|
+
// /ui/Button.jsx
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Batch definition
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
runtime.defineMany([
|
|
74
|
+
{ id: "/dep.js", source: "export const value = 41;", format: "js" },
|
|
75
|
+
{ id: "/main.js", source: 'import { value } from "./dep.js"; export const answer = value + 1;', format: "js" },
|
|
76
|
+
]);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The complete batch is installed before buffered lifecycle events are published.
|
|
80
|
+
|
|
81
|
+
## Updates and removal
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
runtime.update("/Button.jsx", newSource);
|
|
85
|
+
runtime.remove("/Button.jsx");
|
|
86
|
+
runtime.clear();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Updates/removals invalidate linked/evaluated dependents. Compiler artifacts follow the separate cache rules documented in [Persistent compile cache](./compile-cache.md).
|
|
90
|
+
|
|
91
|
+
## Current cycle limitation
|
|
92
|
+
|
|
93
|
+
Circular graphs between runtime-defined source modules are rejected. The current native-module URL backend requires final dependency URLs before an importing URL can be created.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Declarative rendering
|
|
2
|
+
|
|
3
|
+
A runtime script can define a module and mount one component instance.
|
|
4
|
+
|
|
5
|
+
## Render into a selector
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<div id="app"></div>
|
|
9
|
+
|
|
10
|
+
<script type="solid-jsx" module="/App.jsx" render="#app">
|
|
11
|
+
export default function App() {
|
|
12
|
+
return <h1>Hello</h1>;
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Without `component`, rendering selects `module.default`.
|
|
18
|
+
|
|
19
|
+
Selector rendering continues to use normal Solid container rendering.
|
|
20
|
+
|
|
21
|
+
## Named export
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<script
|
|
25
|
+
type="solid-jsx"
|
|
26
|
+
module="/widgets.jsx"
|
|
27
|
+
render="#app"
|
|
28
|
+
component="Counter"
|
|
29
|
+
>
|
|
30
|
+
export function Counter() {
|
|
31
|
+
return <button>Counter</button>;
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## In-place rendering
|
|
37
|
+
|
|
38
|
+
Bare `render` means mount at the exact declaration position:
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<p>Before</p>
|
|
42
|
+
|
|
43
|
+
<script type="solid-jsx" module="/Message.jsx" render>
|
|
44
|
+
export default function Message() {
|
|
45
|
+
return <strong>Hello</strong>;
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<p>After</p>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The adapter replaces the declaration with an owned marker range. No wrapper is introduced.
|
|
53
|
+
|
|
54
|
+
Each in-place render owns its own `createRoot() + insert()` lifecycle. When the runtime comes from `createSolidRuntime()`, the first wrapperless mount lazily establishes the document-level Solid delegation infrastructure needed by delegated handlers such as `onClick`. That infrastructure is not the reactive owner of the mounted ranges.
|
|
55
|
+
|
|
56
|
+
See [Wrapperless Solid 2 delegation](./wrapperless-delegation.md).
|
|
57
|
+
|
|
58
|
+
## Registration ordering
|
|
59
|
+
|
|
60
|
+
All matching declarations in a discovered batch are defined before any `entry` or `render` declaration executes. An importer may therefore appear before its dependency in document order.
|
|
61
|
+
|
|
62
|
+
## `entry` vs `render`
|
|
63
|
+
|
|
64
|
+
- `entry` = evaluate a module for side effects
|
|
65
|
+
- `render` = evaluate a module because a component export must mount
|
|
66
|
+
|
|
67
|
+
Combining `entry` and `render` on one declaration is rejected.
|
|
68
|
+
|
|
69
|
+
## Runtime scope diagnostics
|
|
70
|
+
|
|
71
|
+
A scoped render declaration is immediate work. If `data-solid-runtime="main"` cannot be handled by any registered controller covering that DOM root, the HTML adapter emits `html-warning` with code `unresolved-runtime-scope` and logs one warning.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# `<solid-render>`
|
|
2
|
+
|
|
3
|
+
`<solid-render>` references an already-defined runtime module and mounts a component instance into its own light DOM.
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<script type="solid-jsx" module="/Counter.jsx">
|
|
7
|
+
export default function Counter() {
|
|
8
|
+
return <button>Counter</button>;
|
|
9
|
+
}
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<solid-render module="/Counter.jsx"></solid-render>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Important HTML syntax rule
|
|
16
|
+
|
|
17
|
+
**Always use an explicit closing tag in HTML.**
|
|
18
|
+
|
|
19
|
+
Correct:
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<solid-render module="/Counter.jsx"></solid-render>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Do not write:
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<solid-render module="/Counter.jsx" />
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Custom elements are not HTML void elements. The HTML parser ignores the XML-style self-closing slash, so following siblings may become children of `<solid-render>`. Because initial child content is captured as `props.children`, this can make later page content appear to disappear.
|
|
32
|
+
|
|
33
|
+
## Named component
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<solid-render
|
|
37
|
+
module="/widgets.jsx"
|
|
38
|
+
component="Counter"
|
|
39
|
+
></solid-render>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Runtime selection
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<solid-render
|
|
46
|
+
data-solid-runtime="main"
|
|
47
|
+
module="/Counter.jsx"
|
|
48
|
+
></solid-render>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The selected controller must match scope rules and contain the element within its configured root.
|
|
52
|
+
|
|
53
|
+
## Declarative props
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<solid-render
|
|
57
|
+
module="/UserCard.jsx"
|
|
58
|
+
prop:name="Alice"
|
|
59
|
+
prop:user-id="42"
|
|
60
|
+
prop:compact
|
|
61
|
+
></solid-render>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Rules:
|
|
65
|
+
|
|
66
|
+
- `prop:user-id` becomes `userId`
|
|
67
|
+
- a present empty prop becomes `true`
|
|
68
|
+
- other attribute values remain strings
|
|
69
|
+
- renderer configuration (`module`, `component`, `data-solid-runtime`) is not forwarded
|
|
70
|
+
- `prop:module` is a normal component prop and does not collide with renderer `module`
|
|
71
|
+
|
|
72
|
+
## Programmatic props
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const element = document.querySelector("solid-render");
|
|
76
|
+
|
|
77
|
+
element.props = {
|
|
78
|
+
user,
|
|
79
|
+
onSave,
|
|
80
|
+
service,
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Programmatic values may contain arbitrary JavaScript references and override declarative `prop:*` values.
|
|
85
|
+
|
|
86
|
+
## Reactive updates
|
|
87
|
+
|
|
88
|
+
Changing `prop:*` or `.props` updates the existing component instance without remounting.
|
|
89
|
+
|
|
90
|
+
Changing `module`, `component`, or `data-solid-runtime` changes render identity and therefore disposes/remounts.
|
|
91
|
+
|
|
92
|
+
## Children
|
|
93
|
+
|
|
94
|
+
Initial child DOM becomes `props.children`:
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<solid-render module="/Card.jsx">
|
|
98
|
+
<p>Hello from HTML.</p>
|
|
99
|
+
</solid-render>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Initial children are captured once. Named slots and dynamic child recapture are not part of the current API.
|
|
103
|
+
|
|
104
|
+
## Multiple instances
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<solid-render module="/Counter.jsx"></solid-render>
|
|
108
|
+
<solid-render module="/Counter.jsx"></solid-render>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The evaluated module namespace is shared, while each element owns an independent Solid component/root lifecycle.
|