solid-tag-runtime 0.0.13 → 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 +96 -2
- package/README.md +79 -19
- package/docs/README.md +5 -2
- package/docs/api/html.md +6 -0
- package/docs/api/solid.md +71 -0
- package/docs/getting-started.md +29 -22
- package/docs/html-runtime.md +8 -0
- package/docs/rendering.md +6 -0
- package/docs/solid-runtime-setup.md +181 -0
- package/docs/wrapperless-delegation.md +81 -0
- package/examples/solid-runtime.js +24 -0
- package/package.json +7 -1
- package/solid.d.ts +77 -0
- package/src/html/delegated-events.js +69 -0
- package/src/html/delegation-host.js +29 -0
- package/src/render.js +4 -0
- 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,181 @@
|
|
|
1
|
+
# Solid runtime setup and provider resolution
|
|
2
|
+
|
|
3
|
+
`solid-tag-runtime/solid` is an **optional additive integration layer**. The core `createRuntime()` API remains synchronous and provider-agnostic.
|
|
4
|
+
|
|
5
|
+
## Standard Solid family
|
|
6
|
+
|
|
7
|
+
The helper treats these packages as one coordinated runtime family:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
solid-js
|
|
11
|
+
@solidjs/web
|
|
12
|
+
@solidjs/html
|
|
13
|
+
@solidjs/signals
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The family is resolved coherently rather than as four unrelated imports.
|
|
17
|
+
|
|
18
|
+
## High-level setup
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { createSolidRuntime } from "solid-tag-runtime/solid";
|
|
22
|
+
|
|
23
|
+
const runtime = await createSolidRuntime({
|
|
24
|
+
modules: {
|
|
25
|
+
"@app/state": state,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`createSolidRuntime()`:
|
|
31
|
+
|
|
32
|
+
1. resolves/imports the standard Solid family;
|
|
33
|
+
2. merges those namespaces with `modules`;
|
|
34
|
+
3. gives caller-supplied modules precedence;
|
|
35
|
+
4. calls the normal runtime engine;
|
|
36
|
+
5. installs a lazy Solid integration capability used by wrapperless DOM rendering.
|
|
37
|
+
|
|
38
|
+
The returned value is the normal `SolidTagRuntime` API.
|
|
39
|
+
|
|
40
|
+
## Low-level setup
|
|
41
|
+
|
|
42
|
+
Nothing changes for applications that already own their exact Solid namespaces:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import * as Solid from "solid-js";
|
|
46
|
+
import * as SolidWeb from "@solidjs/web";
|
|
47
|
+
import html from "@solidjs/html";
|
|
48
|
+
import { createRuntime } from "solid-tag-runtime";
|
|
49
|
+
|
|
50
|
+
const runtime = createRuntime({
|
|
51
|
+
modules: {
|
|
52
|
+
"solid-js": Solid,
|
|
53
|
+
"@solidjs/web": SolidWeb,
|
|
54
|
+
"@solidjs/html": { default: html },
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This path performs no provider detection and installs no implicit DOM delegation behavior.
|
|
60
|
+
|
|
61
|
+
## Composable loader
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { loadSolidModules } from "solid-tag-runtime/solid";
|
|
65
|
+
|
|
66
|
+
const solidModules = await loadSolidModules();
|
|
67
|
+
|
|
68
|
+
const runtime = createRuntime({
|
|
69
|
+
modules: {
|
|
70
|
+
...solidModules,
|
|
71
|
+
"@app/state": state,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The returned object is directly compatible with the existing `modules` option.
|
|
77
|
+
|
|
78
|
+
## Resolution precedence
|
|
79
|
+
|
|
80
|
+
For the standard family the loader uses this precedence:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
1. already supplied namespace
|
|
84
|
+
2. explicit specifier override
|
|
85
|
+
3. existing browser import-map/effective host resolution
|
|
86
|
+
4. provider inferred from an existing Solid-family mapping
|
|
87
|
+
5. provider inferred weakly from other page mappings
|
|
88
|
+
6. configured fallback provider
|
|
89
|
+
7. actionable failure
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Existing mappings are authoritative. The helper never silently replaces them.
|
|
93
|
+
|
|
94
|
+
## Source modes
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
await loadSolidModules({ source: "auto" });
|
|
98
|
+
await loadSolidModules({ source: "host" });
|
|
99
|
+
await loadSolidModules({ source: "esm.sh" });
|
|
100
|
+
await loadSolidModules({ source: "jsdelivr" });
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### `auto`
|
|
104
|
+
|
|
105
|
+
Use host/browser resolution first. Fill missing packages only when a coherent provider path can be determined.
|
|
106
|
+
|
|
107
|
+
If only part of the Solid family resolves from an opaque host/bundler identity and the loader cannot identify the provider/version behind that runtime, `auto` fails instead of filling the rest from a CDN. This prevents a hidden second Solid runtime. Supply the missing namespaces explicitly or provide a coherent mapping/provider configuration.
|
|
108
|
+
|
|
109
|
+
### `host`
|
|
110
|
+
|
|
111
|
+
Use only already-resolvable host/bundler/browser modules. No CDN fallback is allowed.
|
|
112
|
+
|
|
113
|
+
### `esm.sh`
|
|
114
|
+
|
|
115
|
+
Use explicit/existing mappings where present and generate missing package URLs through the esm.sh adapter.
|
|
116
|
+
|
|
117
|
+
### `jsdelivr`
|
|
118
|
+
|
|
119
|
+
Use explicit/existing mappings where present and generate missing package URLs through the jsDelivr adapter. Cases that cannot safely preserve a pre-existing Solid identity fail rather than mixing providers silently.
|
|
120
|
+
|
|
121
|
+
## Tested fallback version
|
|
122
|
+
|
|
123
|
+
When provider fallback is needed and there is no versioned Solid anchor, this release uses a documented tested family version rather than CDN `latest`:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { TESTED_SOLID_VERSION } from "solid-tag-runtime/solid";
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
For `0.0.14`, the tested fallback line is Solid `2.0.0-rc.13`.
|
|
130
|
+
|
|
131
|
+
If an existing Solid mapping is explicitly versioned, that version becomes the family anchor for generated siblings. An explicitly unversioned existing mapping remains unversioned; the loader does not pretend it is pinned.
|
|
132
|
+
|
|
133
|
+
## esm.sh identity handling
|
|
134
|
+
|
|
135
|
+
When an authoritative page mapping exists, generated esm.sh siblings externalize that dependency so the browser resolves it through the existing mapping.
|
|
136
|
+
|
|
137
|
+
When there is no existing core anchor, generated sibling package URLs pin coordinated Solid dependencies through provider-specific `deps` parameters. Solid 2's family direction is modeled with `@solidjs/signals` as the reactive core consumed by `solid-js`, then `@solidjs/web`, then `@solidjs/html`; the generated URLs pin/externalize that family closure rather than treating `@solidjs/signals` as depending back on `solid-js`.
|
|
138
|
+
|
|
139
|
+
Provider query details remain isolated in the provider adapter; the core runtime does not know they exist.
|
|
140
|
+
|
|
141
|
+
## Import maps are read-only
|
|
142
|
+
|
|
143
|
+
The helpers may inspect import-map script contents and use the browser's effective resolver, but they never insert or rewrite import maps.
|
|
144
|
+
|
|
145
|
+
```text
|
|
146
|
+
loadSolidModules()
|
|
147
|
+
createSolidRuntime()
|
|
148
|
+
↓
|
|
149
|
+
read/detect only
|
|
150
|
+
↓
|
|
151
|
+
no global import-map mutation
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
If an application wants to install an import map, it should do so before module evaluation using application-owned tooling.
|
|
155
|
+
|
|
156
|
+
## User overrides
|
|
157
|
+
|
|
158
|
+
Caller modules win:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const runtime = await createSolidRuntime({
|
|
162
|
+
modules: {
|
|
163
|
+
"solid-js": CustomSolid,
|
|
164
|
+
"@app/state": state,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This is the escape hatch for custom builds, embedded runtimes, tests, and applications that already control dependency identity.
|
|
170
|
+
|
|
171
|
+
## Wrapperless delegation capability
|
|
172
|
+
|
|
173
|
+
`createSolidRuntime()` installs one private capability used by the HTML adapter:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
ensureDelegation(document)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Normal users do not call it. It is invoked lazily only when wrapperless `<script render>` mounting requires Solid's delegated-event infrastructure.
|
|
180
|
+
|
|
181
|
+
See [Wrapperless delegation](./wrapperless-delegation.md).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Wrapperless Solid 2 event delegation
|
|
2
|
+
|
|
3
|
+
Bare declarative rendering uses marker ranges instead of a container element:
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<script type="solid-jsx" render>
|
|
7
|
+
export default function App() {
|
|
8
|
+
return <button onClick={() => console.log("clicked")}>Click</button>;
|
|
9
|
+
}
|
|
10
|
+
</script>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Each declaration remains an **independent Solid reactive root**.
|
|
14
|
+
|
|
15
|
+
## Ownership model
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Document
|
|
19
|
+
│
|
|
20
|
+
│ lazily, once per Document × @solidjs/web namespace:
|
|
21
|
+
├── delegation host
|
|
22
|
+
│
|
|
23
|
+
├── wrapperless declaration A
|
|
24
|
+
│ └── createRoot A + insert(range A)
|
|
25
|
+
│
|
|
26
|
+
└── wrapperless declaration B
|
|
27
|
+
└── createRoot B + insert(range B)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The delegation host exists only for DOM/event infrastructure. It is not the reactive parent of the wrapperless roots.
|
|
31
|
+
|
|
32
|
+
Disposing A does not dispose B and does not tear down the document host.
|
|
33
|
+
|
|
34
|
+
## When it is initialized
|
|
35
|
+
|
|
36
|
+
The high-level factory:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
await createSolidRuntime(...)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
installs the capability but performs no DOM work immediately.
|
|
43
|
+
|
|
44
|
+
The first wrapperless range mount does:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
ensure document delegation host
|
|
48
|
+
ensure delegated event types
|
|
49
|
+
create independent root
|
|
50
|
+
insert component into marker range
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If the application never performs wrapperless rendering, no document delegation host is created by this feature.
|
|
54
|
+
|
|
55
|
+
## Selector rendering is unchanged
|
|
56
|
+
|
|
57
|
+
```html
|
|
58
|
+
<script type="solid-jsx" render="#app">
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
continues to use normal Solid container rendering.
|
|
62
|
+
|
|
63
|
+
## `<solid-render>` is unchanged
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<solid-render module="/Counter.jsx"></solid-render>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
continues to use its own persistent light-DOM container. This feature does not change its ownership model.
|
|
70
|
+
|
|
71
|
+
## Low-level `createRuntime()`
|
|
72
|
+
|
|
73
|
+
The core runtime deliberately does not install Solid-specific DOM behavior.
|
|
74
|
+
|
|
75
|
+
If wrapperless delegated-event setup should be automatic, use `createSolidRuntime()` from `solid-tag-runtime/solid`.
|
|
76
|
+
|
|
77
|
+
Advanced low-level users remain free to supply their own render adapter or host DOM setup.
|
|
78
|
+
|
|
79
|
+
## Delegated events
|
|
80
|
+
|
|
81
|
+
The integration prefers the renderer's exported delegated-event set when available and otherwise uses the standard Solid/dom-expressions delegated UI event family. Registration is idempotent per renderer/document pair.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createSolidRuntime } from "solid-tag-runtime/solid";
|
|
2
|
+
|
|
3
|
+
const runtime = await createSolidRuntime({
|
|
4
|
+
solid: {
|
|
5
|
+
source: "auto",
|
|
6
|
+
// Optional when the host/import map cannot resolve the complete family:
|
|
7
|
+
fallbackProvider: "esm.sh",
|
|
8
|
+
},
|
|
9
|
+
modules: {
|
|
10
|
+
"@app/config": {
|
|
11
|
+
greeting: "Hello",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
runtime.define("/Greeting.jsx", `
|
|
17
|
+
import { greeting } from "@app/config";
|
|
18
|
+
|
|
19
|
+
export default function Greeting() {
|
|
20
|
+
return <p>{greeting} from createSolidRuntime()</p>;
|
|
21
|
+
}
|
|
22
|
+
`);
|
|
23
|
+
|
|
24
|
+
export default runtime;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solid-tag-runtime",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "Runtime module system for JSX modules compiled with solid-tag and executed through @solidjs/html",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"types": "./html.d.ts",
|
|
24
24
|
"import": "./src/html.js",
|
|
25
25
|
"default": "./src/html.js"
|
|
26
|
+
},
|
|
27
|
+
"./solid": {
|
|
28
|
+
"types": "./solid.d.ts",
|
|
29
|
+
"import": "./src/solid/index.js",
|
|
30
|
+
"default": "./src/solid/index.js"
|
|
26
31
|
}
|
|
27
32
|
},
|
|
28
33
|
"main": "./src/index.js",
|
|
@@ -32,6 +37,7 @@
|
|
|
32
37
|
"src",
|
|
33
38
|
"index.d.ts",
|
|
34
39
|
"html.d.ts",
|
|
40
|
+
"solid.d.ts",
|
|
35
41
|
"README.md",
|
|
36
42
|
"ARCHITECTURE.md",
|
|
37
43
|
"docs",
|
package/solid.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ModuleNamespaceLike,
|
|
3
|
+
RuntimeOptions,
|
|
4
|
+
SolidTagRuntime,
|
|
5
|
+
} from "./index.js";
|
|
6
|
+
|
|
7
|
+
export type SolidRuntimePackageName =
|
|
8
|
+
| "solid-js"
|
|
9
|
+
| "@solidjs/web"
|
|
10
|
+
| "@solidjs/html"
|
|
11
|
+
| "@solidjs/signals";
|
|
12
|
+
|
|
13
|
+
export type SolidModuleProviderId = "esm.sh" | "jsdelivr";
|
|
14
|
+
export type SolidModuleSource = "auto" | "host" | SolidModuleProviderId;
|
|
15
|
+
|
|
16
|
+
export interface SolidRuntimeModules {
|
|
17
|
+
"solid-js": ModuleNamespaceLike | Function;
|
|
18
|
+
"@solidjs/web": ModuleNamespaceLike | Function;
|
|
19
|
+
"@solidjs/html": ModuleNamespaceLike | Function;
|
|
20
|
+
"@solidjs/signals": ModuleNamespaceLike | Function;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface LoadSolidModulesOptions {
|
|
24
|
+
/** Resolution policy. `auto` prefers the existing host/page resolver first. */
|
|
25
|
+
source?: SolidModuleSource;
|
|
26
|
+
/** CDN used only when `auto` cannot complete the family through the host. */
|
|
27
|
+
fallbackProvider?: SolidModuleProviderId;
|
|
28
|
+
/** Version used for provider-generated URLs when no versioned Solid anchor exists. */
|
|
29
|
+
version?: string;
|
|
30
|
+
/** Already-resolved namespaces. Provided entries are never re-imported. */
|
|
31
|
+
modules?: Partial<SolidRuntimeModules>;
|
|
32
|
+
/** Explicit URL/specifier overrides. Exact values are preserved. */
|
|
33
|
+
specifiers?: Partial<Record<SolidRuntimePackageName, string>>;
|
|
34
|
+
/** Optional Document used for read-only import-map/provider inspection. */
|
|
35
|
+
document?: Document;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface CreateSolidRuntimeOptions extends Omit<RuntimeOptions, "modules"> {
|
|
39
|
+
/** Application/host modules. User entries override automatically loaded defaults. */
|
|
40
|
+
modules?: RuntimeOptions["modules"] & Partial<SolidRuntimeModules>;
|
|
41
|
+
/** Options for resolving the standard Solid package family. */
|
|
42
|
+
solid?: LoadSolidModulesOptions;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SolidResolutionInspection {
|
|
46
|
+
pageMappings: Map<string, string>;
|
|
47
|
+
authoritativeMappings: Map<string, string>;
|
|
48
|
+
provider?: SolidModuleProviderId;
|
|
49
|
+
version?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export declare class SolidModuleResolutionError extends Error {
|
|
53
|
+
provider?: string;
|
|
54
|
+
version?: string;
|
|
55
|
+
missing?: string[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export declare const SOLID_RUNTIME_PACKAGES: readonly [
|
|
59
|
+
"solid-js",
|
|
60
|
+
"@solidjs/web",
|
|
61
|
+
"@solidjs/html",
|
|
62
|
+
"@solidjs/signals",
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
export declare const TESTED_SOLID_VERSION: string;
|
|
66
|
+
|
|
67
|
+
export declare function loadSolidModules(
|
|
68
|
+
options?: LoadSolidModulesOptions,
|
|
69
|
+
): Promise<SolidRuntimeModules>;
|
|
70
|
+
|
|
71
|
+
export declare function createSolidRuntime(
|
|
72
|
+
options?: CreateSolidRuntimeOptions,
|
|
73
|
+
): Promise<SolidTagRuntime>;
|
|
74
|
+
|
|
75
|
+
export declare function inspectSolidResolution(
|
|
76
|
+
options?: Pick<LoadSolidModulesOptions, "specifiers" | "document">,
|
|
77
|
+
): SolidResolutionInspection;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Solid/dom-expressions' standard delegated event family. Prefer a renderer's
|
|
2
|
+
// exported DelegatedEvents set when present; this is the compatibility fallback.
|
|
3
|
+
export const DEFAULT_SOLID_DELEGATED_EVENTS = Object.freeze([
|
|
4
|
+
"beforeinput",
|
|
5
|
+
"click",
|
|
6
|
+
"dblclick",
|
|
7
|
+
"contextmenu",
|
|
8
|
+
"focusin",
|
|
9
|
+
"focusout",
|
|
10
|
+
"input",
|
|
11
|
+
"keydown",
|
|
12
|
+
"keyup",
|
|
13
|
+
"mousedown",
|
|
14
|
+
"mousemove",
|
|
15
|
+
"mouseout",
|
|
16
|
+
"mouseover",
|
|
17
|
+
"mouseup",
|
|
18
|
+
"pointerdown",
|
|
19
|
+
"pointermove",
|
|
20
|
+
"pointerout",
|
|
21
|
+
"pointerover",
|
|
22
|
+
"pointerup",
|
|
23
|
+
"touchend",
|
|
24
|
+
"touchmove",
|
|
25
|
+
"touchstart",
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
const delegatedByRenderer = new WeakMap();
|
|
29
|
+
|
|
30
|
+
export function ensureDelegatedEvents(web, document, events) {
|
|
31
|
+
if (!web || (typeof web !== "object" && typeof web !== "function")) {
|
|
32
|
+
throw new TypeError("Solid delegation requires an @solidjs/web namespace.");
|
|
33
|
+
}
|
|
34
|
+
if (!document) throw new TypeError("Solid delegation requires a Document.");
|
|
35
|
+
if (typeof web.delegateEvents !== "function") return [];
|
|
36
|
+
|
|
37
|
+
let byDocument = delegatedByRenderer.get(web);
|
|
38
|
+
if (!byDocument) {
|
|
39
|
+
byDocument = new WeakMap();
|
|
40
|
+
delegatedByRenderer.set(web, byDocument);
|
|
41
|
+
}
|
|
42
|
+
let delegated = byDocument.get(document);
|
|
43
|
+
if (!delegated) {
|
|
44
|
+
delegated = new Set();
|
|
45
|
+
byDocument.set(document, delegated);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const requested = normalizeEvents(events ?? web.DelegatedEvents ?? DEFAULT_SOLID_DELEGATED_EVENTS);
|
|
49
|
+
const fresh = requested.filter(event => !delegated.has(event));
|
|
50
|
+
if (!fresh.length) return [];
|
|
51
|
+
|
|
52
|
+
web.delegateEvents(fresh, document);
|
|
53
|
+
for (const event of fresh) delegated.add(event);
|
|
54
|
+
return fresh;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function normalizeEvents(events) {
|
|
58
|
+
if (!events) return [];
|
|
59
|
+
const values = typeof events[Symbol.iterator] === "function" ? Array.from(events) : [];
|
|
60
|
+
const result = [];
|
|
61
|
+
const seen = new Set();
|
|
62
|
+
for (const value of values) {
|
|
63
|
+
const event = String(value ?? "").trim().toLowerCase();
|
|
64
|
+
if (!event || seen.has(event)) continue;
|
|
65
|
+
seen.add(event);
|
|
66
|
+
result.push(event);
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const hostsByDocument = new WeakMap();
|
|
2
|
+
|
|
3
|
+
export function ensureDocumentDelegationHost(web, document) {
|
|
4
|
+
if (!web || (typeof web !== "object" && typeof web !== "function")) {
|
|
5
|
+
throw new TypeError("Solid delegation requires an @solidjs/web namespace.");
|
|
6
|
+
}
|
|
7
|
+
if (!document) throw new TypeError("Solid delegation requires a Document.");
|
|
8
|
+
if (typeof web.render !== "function") {
|
|
9
|
+
throw new TypeError("@solidjs/web does not provide render() required for document delegation.");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let byRenderer = hostsByDocument.get(document);
|
|
13
|
+
if (!byRenderer) {
|
|
14
|
+
byRenderer = new WeakMap();
|
|
15
|
+
hostsByDocument.set(document, byRenderer);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let host = byRenderer.get(web);
|
|
19
|
+
if (host) return host;
|
|
20
|
+
|
|
21
|
+
const dispose = web.render(() => undefined, document);
|
|
22
|
+
host = {
|
|
23
|
+
document,
|
|
24
|
+
web,
|
|
25
|
+
dispose: typeof dispose === "function" ? dispose : undefined,
|
|
26
|
+
};
|
|
27
|
+
byRenderer.set(web, host);
|
|
28
|
+
return host;
|
|
29
|
+
}
|
package/src/render.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SolidTagRuntimeError } from "./errors.js";
|
|
2
|
+
import { getSolidRuntimeIntegration } from "./solid/integration.js";
|
|
2
3
|
|
|
3
4
|
export class HTMLRenderError extends SolidTagRuntimeError {
|
|
4
5
|
constructor(message, options = {}) {
|
|
@@ -68,6 +69,9 @@ export function createDefaultHTMLRenderAdapter(runtime) {
|
|
|
68
69
|
|
|
69
70
|
async mountRange({ parent, before, startMarker, endMarker, Component, props }) {
|
|
70
71
|
const { Solid, Web } = await getSolidModules();
|
|
72
|
+
const document = parent?.ownerDocument ?? globalThis.document;
|
|
73
|
+
const integration = getSolidRuntimeIntegration(runtime);
|
|
74
|
+
if (integration && document) integration.ensureDelegation(document);
|
|
71
75
|
if (typeof Solid.createRoot !== "function") {
|
|
72
76
|
throw new HTMLRenderError("solid-js does not provide createRoot().");
|
|
73
77
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function readImportMapImports(document = globalThis.document) {
|
|
2
|
+
const imports = new Map();
|
|
3
|
+
if (!document || typeof document.querySelectorAll !== "function") return imports;
|
|
4
|
+
|
|
5
|
+
let scripts = [];
|
|
6
|
+
try {
|
|
7
|
+
scripts = Array.from(document.querySelectorAll('script[type="importmap"]'));
|
|
8
|
+
} catch {
|
|
9
|
+
return imports;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (const script of scripts) {
|
|
13
|
+
const text = String(script?.textContent ?? "").trim();
|
|
14
|
+
if (!text) continue;
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(text);
|
|
17
|
+
const values = parsed?.imports;
|
|
18
|
+
if (!values || typeof values !== "object") continue;
|
|
19
|
+
for (const [specifier, target] of Object.entries(values)) {
|
|
20
|
+
if (typeof target === "string" && target) imports.set(specifier, target);
|
|
21
|
+
}
|
|
22
|
+
} catch {
|
|
23
|
+
// Import-map parsing is advisory here. The browser remains authoritative
|
|
24
|
+
// for actual resolution; malformed page maps must not crash inspection.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return imports;
|
|
29
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createRuntime as createRuntimeCore } from "../runtime.js";
|
|
2
|
+
import { installSolidRuntimeIntegration } from "./integration.js";
|
|
3
|
+
import {
|
|
4
|
+
SOLID_RUNTIME_PACKAGES,
|
|
5
|
+
TESTED_SOLID_VERSION,
|
|
6
|
+
pickSolidRuntimeModules,
|
|
7
|
+
} from "./packages.js";
|
|
8
|
+
import {
|
|
9
|
+
SolidModuleResolutionError,
|
|
10
|
+
createDefaultSolidEnvironment,
|
|
11
|
+
inspectSolidResolution,
|
|
12
|
+
loadSolidModulesWithEnvironment,
|
|
13
|
+
} from "./resolve.js";
|
|
14
|
+
|
|
15
|
+
export { SOLID_RUNTIME_PACKAGES, TESTED_SOLID_VERSION } from "./packages.js";
|
|
16
|
+
export { SolidModuleResolutionError, inspectSolidResolution } from "./resolve.js";
|
|
17
|
+
|
|
18
|
+
export async function loadSolidModules(options = {}) {
|
|
19
|
+
return loadSolidModulesWithEnvironment(options, createDefaultSolidEnvironment());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function createSolidRuntime(options = {}) {
|
|
23
|
+
return createSolidRuntimeWithEnvironment(options, createDefaultSolidEnvironment());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Internal/testable composition point. It intentionally is not part of the
|
|
27
|
+
// package's documented public type surface.
|
|
28
|
+
export async function createSolidRuntimeWithEnvironment(options = {}, environment) {
|
|
29
|
+
const {
|
|
30
|
+
solid = {},
|
|
31
|
+
modules = {},
|
|
32
|
+
compiler: suppliedCompiler,
|
|
33
|
+
compilerOptions,
|
|
34
|
+
...runtimeOptions
|
|
35
|
+
} = options;
|
|
36
|
+
|
|
37
|
+
const suppliedSolidModules = pickSolidRuntimeModules(modules);
|
|
38
|
+
const loadedSolidModules = await loadSolidModulesWithEnvironment({
|
|
39
|
+
...solid,
|
|
40
|
+
modules: {
|
|
41
|
+
...(solid.modules ?? {}),
|
|
42
|
+
...suppliedSolidModules,
|
|
43
|
+
},
|
|
44
|
+
}, environment);
|
|
45
|
+
|
|
46
|
+
const mergedModules = {
|
|
47
|
+
...loadedSolidModules,
|
|
48
|
+
...modules,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
let compiler = suppliedCompiler;
|
|
52
|
+
if (!compiler) {
|
|
53
|
+
// Keep the optional /solid layer cheap/testable when the caller already
|
|
54
|
+
// supplies a compiler, while preserving createRuntime()'s default behavior.
|
|
55
|
+
const { createSolidTagCompiler } = await import("../compiler.js");
|
|
56
|
+
compiler = createSolidTagCompiler(compilerOptions);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const runtime = createRuntimeCore({
|
|
60
|
+
...runtimeOptions,
|
|
61
|
+
compiler,
|
|
62
|
+
modules: mergedModules,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
installSolidRuntimeIntegration(runtime, pickSolidRuntimeModules(mergedModules));
|
|
66
|
+
return runtime;
|
|
67
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ensureDocumentDelegationHost } from "../html/delegation-host.js";
|
|
2
|
+
import { ensureDelegatedEvents } from "../html/delegated-events.js";
|
|
3
|
+
|
|
4
|
+
const integrations = new WeakMap();
|
|
5
|
+
|
|
6
|
+
export function installSolidRuntimeIntegration(runtime, modules, options = {}) {
|
|
7
|
+
if (!runtime || (typeof runtime !== "object" && typeof runtime !== "function")) {
|
|
8
|
+
throw new TypeError("installSolidRuntimeIntegration() requires a runtime object.");
|
|
9
|
+
}
|
|
10
|
+
const web = modules?.["@solidjs/web"];
|
|
11
|
+
if (!web) {
|
|
12
|
+
throw new TypeError("Solid runtime integration requires the @solidjs/web host module.");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const integration = {
|
|
16
|
+
modules,
|
|
17
|
+
web,
|
|
18
|
+
ensureDelegation(document) {
|
|
19
|
+
const host = ensureDocumentDelegationHost(web, document);
|
|
20
|
+
ensureDelegatedEvents(web, document, options.delegatedEvents);
|
|
21
|
+
return host;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
integrations.set(runtime, integration);
|
|
25
|
+
return integration;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getSolidRuntimeIntegration(runtime) {
|
|
29
|
+
return integrations.get(runtime);
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const SOLID_RUNTIME_PACKAGES = Object.freeze([
|
|
2
|
+
"solid-js",
|
|
3
|
+
"@solidjs/web",
|
|
4
|
+
"@solidjs/html",
|
|
5
|
+
"@solidjs/signals",
|
|
6
|
+
]);
|
|
7
|
+
|
|
8
|
+
// Keep CDN fallback deterministic. This runtime release is tested against the
|
|
9
|
+
// coordinated Solid 2 RC family below rather than provider "latest" tags.
|
|
10
|
+
export const TESTED_SOLID_VERSION = "2.0.0-rc.13";
|
|
11
|
+
|
|
12
|
+
export function isSolidRuntimePackage(value) {
|
|
13
|
+
return SOLID_RUNTIME_PACKAGES.includes(String(value));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function pickSolidRuntimeModules(modules = {}) {
|
|
17
|
+
const picked = {};
|
|
18
|
+
for (const packageName of SOLID_RUNTIME_PACKAGES) {
|
|
19
|
+
if (Object.prototype.hasOwnProperty.call(modules, packageName)) {
|
|
20
|
+
picked[packageName] = modules[packageName];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return picked;
|
|
24
|
+
}
|