@nisli/core 0.49.1 → 0.50.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/esbuild-hmr/plugin.d.ts +5 -12
- package/dist/esbuild-hmr/plugin.js +5 -41
- package/dist/esbuild-hmr/plugin.js.map +1 -1
- package/dist/esbuild-hmr/runtime.d.ts +1 -37
- package/dist/esbuild-hmr/runtime.js +19 -98
- package/dist/esbuild-hmr/runtime.js.map +1 -1
- 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 +9 -1
|
@@ -123,18 +123,12 @@ export interface NisliHmrPluginOptions {
|
|
|
123
123
|
filter?: RegExp;
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
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).
|
|
126
|
+
* `transformSource` (wrap `component()` call sites) now lives in the shared
|
|
127
|
+
* `../hmr/transform.js` and is re-exported here so this module's surface — and
|
|
128
|
+
* the tests that import it from './plugin.js' — are unchanged (ADR 0110).
|
|
136
129
|
*/
|
|
137
|
-
|
|
130
|
+
import { transformSource } from '../hmr/transform.js';
|
|
131
|
+
export { transformSource };
|
|
138
132
|
/**
|
|
139
133
|
* Source of the virtual client shim that esbuild's `inject` pulls into every JS
|
|
140
134
|
* module. Because it is `inject`ed (not a `banner`), esbuild RESOLVES the
|
|
@@ -158,4 +152,3 @@ export declare function diffOutputs(prev: Map<string, string> | null, next: Map<
|
|
|
158
152
|
removed: string[];
|
|
159
153
|
updated: string[];
|
|
160
154
|
} | null;
|
|
161
|
-
export {};
|
|
@@ -45,45 +45,12 @@ const CLIENT_SHIM_PATH = 'nisli-hmr-client-shim';
|
|
|
45
45
|
const CLIENT_SHIM_NAMESPACE = 'nisli-hmr-shim';
|
|
46
46
|
const CLIENT_SHIM_FILTER = /^nisli-hmr-client-shim$/;
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* Strategy: alias the real import, then shadow `component` with a wrapper that
|
|
52
|
-
* registers the setup and passes a STABLE thunk to the real `component`. The
|
|
53
|
-
* wrapper is a no-op-shaped passthrough at runtime cost of one Map write +
|
|
54
|
-
* one thunk allocation per `component()` call.
|
|
55
|
-
*
|
|
56
|
-
* Returns the original source unchanged if it does not import `component` from
|
|
57
|
-
* the core specifier (nothing to wrap).
|
|
48
|
+
* `transformSource` (wrap `component()` call sites) now lives in the shared
|
|
49
|
+
* `../hmr/transform.js` and is re-exported here so this module's surface — and
|
|
50
|
+
* the tests that import it from './plugin.js' — are unchanged (ADR 0110).
|
|
58
51
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Match a named import of `component` (alone or among others) from core.
|
|
62
|
-
const importRe = new RegExp(`import\\s*\\{([^}]*)\\}\\s*from\\s*['"]${spec}['"]`, 'g');
|
|
63
|
-
let importsComponent = false;
|
|
64
|
-
const rewritten = code.replace(importRe, (_full, names) => {
|
|
65
|
-
const parts = names.split(',').map((s) => s.trim()).filter(Boolean);
|
|
66
|
-
const next = parts.map((p) => {
|
|
67
|
-
// Handle `component` and `component as X` — we only wrap the bare name.
|
|
68
|
-
if (p === 'component') {
|
|
69
|
-
importsComponent = true;
|
|
70
|
-
return 'component as __nisliRealComponent';
|
|
71
|
-
}
|
|
72
|
-
return p;
|
|
73
|
-
});
|
|
74
|
-
return `import { ${next.join(', ')} } from '${coreSpecifier}'`;
|
|
75
|
-
});
|
|
76
|
-
if (!importsComponent)
|
|
77
|
-
return code;
|
|
78
|
-
// Prepend the registry-import + wrapper. `__register` returns the STABLE
|
|
79
|
-
// thunk the real component captures; the wrapper preserves the factory's
|
|
80
|
-
// return value and signature.
|
|
81
|
-
const preamble = `import { __register as __nisliRegister } from '${runtimeSpecifier}';\n` +
|
|
82
|
-
`function component(tag, setup, opts) {\n` +
|
|
83
|
-
` return __nisliRealComponent(tag, __nisliRegister(tag, setup), opts);\n` +
|
|
84
|
-
`}\n`;
|
|
85
|
-
return preamble + rewritten;
|
|
86
|
-
}
|
|
52
|
+
import { transformSource } from '../hmr/transform.js';
|
|
53
|
+
export { transformSource };
|
|
87
54
|
/**
|
|
88
55
|
* Source of the virtual client shim that esbuild's `inject` pulls into every JS
|
|
89
56
|
* module. Because it is `inject`ed (not a `banner`), esbuild RESOLVES the
|
|
@@ -191,9 +158,6 @@ export function diffOutputs(prev, next) {
|
|
|
191
158
|
return { added, removed, updated };
|
|
192
159
|
}
|
|
193
160
|
// ── helpers ─────────────────────────────────────────────────────────
|
|
194
|
-
function escapeRegExp(s) {
|
|
195
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
196
|
-
}
|
|
197
161
|
function loaderFor(path) {
|
|
198
162
|
if (path.endsWith('.tsx'))
|
|
199
163
|
return 'tsx';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/esbuild-hmr/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA6FvC,uEAAuE;AAEvE,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEzC;;;;GAIG;AACH,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AACjD,MAAM,qBAAqB,GAAG,gBAAgB,CAAC;AAC/C,MAAM,kBAAkB,GAAG,yBAAyB,CAAC;AAErD
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/esbuild-hmr/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
* `setup` behind the registry, working *with* the `customElements.get` guard in
|
|
18
18
|
* component.ts rather than against it.
|
|
19
19
|
*/
|
|
20
|
-
|
|
21
|
-
export type HmrSetup = (props: unknown, host: HTMLElement) => unknown;
|
|
20
|
+
export { __register, pendingRemountCount, drainRemounts, remount, __resetRegistry, type HmrSetup, } from '../hmr/registry.js';
|
|
22
21
|
/** esbuild's `change` event payload shape (added/removed/updated paths). */
|
|
23
22
|
export interface EsbuildChangePayload {
|
|
24
23
|
added: string[];
|
|
@@ -52,40 +51,6 @@ export interface ConnectOptions {
|
|
|
52
51
|
/** Force a full reload. Defaults to `location.reload()`. */
|
|
53
52
|
reload?: () => void;
|
|
54
53
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Register (or update) the setup for a tag and return a STABLE indirection
|
|
57
|
-
* thunk that always reads the *current* setup from the registry.
|
|
58
|
-
*
|
|
59
|
-
* On the first registration for a tag (initial page load) no re-mount is
|
|
60
|
-
* scheduled. On a subsequent registration with a *different* setup reference
|
|
61
|
-
* (a watch rebuild re-evaluating the module) the tag is queued for re-mount.
|
|
62
|
-
*
|
|
63
|
-
* The returned thunk is what `component()` hands to the real
|
|
64
|
-
* `FrameworkComponent`; because it reads `registry.get(tag)` lazily, the live
|
|
65
|
-
* element picks up new setup without any class swap or tag re-definition.
|
|
66
|
-
*/
|
|
67
|
-
export declare function __register(tag: string, setup: HmrSetup): HmrSetup;
|
|
68
|
-
/** Number of tags awaiting a re-mount (for orchestration/tests). */
|
|
69
|
-
export declare function pendingRemountCount(): number;
|
|
70
|
-
/** Drain and re-mount every pending tag. Returns the tags that were remounted. */
|
|
71
|
-
export declare function drainRemounts(): string[];
|
|
72
|
-
/**
|
|
73
|
-
* Re-mount every live element of `tag` in place, on the SAME instance:
|
|
74
|
-
*
|
|
75
|
-
* disconnectedCallback() — resets `_mounted`, disposes effects + template
|
|
76
|
-
* (the ADR 0008.1 disposal contract)
|
|
77
|
-
* replaceChildren() — clears old DOM, firing nested custom elements'
|
|
78
|
-
* disconnectedCallback so their disposers run too
|
|
79
|
-
* connectedCallback() — re-runs the NEW setup (via the registry thunk)
|
|
80
|
-
* inside the same `untrack(...)` mount path
|
|
81
|
-
*
|
|
82
|
-
* Props survive because `_propsProxy` is constructor-owned (component.ts), and
|
|
83
|
-
* the element node identity is preserved — siblings, scroll, route, and global
|
|
84
|
-
* stores are untouched.
|
|
85
|
-
*/
|
|
86
|
-
export declare function remount(tag: string): void;
|
|
87
|
-
/** Test-only: clear the registry and pending state between cases. */
|
|
88
|
-
export declare function __resetRegistry(): void;
|
|
89
54
|
/**
|
|
90
55
|
* Decide the action for an esbuild output diff:
|
|
91
56
|
* - every changed output is CSS -> 'css' (hot-swap, preserves everything)
|
|
@@ -119,4 +84,3 @@ export declare function applyChange(payload: EsbuildChangePayload, deps: {
|
|
|
119
84
|
reimport: () => Promise<void>;
|
|
120
85
|
reload: () => void;
|
|
121
86
|
}): Promise<HmrAction>;
|
|
122
|
-
export {};
|
|
@@ -17,101 +17,13 @@
|
|
|
17
17
|
* `setup` behind the registry, working *with* the `customElements.get` guard in
|
|
18
18
|
* component.ts rather than against it.
|
|
19
19
|
*/
|
|
20
|
-
// ──
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* microtask drain — `applyChange` owns the drain so it can wait for a full
|
|
28
|
-
* module re-eval to register ALL changed tags first.
|
|
29
|
-
*/
|
|
30
|
-
let suppressAutoDrain = false;
|
|
31
|
-
/**
|
|
32
|
-
* Register (or update) the setup for a tag and return a STABLE indirection
|
|
33
|
-
* thunk that always reads the *current* setup from the registry.
|
|
34
|
-
*
|
|
35
|
-
* On the first registration for a tag (initial page load) no re-mount is
|
|
36
|
-
* scheduled. On a subsequent registration with a *different* setup reference
|
|
37
|
-
* (a watch rebuild re-evaluating the module) the tag is queued for re-mount.
|
|
38
|
-
*
|
|
39
|
-
* The returned thunk is what `component()` hands to the real
|
|
40
|
-
* `FrameworkComponent`; because it reads `registry.get(tag)` lazily, the live
|
|
41
|
-
* element picks up new setup without any class swap or tag re-definition.
|
|
42
|
-
*/
|
|
43
|
-
export function __register(tag, setup) {
|
|
44
|
-
const prev = registry.get(tag);
|
|
45
|
-
registry.set(tag, setup);
|
|
46
|
-
if (prev !== undefined && prev !== setup) {
|
|
47
|
-
pendingRemounts.add(tag);
|
|
48
|
-
if (!suppressAutoDrain)
|
|
49
|
-
scheduleRemount();
|
|
50
|
-
}
|
|
51
|
-
return (props, host) => {
|
|
52
|
-
const current = registry.get(tag);
|
|
53
|
-
if (!current)
|
|
54
|
-
throw new Error(`[nisli-hmr] no setup registered for <${tag}>`);
|
|
55
|
-
return current(props, host);
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
/** Number of tags awaiting a re-mount (for orchestration/tests). */
|
|
59
|
-
export function pendingRemountCount() {
|
|
60
|
-
return pendingRemounts.size;
|
|
61
|
-
}
|
|
62
|
-
/** Drain and re-mount every pending tag. Returns the tags that were remounted. */
|
|
63
|
-
export function drainRemounts() {
|
|
64
|
-
const tags = [...pendingRemounts];
|
|
65
|
-
pendingRemounts.clear();
|
|
66
|
-
remountScheduled = false;
|
|
67
|
-
for (const tag of tags)
|
|
68
|
-
remount(tag);
|
|
69
|
-
return tags;
|
|
70
|
-
}
|
|
71
|
-
function scheduleRemount() {
|
|
72
|
-
if (remountScheduled)
|
|
73
|
-
return;
|
|
74
|
-
remountScheduled = true;
|
|
75
|
-
// Defer so a full module re-eval can register *all* changed tags first.
|
|
76
|
-
queueMicrotask(() => {
|
|
77
|
-
if (remountScheduled)
|
|
78
|
-
drainRemounts();
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Re-mount every live element of `tag` in place, on the SAME instance:
|
|
83
|
-
*
|
|
84
|
-
* disconnectedCallback() — resets `_mounted`, disposes effects + template
|
|
85
|
-
* (the ADR 0008.1 disposal contract)
|
|
86
|
-
* replaceChildren() — clears old DOM, firing nested custom elements'
|
|
87
|
-
* disconnectedCallback so their disposers run too
|
|
88
|
-
* connectedCallback() — re-runs the NEW setup (via the registry thunk)
|
|
89
|
-
* inside the same `untrack(...)` mount path
|
|
90
|
-
*
|
|
91
|
-
* Props survive because `_propsProxy` is constructor-owned (component.ts), and
|
|
92
|
-
* the element node identity is preserved — siblings, scroll, route, and global
|
|
93
|
-
* stores are untouched.
|
|
94
|
-
*/
|
|
95
|
-
export function remount(tag) {
|
|
96
|
-
const elements = document.querySelectorAll(tag);
|
|
97
|
-
elements.forEach((node) => {
|
|
98
|
-
const el = node;
|
|
99
|
-
// Dispose first: must run BEFORE clearing DOM or effects/subscriptions
|
|
100
|
-
// leak across reloads (ADR 0008.1 hazard).
|
|
101
|
-
el.disconnectedCallback?.();
|
|
102
|
-
// Clear old DOM — removal fires nested children's disconnectedCallback.
|
|
103
|
-
el.replaceChildren();
|
|
104
|
-
// Re-run setup + re-mount on the same instance.
|
|
105
|
-
el.connectedCallback?.();
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
/** Test-only: clear the registry and pending state between cases. */
|
|
109
|
-
export function __resetRegistry() {
|
|
110
|
-
registry.clear();
|
|
111
|
-
pendingRemounts.clear();
|
|
112
|
-
remountScheduled = false;
|
|
113
|
-
suppressAutoDrain = false;
|
|
114
|
-
}
|
|
20
|
+
// ── Types ───────────────────────────────────────────────────────────
|
|
21
|
+
// Transport-agnostic registry/remount core lives in ../hmr/registry.js and is
|
|
22
|
+
// shared with the Vite adapter (ADR 0110). Re-exported here so this module's
|
|
23
|
+
// public surface — and the tests that import from './runtime.js' — are
|
|
24
|
+
// unchanged by the extraction.
|
|
25
|
+
export { __register, pendingRemountCount, drainRemounts, remount, __resetRegistry, } from '../hmr/registry.js';
|
|
26
|
+
import { beginManualDrain, drainRemounts, endManualDrain, pendingRemountCount } from '../hmr/registry.js';
|
|
115
27
|
// ── Change classification + escalation (Ruling 4) ───────────────────
|
|
116
28
|
const CSS_RE = /\.css($|\?)/;
|
|
117
29
|
/**
|
|
@@ -163,6 +75,16 @@ let connected = null;
|
|
|
163
75
|
* Safe to call once from the dev client; injected by the plugin in watch builds.
|
|
164
76
|
*/
|
|
165
77
|
export function connect(options = {}) {
|
|
78
|
+
// Idempotency guard (critical for the bundled re-import model). The plugin
|
|
79
|
+
// injects `connect()` at the entry's top level, and a JS update re-evaluates
|
|
80
|
+
// the entry (so `__register` re-runs for changed tags). That re-eval also
|
|
81
|
+
// re-runs this `connect()` call. Because `connected` lives in the persistent
|
|
82
|
+
// HMR runtime chunk (re-imported entries reuse it by name, un-busted), the
|
|
83
|
+
// guard survives across re-imports and keeps EXACTLY ONE EventSource + change
|
|
84
|
+
// listener alive — otherwise listeners stack and each edit fans out into N
|
|
85
|
+
// compounding re-imports.
|
|
86
|
+
if (connected)
|
|
87
|
+
return connected;
|
|
166
88
|
const path = options.path ?? '/esbuild';
|
|
167
89
|
const reload = options.reload ?? (() => location.reload());
|
|
168
90
|
const reimport = options.reimport ?? defaultReimport;
|
|
@@ -205,13 +127,12 @@ export async function applyChange(payload, deps) {
|
|
|
205
127
|
if (action === 'js') {
|
|
206
128
|
// Own the drain: suppress the auto microtask so ALL changed tags register
|
|
207
129
|
// during re-import before any re-mount runs.
|
|
208
|
-
|
|
209
|
-
remountScheduled = false;
|
|
130
|
+
beginManualDrain();
|
|
210
131
|
try {
|
|
211
132
|
await deps.reimport();
|
|
212
133
|
}
|
|
213
134
|
finally {
|
|
214
|
-
|
|
135
|
+
endManualDrain();
|
|
215
136
|
}
|
|
216
137
|
if (pendingRemountCount() > 0) {
|
|
217
138
|
drainRemounts();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/esbuild-hmr/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/esbuild-hmr/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 — esbuild SSE
|
|
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 esbuild whole-bundle path; the Vite path drains per-module instead.
|
|
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 — esbuild SSE
|
|
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 (the esbuild whole-bundle path).
|
|
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 esbuild whole-bundle path; the Vite path drains per-module instead.
|
|
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 esbuild `onLoad` transform and 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 esbuild `onLoad` transform and 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
|
+
* Mirrors the esbuild plugin's component-wrapping (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
|
+
* Unlike the esbuild path, 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
|
+
* Unlike the esbuild path, 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.50.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",
|
|
@@ -33,6 +33,14 @@
|
|
|
33
33
|
"./esbuild-hmr/server": {
|
|
34
34
|
"types": "./dist/esbuild-hmr/server.d.ts",
|
|
35
35
|
"default": "./dist/esbuild-hmr/server.js"
|
|
36
|
+
},
|
|
37
|
+
"./vite-hmr": {
|
|
38
|
+
"types": "./dist/vite-hmr/plugin.d.ts",
|
|
39
|
+
"default": "./dist/vite-hmr/plugin.js"
|
|
40
|
+
},
|
|
41
|
+
"./vite-hmr/runtime": {
|
|
42
|
+
"types": "./dist/vite-hmr/runtime.d.ts",
|
|
43
|
+
"default": "./dist/vite-hmr/runtime.js"
|
|
36
44
|
}
|
|
37
45
|
},
|
|
38
46
|
"peerDependencies": {
|