@nisli/core 0.49.2 → 0.51.0
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/dist/hmr/registry.d.ts +58 -0
- package/dist/hmr/registry.js +125 -0
- package/dist/hmr/registry.js.map +1 -0
- package/dist/hmr/transform.d.ts +21 -0
- package/dist/hmr/transform.js +52 -0
- package/dist/hmr/transform.js.map +1 -0
- package/dist/vite-hmr/plugin.d.ts +27 -0
- package/dist/vite-hmr/plugin.js +62 -0
- package/dist/vite-hmr/plugin.js.map +1 -0
- package/dist/vite-hmr/runtime.d.ts +16 -0
- package/dist/vite-hmr/runtime.js +17 -0
- package/dist/vite-hmr/runtime.js.map +1 -0
- package/package.json +8 -21
- package/dist/esbuild-hmr/plugin.d.ts +0 -161
- package/dist/esbuild-hmr/plugin.js +0 -219
- package/dist/esbuild-hmr/plugin.js.map +0 -1
- package/dist/esbuild-hmr/runtime.d.ts +0 -122
- package/dist/esbuild-hmr/runtime.js +0 -252
- package/dist/esbuild-hmr/runtime.js.map +0 -1
- package/dist/esbuild-hmr/server.d.ts +0 -51
- package/dist/esbuild-hmr/server.js +0 -87
- package/dist/esbuild-hmr/server.js.map +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hmr/registry.ts — Transport-agnostic HMR core for Nisli (ADR 0021, ADR 0110).
|
|
3
|
+
*
|
|
4
|
+
* The tag→setup registry, the stable indirection thunk, and the in-place
|
|
5
|
+
* re-mount through the custom-element lifecycle. This is the part that is
|
|
6
|
+
* IDENTICAL regardless of how change notifications arrive — change
|
|
7
|
+
* (`../esbuild-hmr/*`) or Vite `import.meta.hot` (`../vite-hmr/*`) both drive
|
|
8
|
+
* the same registry. Keeping it here means one implementation, one set of
|
|
9
|
+
* correctness guarantees (ADR 0008.1 disposal), and no duplication.
|
|
10
|
+
*
|
|
11
|
+
* DEV-ONLY: reachable only via the dev subpaths, never from the `@nisli/core`
|
|
12
|
+
* `.` entry, so it contributes zero production bytes.
|
|
13
|
+
*/
|
|
14
|
+
/** The author's setup function, kept opaque here (props proxy, host). */
|
|
15
|
+
export type HmrSetup = (props: unknown, host: HTMLElement) => unknown;
|
|
16
|
+
/**
|
|
17
|
+
* Begin a caller-owned drain window: suppress auto-scheduling AND cancel any
|
|
18
|
+
* pending microtask drain, so the caller can re-evaluate a whole bundle and
|
|
19
|
+
* register ALL changed tags before a single explicit `drainRemounts()`. Used by
|
|
20
|
+
* the Vite path drains per-module.
|
|
21
|
+
*/
|
|
22
|
+
export declare function beginManualDrain(): void;
|
|
23
|
+
/** End a caller-owned drain window (re-enable auto-scheduling). */
|
|
24
|
+
export declare function endManualDrain(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Register (or update) the setup for a tag and return a STABLE indirection
|
|
27
|
+
* thunk that always reads the *current* setup from the registry.
|
|
28
|
+
*
|
|
29
|
+
* First registration for a tag (initial load) schedules no re-mount. A
|
|
30
|
+
* subsequent registration with a *different* setup reference (a rebuild
|
|
31
|
+
* re-evaluating the module) queues the tag for re-mount.
|
|
32
|
+
*
|
|
33
|
+
* The returned thunk is what `component()` hands to the real
|
|
34
|
+
* `FrameworkComponent`; because it reads `registry.get(tag)` lazily, the live
|
|
35
|
+
* element picks up new setup with no class swap or tag re-definition.
|
|
36
|
+
*/
|
|
37
|
+
export declare function __register(tag: string, setup: HmrSetup): HmrSetup;
|
|
38
|
+
/** Number of tags awaiting a re-mount (for orchestration/tests). */
|
|
39
|
+
export declare function pendingRemountCount(): number;
|
|
40
|
+
/** Drain and re-mount every pending tag. Returns the tags that were remounted. */
|
|
41
|
+
export declare function drainRemounts(): string[];
|
|
42
|
+
/**
|
|
43
|
+
* Re-mount every live element of `tag` in place, on the SAME instance:
|
|
44
|
+
*
|
|
45
|
+
* disconnectedCallback() — resets `_mounted`, disposes effects + template
|
|
46
|
+
* (the ADR 0008.1 disposal contract)
|
|
47
|
+
* replaceChildren() — clears old DOM, firing nested custom elements'
|
|
48
|
+
* disconnectedCallback so their disposers run too
|
|
49
|
+
* connectedCallback() — re-runs the NEW setup (via the registry thunk)
|
|
50
|
+
* inside the same `untrack(...)` mount path
|
|
51
|
+
*
|
|
52
|
+
* Props survive because `_propsProxy` is constructor-owned (component.ts), and
|
|
53
|
+
* the element node identity is preserved — siblings, scroll, route, and global
|
|
54
|
+
* stores are untouched.
|
|
55
|
+
*/
|
|
56
|
+
export declare function remount(tag: string): void;
|
|
57
|
+
/** Test-only: clear the registry and pending state between cases. */
|
|
58
|
+
export declare function __resetRegistry(): void;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hmr/registry.ts — Transport-agnostic HMR core for Nisli (ADR 0021, ADR 0110).
|
|
3
|
+
*
|
|
4
|
+
* The tag→setup registry, the stable indirection thunk, and the in-place
|
|
5
|
+
* re-mount through the custom-element lifecycle. This is the part that is
|
|
6
|
+
* IDENTICAL regardless of how change notifications arrive — change
|
|
7
|
+
* (`../esbuild-hmr/*`) or Vite `import.meta.hot` (`../vite-hmr/*`) both drive
|
|
8
|
+
* the same registry. Keeping it here means one implementation, one set of
|
|
9
|
+
* correctness guarantees (ADR 0008.1 disposal), and no duplication.
|
|
10
|
+
*
|
|
11
|
+
* DEV-ONLY: reachable only via the dev subpaths, never from the `@nisli/core`
|
|
12
|
+
* `.` entry, so it contributes zero production bytes.
|
|
13
|
+
*/
|
|
14
|
+
// ── Tag → setup registry (Ruling 2) ─────────────────────────────────
|
|
15
|
+
const registry = new Map();
|
|
16
|
+
/** Tags whose setup changed since the last drain — pending a re-mount. */
|
|
17
|
+
const pendingRemounts = new Set();
|
|
18
|
+
let remountScheduled = false;
|
|
19
|
+
/**
|
|
20
|
+
* When true, `__register` accumulates pending tags but does NOT auto-schedule a
|
|
21
|
+
* microtask drain — the caller owns the drain so it can wait for a full module
|
|
22
|
+
* re-eval to register ALL changed tags first.
|
|
23
|
+
* The Vite path leaves this false and drains explicitly from its accept hook.
|
|
24
|
+
*/
|
|
25
|
+
let suppressAutoDrain = false;
|
|
26
|
+
/**
|
|
27
|
+
* Begin a caller-owned drain window: suppress auto-scheduling AND cancel any
|
|
28
|
+
* pending microtask drain, so the caller can re-evaluate a whole bundle and
|
|
29
|
+
* register ALL changed tags before a single explicit `drainRemounts()`. Used by
|
|
30
|
+
* the Vite path drains per-module.
|
|
31
|
+
*/
|
|
32
|
+
export function beginManualDrain() {
|
|
33
|
+
suppressAutoDrain = true;
|
|
34
|
+
remountScheduled = false;
|
|
35
|
+
}
|
|
36
|
+
/** End a caller-owned drain window (re-enable auto-scheduling). */
|
|
37
|
+
export function endManualDrain() {
|
|
38
|
+
suppressAutoDrain = false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Register (or update) the setup for a tag and return a STABLE indirection
|
|
42
|
+
* thunk that always reads the *current* setup from the registry.
|
|
43
|
+
*
|
|
44
|
+
* First registration for a tag (initial load) schedules no re-mount. A
|
|
45
|
+
* subsequent registration with a *different* setup reference (a rebuild
|
|
46
|
+
* re-evaluating the module) queues the tag for re-mount.
|
|
47
|
+
*
|
|
48
|
+
* The returned thunk is what `component()` hands to the real
|
|
49
|
+
* `FrameworkComponent`; because it reads `registry.get(tag)` lazily, the live
|
|
50
|
+
* element picks up new setup with no class swap or tag re-definition.
|
|
51
|
+
*/
|
|
52
|
+
export function __register(tag, setup) {
|
|
53
|
+
const prev = registry.get(tag);
|
|
54
|
+
registry.set(tag, setup);
|
|
55
|
+
if (prev !== undefined && prev !== setup) {
|
|
56
|
+
pendingRemounts.add(tag);
|
|
57
|
+
if (!suppressAutoDrain)
|
|
58
|
+
scheduleRemount();
|
|
59
|
+
}
|
|
60
|
+
return (props, host) => {
|
|
61
|
+
const current = registry.get(tag);
|
|
62
|
+
if (!current)
|
|
63
|
+
throw new Error(`[nisli-hmr] no setup registered for <${tag}>`);
|
|
64
|
+
return current(props, host);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Number of tags awaiting a re-mount (for orchestration/tests). */
|
|
68
|
+
export function pendingRemountCount() {
|
|
69
|
+
return pendingRemounts.size;
|
|
70
|
+
}
|
|
71
|
+
/** Drain and re-mount every pending tag. Returns the tags that were remounted. */
|
|
72
|
+
export function drainRemounts() {
|
|
73
|
+
const tags = [...pendingRemounts];
|
|
74
|
+
pendingRemounts.clear();
|
|
75
|
+
remountScheduled = false;
|
|
76
|
+
for (const tag of tags)
|
|
77
|
+
remount(tag);
|
|
78
|
+
return tags;
|
|
79
|
+
}
|
|
80
|
+
function scheduleRemount() {
|
|
81
|
+
if (remountScheduled)
|
|
82
|
+
return;
|
|
83
|
+
remountScheduled = true;
|
|
84
|
+
// Defer so a full module re-eval can register *all* changed tags first.
|
|
85
|
+
queueMicrotask(() => {
|
|
86
|
+
if (remountScheduled)
|
|
87
|
+
drainRemounts();
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
// ── Re-mount through the existing lifecycle (Ruling 3) ──────────────
|
|
91
|
+
/**
|
|
92
|
+
* Re-mount every live element of `tag` in place, on the SAME instance:
|
|
93
|
+
*
|
|
94
|
+
* disconnectedCallback() — resets `_mounted`, disposes effects + template
|
|
95
|
+
* (the ADR 0008.1 disposal contract)
|
|
96
|
+
* replaceChildren() — clears old DOM, firing nested custom elements'
|
|
97
|
+
* disconnectedCallback so their disposers run too
|
|
98
|
+
* connectedCallback() — re-runs the NEW setup (via the registry thunk)
|
|
99
|
+
* inside the same `untrack(...)` mount path
|
|
100
|
+
*
|
|
101
|
+
* Props survive because `_propsProxy` is constructor-owned (component.ts), and
|
|
102
|
+
* the element node identity is preserved — siblings, scroll, route, and global
|
|
103
|
+
* stores are untouched.
|
|
104
|
+
*/
|
|
105
|
+
export function remount(tag) {
|
|
106
|
+
const elements = document.querySelectorAll(tag);
|
|
107
|
+
elements.forEach((node) => {
|
|
108
|
+
const el = node;
|
|
109
|
+
// Dispose first: must run BEFORE clearing DOM or effects/subscriptions
|
|
110
|
+
// leak across reloads (ADR 0008.1 hazard).
|
|
111
|
+
el.disconnectedCallback?.();
|
|
112
|
+
// Clear old DOM — removal fires nested children's disconnectedCallback.
|
|
113
|
+
el.replaceChildren();
|
|
114
|
+
// Re-run setup + re-mount on the same instance.
|
|
115
|
+
el.connectedCallback?.();
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/** Test-only: clear the registry and pending state between cases. */
|
|
119
|
+
export function __resetRegistry() {
|
|
120
|
+
registry.clear();
|
|
121
|
+
pendingRemounts.clear();
|
|
122
|
+
remountScheduled = false;
|
|
123
|
+
suppressAutoDrain = false;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/hmr/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH,uEAAuE;AAEvE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;AAE7C,0EAA0E;AAC1E,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;AAC1C,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAE7B;;;;;GAKG;AACH,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,iBAAiB,GAAG,IAAI,CAAC;IACzB,gBAAgB,GAAG,KAAK,CAAC;AAC3B,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,cAAc;IAC5B,iBAAiB,GAAG,KAAK,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,KAAe;IACrD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACzC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,iBAAiB;YAAE,eAAe,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,CAAC,KAAc,EAAE,IAAiB,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,GAAG,GAAG,CAAC,CAAC;QAC9E,OAAO,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,mBAAmB;IACjC,OAAO,eAAe,CAAC,IAAI,CAAC;AAC9B,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,aAAa;IAC3B,MAAM,IAAI,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC;IAClC,eAAe,CAAC,KAAK,EAAE,CAAC;IACxB,gBAAgB,GAAG,KAAK,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,gBAAgB;QAAE,OAAO;IAC7B,gBAAgB,GAAG,IAAI,CAAC;IACxB,wEAAwE;IACxE,cAAc,CAAC,GAAG,EAAE;QAClB,IAAI,gBAAgB;YAAE,aAAa,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,uEAAuE;AAEvE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChD,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,EAAE,GAAG,IAAyB,CAAC;QACrC,uEAAuE;QACvE,2CAA2C;QAC3C,EAAE,CAAC,oBAAoB,EAAE,EAAE,CAAC;QAC5B,wEAAwE;QACxE,EAAE,CAAC,eAAe,EAAE,CAAC;QACrB,gDAAgD;QAChD,EAAE,CAAC,iBAAiB,EAAE,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,eAAe;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjB,eAAe,CAAC,KAAK,EAAE,CAAC;IACxB,gBAAgB,GAAG,KAAK,CAAC;IACzB,iBAAiB,GAAG,KAAK,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hmr/transform.ts — Shared source rewrite for Nisli HMR (ADR 0021, ADR 0110).
|
|
3
|
+
*
|
|
4
|
+
* Wraps the `component` a module imports from `@nisli/core` with the registry
|
|
5
|
+
* indirection so a rebuilt module's `component()` calls re-register their setup
|
|
6
|
+
* and trigger an in-place re-mount. Transport-agnostic and pure — used by both
|
|
7
|
+
* the Vite `transform` hook.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Rewrite a module's source so the `component` it imports from `coreSpecifier`
|
|
11
|
+
* is wrapped by the registry indirection from `runtimeSpecifier`.
|
|
12
|
+
*
|
|
13
|
+
* Strategy: alias the real import, then shadow `component` with a wrapper that
|
|
14
|
+
* registers the setup and passes a STABLE thunk to the real `component`. Cost:
|
|
15
|
+
* one Map write + one thunk allocation per `component()` call.
|
|
16
|
+
*
|
|
17
|
+
* Returns the original source unchanged if it does not import `component` from
|
|
18
|
+
* the core specifier (nothing to wrap) — the caller uses identity to decide
|
|
19
|
+
* whether the module is HMR-relevant.
|
|
20
|
+
*/
|
|
21
|
+
export declare function transformSource(code: string, coreSpecifier: string, runtimeSpecifier: string): string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hmr/transform.ts — Shared source rewrite for Nisli HMR (ADR 0021, ADR 0110).
|
|
3
|
+
*
|
|
4
|
+
* Wraps the `component` a module imports from `@nisli/core` with the registry
|
|
5
|
+
* indirection so a rebuilt module's `component()` calls re-register their setup
|
|
6
|
+
* and trigger an in-place re-mount. Transport-agnostic and pure — used by both
|
|
7
|
+
* the Vite `transform` hook.
|
|
8
|
+
*/
|
|
9
|
+
function escapeRegExp(s) {
|
|
10
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Rewrite a module's source so the `component` it imports from `coreSpecifier`
|
|
14
|
+
* is wrapped by the registry indirection from `runtimeSpecifier`.
|
|
15
|
+
*
|
|
16
|
+
* Strategy: alias the real import, then shadow `component` with a wrapper that
|
|
17
|
+
* registers the setup and passes a STABLE thunk to the real `component`. Cost:
|
|
18
|
+
* one Map write + one thunk allocation per `component()` call.
|
|
19
|
+
*
|
|
20
|
+
* Returns the original source unchanged if it does not import `component` from
|
|
21
|
+
* the core specifier (nothing to wrap) — the caller uses identity to decide
|
|
22
|
+
* whether the module is HMR-relevant.
|
|
23
|
+
*/
|
|
24
|
+
export function transformSource(code, coreSpecifier, runtimeSpecifier) {
|
|
25
|
+
const spec = escapeRegExp(coreSpecifier);
|
|
26
|
+
// Match a named import of `component` (alone or among others) from core.
|
|
27
|
+
const importRe = new RegExp(`import\\s*\\{([^}]*)\\}\\s*from\\s*['"]${spec}['"]`, 'g');
|
|
28
|
+
let importsComponent = false;
|
|
29
|
+
const rewritten = code.replace(importRe, (_full, names) => {
|
|
30
|
+
const parts = names.split(',').map((s) => s.trim()).filter(Boolean);
|
|
31
|
+
const next = parts.map((p) => {
|
|
32
|
+
// Handle `component` and `component as X` — we only wrap the bare name.
|
|
33
|
+
if (p === 'component') {
|
|
34
|
+
importsComponent = true;
|
|
35
|
+
return 'component as __nisliRealComponent';
|
|
36
|
+
}
|
|
37
|
+
return p;
|
|
38
|
+
});
|
|
39
|
+
return `import { ${next.join(', ')} } from '${coreSpecifier}'`;
|
|
40
|
+
});
|
|
41
|
+
if (!importsComponent)
|
|
42
|
+
return code;
|
|
43
|
+
// Prepend the registry-import + wrapper. `__register` returns the STABLE
|
|
44
|
+
// thunk the real component captures; the wrapper preserves the factory's
|
|
45
|
+
// return value and signature.
|
|
46
|
+
const preamble = `import { __register as __nisliRegister } from '${runtimeSpecifier}';\n` +
|
|
47
|
+
`function component(tag, setup, opts) {\n` +
|
|
48
|
+
` return __nisliRealComponent(tag, __nisliRegister(tag, setup), opts);\n` +
|
|
49
|
+
`}\n`;
|
|
50
|
+
return preamble + rewritten;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../src/hmr/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,aAAqB,EAAE,gBAAwB;IAC3F,MAAM,IAAI,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IACzC,yEAAyE;IACzE,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,0CAA0C,IAAI,MAAM,EAAE,GAAG,CAAC,CAAC;IAEvF,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAa,EAAE,KAAa,EAAE,EAAE;QACxE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAC3B,wEAAwE;YACxE,IAAI,CAAC,KAAK,WAAW,EAAE,CAAC;gBACtB,gBAAgB,GAAG,IAAI,CAAC;gBACxB,OAAO,mCAAmC,CAAC;YAC7C,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;QACH,OAAO,YAAY,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,aAAa,GAAG,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gBAAgB;QAAE,OAAO,IAAI,CAAC;IAEnC,yEAAyE;IACzE,yEAAyE;IACzE,8BAA8B;IAC9B,MAAM,QAAQ,GACZ,kDAAkD,gBAAgB,MAAM;QACxE,0CAA0C;QAC1C,0EAA0E;QAC1E,KAAK,CAAC;IAER,OAAO,QAAQ,GAAG,SAAS,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal structural subset of Vite's `Plugin` we implement. Declared
|
|
3
|
+
* structurally (not imported from `vite`) so `@nisli/core` keeps its
|
|
4
|
+
* zero-dependency footprint — `vite` is the consumer's dependency, not ours.
|
|
5
|
+
*/
|
|
6
|
+
export interface NisliVitePlugin {
|
|
7
|
+
name: string;
|
|
8
|
+
enforce?: 'pre' | 'post';
|
|
9
|
+
apply?: 'serve' | 'build';
|
|
10
|
+
transform(code: string, id: string): {
|
|
11
|
+
code: string;
|
|
12
|
+
map: null;
|
|
13
|
+
} | undefined;
|
|
14
|
+
}
|
|
15
|
+
export interface NisliViteHmrOptions {
|
|
16
|
+
/** The specifier modules import `component` from. Default `@nisli/core`. */
|
|
17
|
+
coreSpecifier?: string;
|
|
18
|
+
/** The runtime subpath providing `__register`/`__drain`. Default `@nisli/core/vite-hmr/runtime`. */
|
|
19
|
+
runtimeSpecifier?: string;
|
|
20
|
+
/** Which module ids to transform. Default: TS/JS sources. */
|
|
21
|
+
filter?: RegExp;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create the dev-only Nisli Vite HMR plugin. Add it to `plugins` in
|
|
25
|
+
* `vite.config.ts`; `apply: 'serve'` keeps it off the production build path.
|
|
26
|
+
*/
|
|
27
|
+
export declare function nisliHmr(options?: NisliViteHmrOptions): NisliVitePlugin;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vite-hmr/plugin.ts — Dev-only Vite plugin for Nisli HMR (ADR 0110).
|
|
3
|
+
*
|
|
4
|
+
* Vite plugin that wraps component() calls (shared `transformSource`),
|
|
5
|
+
* but drives re-mount through Vite's native `import.meta.hot` instead of an SSE
|
|
6
|
+
* hub + whole-bundle re-import. For each source module that imports `component`
|
|
7
|
+
* from `@nisli/core`, it:
|
|
8
|
+
* 1. wraps `component(tag, setup)` → `component(tag, __register(tag, setup))`
|
|
9
|
+
* so a re-evaluated module swaps its setup in the shared registry, and
|
|
10
|
+
* 2. appends `import.meta.hot.accept(() => __drain())` so Vite replaces JUST
|
|
11
|
+
* this module (granular HMR) and the queued re-mounts are applied.
|
|
12
|
+
*
|
|
13
|
+
* Because Vite re-evaluates only the changed module against a STABLE framework
|
|
14
|
+
* module, there is exactly one `@nisli/core` instance — the dual-instance
|
|
15
|
+
* "split-brain" of whole-bundle re-import cannot occur.
|
|
16
|
+
*
|
|
17
|
+
* `apply: 'serve'` makes this dev-only: the production `vite build` never runs
|
|
18
|
+
* the transform, so no wrapper, no registry import, and no `import.meta.hot`
|
|
19
|
+
* reach the prod bundle (zero prod HMR bytes).
|
|
20
|
+
*/
|
|
21
|
+
import { transformSource } from '../hmr/transform.js';
|
|
22
|
+
const DEFAULT_FILTER = /\.[mc]?[jt]sx?$/;
|
|
23
|
+
/**
|
|
24
|
+
* Create the dev-only Nisli Vite HMR plugin. Add it to `plugins` in
|
|
25
|
+
* `vite.config.ts`; `apply: 'serve'` keeps it off the production build path.
|
|
26
|
+
*/
|
|
27
|
+
export function nisliHmr(options = {}) {
|
|
28
|
+
const coreSpecifier = options.coreSpecifier ?? '@nisli/core';
|
|
29
|
+
const runtimeSpecifier = options.runtimeSpecifier ?? '@nisli/core/vite-hmr/runtime';
|
|
30
|
+
const filter = options.filter ?? DEFAULT_FILTER;
|
|
31
|
+
return {
|
|
32
|
+
name: 'nisli-vite-hmr',
|
|
33
|
+
// Run on the raw TS source before Vite's own transforms rewrite imports.
|
|
34
|
+
enforce: 'pre',
|
|
35
|
+
// Dev server only — never transform the production build.
|
|
36
|
+
apply: 'serve',
|
|
37
|
+
transform(code, id) {
|
|
38
|
+
const clean = id.split('?')[0] ?? id;
|
|
39
|
+
if (clean.includes('node_modules'))
|
|
40
|
+
return undefined;
|
|
41
|
+
if (!filter.test(clean))
|
|
42
|
+
return undefined;
|
|
43
|
+
const wrapped = transformSource(code, coreSpecifier, runtimeSpecifier);
|
|
44
|
+
// Identity ⇒ the module does not import `component` — not HMR-relevant.
|
|
45
|
+
// Leaving it un-accepted lets Vite propagate to a full reload (correct for
|
|
46
|
+
// services/utils edits).
|
|
47
|
+
if (wrapped === code)
|
|
48
|
+
return undefined;
|
|
49
|
+
const out = `import { __drain as __nisliViteDrain } from ${JSON.stringify(runtimeSpecifier)};\n` +
|
|
50
|
+
wrapped +
|
|
51
|
+
`\nif (import.meta.hot) {\n` +
|
|
52
|
+
` import.meta.hot.accept(() => { __nisliViteDrain(); });\n` +
|
|
53
|
+
`}\n`;
|
|
54
|
+
// map: null — the injection is an additive prepend/append on a handful of
|
|
55
|
+
// component modules in DEV only; a precise map would require a sourcemap
|
|
56
|
+
// dependency (magic-string), which `@nisli/core` deliberately avoids to
|
|
57
|
+
// stay zero-dependency. Original statements keep their column offsets.
|
|
58
|
+
return { code: out, map: null };
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/vite-hmr/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAuBtD,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEzC;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,UAA+B,EAAE;IACxD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,aAAa,CAAC;IAC7D,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,8BAA8B,CAAC;IACpF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;IAEhD,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,yEAAyE;QACzE,OAAO,EAAE,KAAK;QACd,0DAA0D;QAC1D,KAAK,EAAE,OAAO;QACd,SAAS,CAAC,IAAY,EAAE,EAAU;YAChC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;gBAAE,OAAO,SAAS,CAAC;YACrD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAC;YAE1C,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;YACvE,wEAAwE;YACxE,2EAA2E;YAC3E,yBAAyB;YACzB,IAAI,OAAO,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC;YAEvC,MAAM,GAAG,GACP,+CAA+C,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK;gBACpF,OAAO;gBACP,4BAA4B;gBAC5B,4DAA4D;gBAC5D,KAAK,CAAC;YAER,0EAA0E;YAC1E,yEAAyE;YACzE,wEAAwE;YACxE,uEAAuE;YACvE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAClC,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vite-hmr/runtime.ts — Browser runtime for Nisli HMR under Vite (ADR 0110).
|
|
3
|
+
*
|
|
4
|
+
* DEV-ONLY. The Vite plugin (`./plugin.ts`) injects calls to these into each
|
|
5
|
+
* component module:
|
|
6
|
+
* - `__register(tag, setup)` wraps `component()` so a re-evaluated module swaps
|
|
7
|
+
* its setup in the shared registry and queues an in-place re-mount.
|
|
8
|
+
* - `__drain()` is called from the module's `import.meta.hot.accept` hook to
|
|
9
|
+
* apply the queued re-mounts.
|
|
10
|
+
*
|
|
11
|
+
* Vite re-evaluates ONLY the changed module against a
|
|
12
|
+
* STABLE framework module — so there is exactly one `@nisli/core` instance and
|
|
13
|
+
* no lifecycle/reactive split-brain. This module just re-exports the
|
|
14
|
+
* transport-agnostic registry core.
|
|
15
|
+
*/
|
|
16
|
+
export { __register, drainRemounts as __drain, pendingRemountCount, remount } from '../hmr/registry.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vite-hmr/runtime.ts — Browser runtime for Nisli HMR under Vite (ADR 0110).
|
|
3
|
+
*
|
|
4
|
+
* DEV-ONLY. The Vite plugin (`./plugin.ts`) injects calls to these into each
|
|
5
|
+
* component module:
|
|
6
|
+
* - `__register(tag, setup)` wraps `component()` so a re-evaluated module swaps
|
|
7
|
+
* its setup in the shared registry and queues an in-place re-mount.
|
|
8
|
+
* - `__drain()` is called from the module's `import.meta.hot.accept` hook to
|
|
9
|
+
* apply the queued re-mounts.
|
|
10
|
+
*
|
|
11
|
+
* Vite re-evaluates ONLY the changed module against a
|
|
12
|
+
* STABLE framework module — so there is exactly one `@nisli/core` instance and
|
|
13
|
+
* no lifecycle/reactive split-brain. This module just re-exports the
|
|
14
|
+
* transport-agnostic registry core.
|
|
15
|
+
*/
|
|
16
|
+
export { __register, drainRemounts as __drain, pendingRemountCount, remount } from '../hmr/registry.js';
|
|
17
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/vite-hmr/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,aAAa,IAAI,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nisli/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"description": "A reactive web component framework. Signals, templates, dependency injection — no build step, no virtual DOM, no dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,30 +22,17 @@
|
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
23
|
"default": "./dist/index.js"
|
|
24
24
|
},
|
|
25
|
-
"./
|
|
26
|
-
"types": "./dist/
|
|
27
|
-
"default": "./dist/
|
|
25
|
+
"./vite-hmr": {
|
|
26
|
+
"types": "./dist/vite-hmr/plugin.d.ts",
|
|
27
|
+
"default": "./dist/vite-hmr/plugin.js"
|
|
28
28
|
},
|
|
29
|
-
"./
|
|
30
|
-
"types": "./dist/
|
|
31
|
-
"default": "./dist/
|
|
32
|
-
},
|
|
33
|
-
"./esbuild-hmr/server": {
|
|
34
|
-
"types": "./dist/esbuild-hmr/server.d.ts",
|
|
35
|
-
"default": "./dist/esbuild-hmr/server.js"
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"peerDependencies": {
|
|
39
|
-
"esbuild": "*"
|
|
40
|
-
},
|
|
41
|
-
"peerDependenciesMeta": {
|
|
42
|
-
"esbuild": {
|
|
43
|
-
"optional": true
|
|
29
|
+
"./vite-hmr/runtime": {
|
|
30
|
+
"types": "./dist/vite-hmr/runtime.d.ts",
|
|
31
|
+
"default": "./dist/vite-hmr/runtime.js"
|
|
44
32
|
}
|
|
45
33
|
},
|
|
46
34
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^22.0.0"
|
|
48
|
-
"esbuild": "^0.28.1"
|
|
35
|
+
"@types/node": "^22.0.0"
|
|
49
36
|
},
|
|
50
37
|
"files": [
|
|
51
38
|
"dist",
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* esbuild-hmr/plugin.ts — Dev-only esbuild plugin for Nisli component HMR.
|
|
3
|
-
*
|
|
4
|
-
* DEV-ONLY, build-time (Node). Reachable only via `@nisli/core/esbuild-hmr`,
|
|
5
|
-
* never from the runtime `.` entry (ADR 0021, Ruling 1). It is added to the
|
|
6
|
-
* esbuild plugin list ONLY on the `--watch` path; `pnpm build` (no watch) never
|
|
7
|
-
* sees it, so prod is byte-identical by construction (Ruling 5).
|
|
8
|
-
*
|
|
9
|
-
* `esbuild` is an OPTIONAL peerDependency. To keep `@nisli/core` dependency-free
|
|
10
|
-
* we do NOT `import` esbuild here — we type the plugin against a minimal local
|
|
11
|
-
* structural surface. The host build script supplies the real esbuild.
|
|
12
|
-
*
|
|
13
|
-
* What it does:
|
|
14
|
-
* 1. onLoad (Ruling 2): for author modules that import `component` from
|
|
15
|
-
* `@nisli/core`, rewrite the import so `component(tag, setup, opts)` routes
|
|
16
|
-
* `setup` through the runtime tag-keyed registry's STABLE indirection thunk.
|
|
17
|
-
* The real `FrameworkComponent` thus captures a thunk that always reads the
|
|
18
|
-
* current setup — no class swap, no tag re-definition.
|
|
19
|
-
* 2. onEnd (Ruling 4 transport): diff the metafile outputs against the previous
|
|
20
|
-
* build and broadcast a `change` payload ({added, removed, updated}) over
|
|
21
|
-
* SSE so the browser client can escalate (css/js/reload).
|
|
22
|
-
* 3. Inject the browser dev client (`@nisli/core/esbuild-hmr/runtime` +
|
|
23
|
-
* `connect({ path })`) via esbuild's `inject` option pointed at a VIRTUAL
|
|
24
|
-
* shim module, so the runtime is RESOLVED + BUNDLED into the output (no
|
|
25
|
-
* author HTML/JS change needed). We deliberately do NOT use `banner`: a
|
|
26
|
-
* banner is raw passthrough text that esbuild neither resolves nor bundles,
|
|
27
|
-
* so a bare `import … from "@nisli/core/esbuild-hmr/runtime"` would leak
|
|
28
|
-
* verbatim into the output and the browser would throw
|
|
29
|
-
* `Failed to resolve module specifier` (no import map). `inject` runs the
|
|
30
|
-
* shim through onResolve/onLoad so the runtime is inlined at build time, and
|
|
31
|
-
* esbuild applies `inject` ONLY to JS modules — never to file/copy-loaded
|
|
32
|
-
* entries (e.g. the viewer's `logo.svg`). Verified empirically against
|
|
33
|
-
* esbuild 0.28.1.
|
|
34
|
-
*/
|
|
35
|
-
import type { ChangeBroadcaster } from './server.js';
|
|
36
|
-
/** A subset of esbuild's `OnLoadArgs` we rely on. */
|
|
37
|
-
interface OnLoadArgs {
|
|
38
|
-
path: string;
|
|
39
|
-
}
|
|
40
|
-
/** A subset of esbuild's `OnLoadResult`. */
|
|
41
|
-
interface OnLoadResult {
|
|
42
|
-
contents: string;
|
|
43
|
-
loader?: 'ts' | 'tsx' | 'js' | 'jsx';
|
|
44
|
-
/** Directory used to resolve imports from a virtual module (the client shim). */
|
|
45
|
-
resolveDir?: string;
|
|
46
|
-
}
|
|
47
|
-
/** A subset of esbuild's `OnResolveArgs`. */
|
|
48
|
-
interface OnResolveArgs {
|
|
49
|
-
path: string;
|
|
50
|
-
}
|
|
51
|
-
/** A subset of esbuild's `OnResolveResult`. */
|
|
52
|
-
interface OnResolveResult {
|
|
53
|
-
path: string;
|
|
54
|
-
namespace?: string;
|
|
55
|
-
}
|
|
56
|
-
/** A subset of esbuild's metafile. */
|
|
57
|
-
interface Metafile {
|
|
58
|
-
outputs: Record<string, {
|
|
59
|
-
bytes: number;
|
|
60
|
-
hash?: string;
|
|
61
|
-
}>;
|
|
62
|
-
}
|
|
63
|
-
/** A subset of esbuild's `BuildResult`. */
|
|
64
|
-
interface BuildResult {
|
|
65
|
-
metafile?: Metafile;
|
|
66
|
-
}
|
|
67
|
-
/** The hooks surface of esbuild's `PluginBuild` we use. */
|
|
68
|
-
interface PluginBuild {
|
|
69
|
-
initialOptions: {
|
|
70
|
-
banner?: {
|
|
71
|
-
js?: string;
|
|
72
|
-
} & Record<string, string | undefined>;
|
|
73
|
-
/** Files esbuild injects into every JS module (never file/copy entries). */
|
|
74
|
-
inject?: string[];
|
|
75
|
-
/** esbuild's working directory; anchors virtual-module resolution. */
|
|
76
|
-
absWorkingDir?: string;
|
|
77
|
-
[key: string]: unknown;
|
|
78
|
-
};
|
|
79
|
-
onResolve(options: {
|
|
80
|
-
filter: RegExp;
|
|
81
|
-
namespace?: string;
|
|
82
|
-
}, callback: (args: OnResolveArgs) => OnResolveResult | undefined): void;
|
|
83
|
-
onLoad(options: {
|
|
84
|
-
filter: RegExp;
|
|
85
|
-
namespace?: string;
|
|
86
|
-
}, callback: (args: OnLoadArgs) => OnLoadResult | undefined): void;
|
|
87
|
-
onEnd(callback: (result: BuildResult) => void): void;
|
|
88
|
-
}
|
|
89
|
-
/** esbuild's `Plugin` shape (structural). */
|
|
90
|
-
export interface EsbuildPlugin {
|
|
91
|
-
name: string;
|
|
92
|
-
setup(build: PluginBuild): void;
|
|
93
|
-
}
|
|
94
|
-
export interface NisliHmrPluginOptions {
|
|
95
|
-
/**
|
|
96
|
-
* Broadcaster used to push `change` events to connected clients. Supply the
|
|
97
|
-
* one returned by `createHmrServer()` (server.ts), or any object with a
|
|
98
|
-
* `broadcast(payload)` method (e.g. an esbuild `serve` adapter).
|
|
99
|
-
*/
|
|
100
|
-
broadcaster: ChangeBroadcaster;
|
|
101
|
-
/**
|
|
102
|
-
* The module specifier author code imports `component` from.
|
|
103
|
-
* Defaults to `@nisli/core`.
|
|
104
|
-
*/
|
|
105
|
-
coreSpecifier?: string;
|
|
106
|
-
/**
|
|
107
|
-
* The specifier of the browser dev runtime, inlined into the bundle via the
|
|
108
|
-
* injected client shim. Defaults to `@nisli/core/esbuild-hmr/runtime`.
|
|
109
|
-
*/
|
|
110
|
-
runtimeSpecifier?: string;
|
|
111
|
-
/**
|
|
112
|
-
* The SSE endpoint the browser dev client connects to. Baked into the injected
|
|
113
|
-
* shim as `connect({ path: clientUrl })`. Defaults to `/esbuild` (esbuild's
|
|
114
|
-
* client convention, same-origin).
|
|
115
|
-
*
|
|
116
|
-
* Set this to an ABSOLUTE URL when the SSE hub (server.ts) runs on a different
|
|
117
|
-
* origin than the page server — e.g. `http://localhost:3031/esbuild` when the
|
|
118
|
-
* hub listens on :3031 and the page is served by Hono on :3040. The hub already
|
|
119
|
-
* sends `Access-Control-Allow-Origin: '*'`, so cross-origin SSE works.
|
|
120
|
-
*/
|
|
121
|
-
clientUrl?: string;
|
|
122
|
-
/** Files to transform. Defaults to TS/JS sources (excludes node_modules). */
|
|
123
|
-
filter?: RegExp;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Rewrite a module's source so the `component` it imports from `@nisli/core` is
|
|
127
|
-
* wrapped by the registry indirection. Pure function — exported for testing.
|
|
128
|
-
*
|
|
129
|
-
* Strategy: alias the real import, then shadow `component` with a wrapper that
|
|
130
|
-
* registers the setup and passes a STABLE thunk to the real `component`. The
|
|
131
|
-
* wrapper is a no-op-shaped passthrough at runtime cost of one Map write +
|
|
132
|
-
* one thunk allocation per `component()` call.
|
|
133
|
-
*
|
|
134
|
-
* Returns the original source unchanged if it does not import `component` from
|
|
135
|
-
* the core specifier (nothing to wrap).
|
|
136
|
-
*/
|
|
137
|
-
export declare function transformSource(code: string, coreSpecifier: string, runtimeSpecifier: string): string;
|
|
138
|
-
/**
|
|
139
|
-
* Source of the virtual client shim that esbuild's `inject` pulls into every JS
|
|
140
|
-
* module. Because it is `inject`ed (not a `banner`), esbuild RESOLVES the
|
|
141
|
-
* `runtimeSpecifier` import and BUNDLES `connect` inline — no bare specifier
|
|
142
|
-
* survives in the output (the 0.49.0 bug). `clientUrl` is baked in so the
|
|
143
|
-
* client targets the right SSE origin. Pure function — exported for testing.
|
|
144
|
-
*/
|
|
145
|
-
export declare function clientShimSource(runtimeSpecifier: string, clientUrl: string): string;
|
|
146
|
-
/**
|
|
147
|
-
* Create the dev-only Nisli HMR esbuild plugin. Add it to `plugins` ONLY when
|
|
148
|
-
* building with `--watch`; never on the prod build path.
|
|
149
|
-
*/
|
|
150
|
-
export declare function nisliHmrPlugin(options: NisliHmrPluginOptions): EsbuildPlugin;
|
|
151
|
-
/**
|
|
152
|
-
* Diff two output-hash maps into an esbuild-shaped change payload.
|
|
153
|
-
* Returns `null` for the very first build (no previous baseline).
|
|
154
|
-
* Exported for testing.
|
|
155
|
-
*/
|
|
156
|
-
export declare function diffOutputs(prev: Map<string, string> | null, next: Map<string, string>): {
|
|
157
|
-
added: string[];
|
|
158
|
-
removed: string[];
|
|
159
|
-
updated: string[];
|
|
160
|
-
} | null;
|
|
161
|
-
export {};
|