@nisli/core 0.49.2 → 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.
@@ -123,18 +123,12 @@ export interface NisliHmrPluginOptions {
123
123
  filter?: RegExp;
124
124
  }
125
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).
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
- export declare function transformSource(code: string, coreSpecifier: string, runtimeSpecifier: string): string;
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
- * Rewrite a module's source so the `component` it imports from `@nisli/core` is
49
- * wrapped by the registry indirection. Pure function — exported for testing.
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
- export function transformSource(code, coreSpecifier, runtimeSpecifier) {
60
- const spec = escapeRegExp(coreSpecifier);
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":"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"}
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
- /** The author's setup function, kept opaque here (props proxy, host). */
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
- // ── Tag -> setup registry (Ruling 2) ────────────────────────────────
21
- const registry = new Map();
22
- /** Tags whose setup changed since the last drain — pending a re-mount. */
23
- const pendingRemounts = new Set();
24
- let remountScheduled = false;
25
- /**
26
- * When true, `__register` accumulates pending tags but does NOT auto-schedule a
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
  /**
@@ -215,13 +127,12 @@ export async function applyChange(payload, deps) {
215
127
  if (action === 'js') {
216
128
  // Own the drain: suppress the auto microtask so ALL changed tags register
217
129
  // during re-import before any re-mount runs.
218
- suppressAutoDrain = true;
219
- remountScheduled = false;
130
+ beginManualDrain();
220
131
  try {
221
132
  await deps.reimport();
222
133
  }
223
134
  finally {
224
- suppressAutoDrain = false;
135
+ endManualDrain();
225
136
  }
226
137
  if (pendingRemountCount() > 0) {
227
138
  drainRemounts();
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/esbuild-hmr/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA0CH,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;AAC7B;;;;GAIG;AACH,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B;;;;;;;;;;;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;AASD;;;;;;;;;;;;;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;AAED,uEAAuE;AAEvE,MAAM,MAAM,GAAG,aAAa,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAA6B;IAC1D,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC1C,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACvD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAChE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAiB;IAC1C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,KAAK,GAAG,QAAQ,CAAC,gBAAgB,CAAC,wBAAwB,CAAC,CAAC;IAClE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACrB,MAAM,IAAI,GAAG,IAAuB,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACjC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC3D,OAAO,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QACH,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,IAAI,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACrD,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,uEAAuE;AAEvE,IAAI,SAAS,GAA2B,IAAI,CAAC;AAE7C;;;GAGG;AACH,MAAM,UAAU,OAAO,CAAC,UAA0B,EAAE;IAClD,2EAA2E;IAC3E,6EAA6E;IAC7E,0EAA0E;IAC1E,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,2EAA2E;IAC3E,0BAA0B;IAC1B,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC;IAEhC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,UAAU,CAAC;IACxC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,CAAC;IACrD,MAAM,OAAO,GACX,OAAO,CAAC,kBAAkB;QAC1B,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,IAAK,UAAkE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAE9G,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,SAAS,GAAG,MAAM,CAAC;IACnB,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE;QACvC,IAAI,OAA6B,CAAC;QAClC,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAA0B,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAC9G,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,EAAE,CAAC;YACT,OAAO;QACT,CAAC;QACD,KAAK,WAAW,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,UAAU;IACxB,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC;IACrB,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAA6B,EAC7B,IAA2D;IAE3D,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,0EAA0E;QAC1E,6CAA6C;QAC7C,iBAAiB,GAAG,IAAI,CAAC;QACzB,gBAAgB,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACxB,CAAC;gBAAS,CAAC;YACT,iBAAiB,GAAG,KAAK,CAAC;QAC5B,CAAC;QACD,IAAI,mBAAmB,EAAE,GAAG,CAAC,EAAE,CAAC;YAC9B,aAAa,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,6EAA6E;QAC7E,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;IACd,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,eAAe;IAC5B,MAAM,OAAO,GAAG,QAAQ,CAAC,gBAAgB,CAAC,4BAA4B,CAAC,CAAC;IACxE,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACvB,MAAM,GAAG,GAAI,IAA0B,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC5D,IAAI,GAAG;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC"}
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.49.2",
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": {