dalila 1.4.1 → 1.4.2
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/package.json +1 -1
- package/scripts/dev-server.cjs +154 -3
- package/dist/context/auto-scope.d.ts +0 -167
- package/dist/context/auto-scope.js +0 -381
- package/dist/context/context.d.ts +0 -111
- package/dist/context/context.js +0 -283
- package/dist/context/index.d.ts +0 -2
- package/dist/context/index.js +0 -2
- package/dist/context/raw.d.ts +0 -2
- package/dist/context/raw.js +0 -2
- package/dist/core/dev.d.ts +0 -7
- package/dist/core/dev.js +0 -14
- package/dist/core/for.d.ts +0 -42
- package/dist/core/for.js +0 -311
- package/dist/core/index.d.ts +0 -14
- package/dist/core/index.js +0 -14
- package/dist/core/key.d.ts +0 -33
- package/dist/core/key.js +0 -83
- package/dist/core/match.d.ts +0 -22
- package/dist/core/match.js +0 -175
- package/dist/core/mutation.d.ts +0 -55
- package/dist/core/mutation.js +0 -128
- package/dist/core/persist.d.ts +0 -63
- package/dist/core/persist.js +0 -371
- package/dist/core/query.d.ts +0 -72
- package/dist/core/query.js +0 -184
- package/dist/core/resource.d.ts +0 -299
- package/dist/core/resource.js +0 -924
- package/dist/core/scheduler.d.ts +0 -111
- package/dist/core/scheduler.js +0 -243
- package/dist/core/scope.d.ts +0 -74
- package/dist/core/scope.js +0 -171
- package/dist/core/signal.d.ts +0 -88
- package/dist/core/signal.js +0 -451
- package/dist/core/store.d.ts +0 -130
- package/dist/core/store.js +0 -234
- package/dist/core/virtual.d.ts +0 -26
- package/dist/core/virtual.js +0 -277
- package/dist/core/watch-testing.d.ts +0 -13
- package/dist/core/watch-testing.js +0 -16
- package/dist/core/watch.d.ts +0 -81
- package/dist/core/watch.js +0 -353
- package/dist/core/when.d.ts +0 -23
- package/dist/core/when.js +0 -124
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -4
- package/dist/internal/watch-testing.d.ts +0 -1
- package/dist/internal/watch-testing.js +0 -8
- package/dist/router/index.d.ts +0 -1
- package/dist/router/index.js +0 -1
- package/dist/router/route.d.ts +0 -23
- package/dist/router/route.js +0 -48
- package/dist/router/router.d.ts +0 -23
- package/dist/router/router.js +0 -169
- package/dist/runtime/bind.d.ts +0 -59
- package/dist/runtime/bind.js +0 -336
- package/dist/runtime/index.d.ts +0 -10
- package/dist/runtime/index.js +0 -9
- package/dist/simple.d.ts +0 -11
- package/dist/simple.js +0 -11
package/package.json
CHANGED
package/scripts/dev-server.cjs
CHANGED
|
@@ -250,17 +250,168 @@ function injectBindings(html, requestPath) {
|
|
|
250
250
|
}
|
|
251
251
|
</script>`;
|
|
252
252
|
|
|
253
|
-
// For user projects,
|
|
253
|
+
// For user projects, inject import map + HMR script
|
|
254
254
|
if (!isDalilaRepo) {
|
|
255
255
|
let output = addLoadingAttributes(html);
|
|
256
256
|
|
|
257
257
|
// FOUC prevention CSS
|
|
258
258
|
const foucPreventionCSS = ` <style>[d-loading]{visibility:hidden}</style>`;
|
|
259
259
|
|
|
260
|
+
// Smart HMR script for user projects
|
|
261
|
+
const hmrScript = `
|
|
262
|
+
<script type="module">
|
|
263
|
+
// HMR: Use native bind() HMR support
|
|
264
|
+
let disposeBinding = null;
|
|
265
|
+
|
|
266
|
+
const rebind = async () => {
|
|
267
|
+
const hmrContext = window.__dalila_hmr_context;
|
|
268
|
+
if (!hmrContext) {
|
|
269
|
+
console.warn('[HMR] Cannot rebind: bind() not called yet');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const { bind } = await import('${dalilaPath}/runtime/index.js');
|
|
275
|
+
const { root, ctx, options } = hmrContext;
|
|
276
|
+
|
|
277
|
+
// Dispose old bindings
|
|
278
|
+
if (disposeBinding) {
|
|
279
|
+
try { disposeBinding(); } catch (e) {}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Rebind with preserved context
|
|
283
|
+
disposeBinding = bind(root, ctx, options);
|
|
284
|
+
console.log('[HMR] Rebound successfully');
|
|
285
|
+
} catch (e) {
|
|
286
|
+
console.error('[HMR] Rebind failed:', e);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const patchNode = (current, next) => {
|
|
291
|
+
if (!current || !next) return;
|
|
292
|
+
|
|
293
|
+
if (current.nodeType !== next.nodeType) {
|
|
294
|
+
current.replaceWith(next.cloneNode(true));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (current.nodeType === Node.TEXT_NODE) {
|
|
299
|
+
if (current.data !== next.data) current.data = next.data;
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (current.nodeType === Node.ELEMENT_NODE) {
|
|
304
|
+
if (current.tagName !== next.tagName) {
|
|
305
|
+
current.replaceWith(next.cloneNode(true));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const currentAttrs = current.getAttributeNames();
|
|
310
|
+
const nextAttrs = next.getAttributeNames();
|
|
311
|
+
|
|
312
|
+
currentAttrs.forEach((name) => {
|
|
313
|
+
if (!nextAttrs.includes(name)) current.removeAttribute(name);
|
|
314
|
+
});
|
|
315
|
+
nextAttrs.forEach((name) => {
|
|
316
|
+
const value = next.getAttribute(name);
|
|
317
|
+
if (current.getAttribute(name) !== value) {
|
|
318
|
+
if (value === null) {
|
|
319
|
+
current.removeAttribute(name);
|
|
320
|
+
} else {
|
|
321
|
+
current.setAttribute(name, value);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const currentChildren = Array.from(current.childNodes);
|
|
327
|
+
const nextChildren = Array.from(next.childNodes);
|
|
328
|
+
const max = Math.max(currentChildren.length, nextChildren.length);
|
|
329
|
+
|
|
330
|
+
for (let i = 0; i < max; i += 1) {
|
|
331
|
+
const currentChild = currentChildren[i];
|
|
332
|
+
const nextChild = nextChildren[i];
|
|
333
|
+
|
|
334
|
+
if (!currentChild && nextChild) {
|
|
335
|
+
current.appendChild(nextChild.cloneNode(true));
|
|
336
|
+
} else if (currentChild && !nextChild) {
|
|
337
|
+
currentChild.remove();
|
|
338
|
+
} else if (currentChild && nextChild) {
|
|
339
|
+
patchNode(currentChild, nextChild);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
const refreshStyles = () => {
|
|
346
|
+
const links = document.querySelectorAll('link[rel="stylesheet"]');
|
|
347
|
+
links.forEach((link) => {
|
|
348
|
+
const url = new URL(link.href);
|
|
349
|
+
url.searchParams.set('v', String(Date.now()));
|
|
350
|
+
link.href = url.toString();
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const refreshMarkup = async () => {
|
|
355
|
+
const res = await fetch(window.location.pathname, { cache: 'no-store' });
|
|
356
|
+
const html = await res.text();
|
|
357
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
358
|
+
|
|
359
|
+
// Find root element (prefer #app, fallback to body)
|
|
360
|
+
const nextRoot = doc.querySelector('#app') || doc.body;
|
|
361
|
+
const currentRoot = document.querySelector('#app') || document.body;
|
|
362
|
+
|
|
363
|
+
if (nextRoot && currentRoot) {
|
|
364
|
+
patchNode(currentRoot, nextRoot);
|
|
365
|
+
console.log('[HMR] HTML patched');
|
|
366
|
+
|
|
367
|
+
// Rebind after patching
|
|
368
|
+
rebind();
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
if (window.__dalila_hmr) {
|
|
373
|
+
window.__dalila_hmr.close();
|
|
374
|
+
}
|
|
375
|
+
const hmr = new EventSource('/__hmr');
|
|
376
|
+
window.__dalila_hmr = hmr;
|
|
377
|
+
|
|
378
|
+
hmr.addEventListener('update', async (event) => {
|
|
379
|
+
let file = '';
|
|
380
|
+
try {
|
|
381
|
+
const payload = JSON.parse(event.data || '{}');
|
|
382
|
+
file = payload.file || '';
|
|
383
|
+
} catch {
|
|
384
|
+
file = '';
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
console.log('[HMR] File changed:', file);
|
|
388
|
+
|
|
389
|
+
if (file.endsWith('.css')) {
|
|
390
|
+
refreshStyles();
|
|
391
|
+
console.log('[HMR] CSS reloaded');
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (file.endsWith('.html')) {
|
|
396
|
+
await refreshMarkup();
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// For TS/JS files, full reload is needed to re-import modules
|
|
401
|
+
console.log('[HMR] Reloading page...');
|
|
402
|
+
location.reload();
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
hmr.onerror = () => {
|
|
406
|
+
console.warn('[HMR] Connection lost, will retry...');
|
|
407
|
+
};
|
|
408
|
+
</script>`;
|
|
409
|
+
|
|
410
|
+
// Inject HMR + import map in HEAD (HMR must load before user scripts)
|
|
260
411
|
if (output.includes('</head>')) {
|
|
261
|
-
output = output.replace('</head>', `${foucPreventionCSS}\n${importMap}\n</head>`);
|
|
412
|
+
output = output.replace('</head>', `${foucPreventionCSS}\n${importMap}\n${hmrScript}\n</head>`);
|
|
262
413
|
} else {
|
|
263
|
-
output = `${foucPreventionCSS}\n${importMap}\n${output}`;
|
|
414
|
+
output = `${foucPreventionCSS}\n${importMap}\n${hmrScript}\n${output}`;
|
|
264
415
|
}
|
|
265
416
|
|
|
266
417
|
return output;
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-scoping Context API.
|
|
3
|
-
*
|
|
4
|
-
* Goal:
|
|
5
|
-
* - Remove the need for explicit `withScope()` in common app code.
|
|
6
|
-
*
|
|
7
|
-
* Auto-scope rules:
|
|
8
|
-
* - `provide()` outside a scope creates a global root scope (warns once in dev).
|
|
9
|
-
* - `inject()` outside a scope never creates global state; it only reads an existing global root.
|
|
10
|
-
*
|
|
11
|
-
* Rationale:
|
|
12
|
-
* - Apps often want "global-ish" DI without Provider pyramids.
|
|
13
|
-
* - Still keep things lifecycle-safe: the global scope can be disposed on page unload.
|
|
14
|
-
*/
|
|
15
|
-
import { type Scope } from '../core/scope.js';
|
|
16
|
-
import { type Signal } from '../core/signal.js';
|
|
17
|
-
import { createContext, type ContextToken, type TryInjectResult } from './context.js';
|
|
18
|
-
export type AutoScopePolicy = "warn" | "throw" | "silent";
|
|
19
|
-
export declare function setAutoScopePolicy(policy: AutoScopePolicy): void;
|
|
20
|
-
/**
|
|
21
|
-
* Provide with auto-scope.
|
|
22
|
-
*
|
|
23
|
-
* Semantics:
|
|
24
|
-
* - Inside a scope: behaves like the raw `provide()`.
|
|
25
|
-
* - Outside a scope: creates/uses the global root scope (warns once in dev).
|
|
26
|
-
*/
|
|
27
|
-
export declare function provide<T>(token: ContextToken<T>, value: T): void;
|
|
28
|
-
/**
|
|
29
|
-
* Provide explicitly in the global root scope.
|
|
30
|
-
*
|
|
31
|
-
* Semantics:
|
|
32
|
-
* - Always uses the detached global scope (creates if needed).
|
|
33
|
-
* - Never warns.
|
|
34
|
-
*/
|
|
35
|
-
export declare function provideGlobal<T>(token: ContextToken<T>, value: T): void;
|
|
36
|
-
/**
|
|
37
|
-
* Inject with auto-scope.
|
|
38
|
-
*
|
|
39
|
-
* Semantics:
|
|
40
|
-
* - Inside a scope: behaves like raw `inject()`, but throws a more descriptive error.
|
|
41
|
-
* - Outside a scope:
|
|
42
|
-
* - If a global scope exists: reads from it (safe-by-default).
|
|
43
|
-
* - If no global scope exists: throws with guidance (does NOT create global state).
|
|
44
|
-
*/
|
|
45
|
-
export declare function inject<T>(token: ContextToken<T>): T;
|
|
46
|
-
/**
|
|
47
|
-
* Try to inject a context value with auto-scope.
|
|
48
|
-
*
|
|
49
|
-
* Semantics:
|
|
50
|
-
* - Returns { found: true, value } when the token is found.
|
|
51
|
-
* - Returns { found: false, value: undefined } when not found.
|
|
52
|
-
* - Works both inside and outside scopes (reads global if exists).
|
|
53
|
-
*/
|
|
54
|
-
export declare function tryInject<T>(token: ContextToken<T>): TryInjectResult<T>;
|
|
55
|
-
/**
|
|
56
|
-
* Inject explicitly from the global root scope.
|
|
57
|
-
*
|
|
58
|
-
* Semantics:
|
|
59
|
-
* - Reads only the global root scope.
|
|
60
|
-
* - Throws if no global scope exists yet.
|
|
61
|
-
*/
|
|
62
|
-
export declare function injectGlobal<T>(token: ContextToken<T>): T;
|
|
63
|
-
/**
|
|
64
|
-
* Convenience helper: create a scope, run `fn` inside it, and return `{ result, dispose }`.
|
|
65
|
-
*
|
|
66
|
-
* Semantics:
|
|
67
|
-
* - If `fn` throws, the scope is disposed and the error is rethrown.
|
|
68
|
-
* - Caller owns disposal.
|
|
69
|
-
*/
|
|
70
|
-
export declare function scope<T>(fn: () => T): {
|
|
71
|
-
result: T;
|
|
72
|
-
dispose: () => void;
|
|
73
|
-
};
|
|
74
|
-
/**
|
|
75
|
-
* Provider helper that bundles:
|
|
76
|
-
* - a dedicated provider scope
|
|
77
|
-
* - a value created by `setup()`
|
|
78
|
-
* - registration via `provide()`
|
|
79
|
-
*
|
|
80
|
-
* Useful for "feature modules" that want to expose a typed dependency with explicit lifetime.
|
|
81
|
-
*/
|
|
82
|
-
export declare function createProvider<T>(token: ContextToken<T>, setup: () => T): {
|
|
83
|
-
create: () => {
|
|
84
|
-
value: T;
|
|
85
|
-
dispose: () => void;
|
|
86
|
-
};
|
|
87
|
-
use: () => T;
|
|
88
|
-
};
|
|
89
|
-
/**
|
|
90
|
-
* Returns the global root scope (if it exists).
|
|
91
|
-
* Intended for debugging/advanced usage only.
|
|
92
|
-
*/
|
|
93
|
-
export declare function getGlobalScope(): Scope | null;
|
|
94
|
-
/**
|
|
95
|
-
* Returns true if a global root scope exists.
|
|
96
|
-
*/
|
|
97
|
-
export declare function hasGlobalScope(): boolean;
|
|
98
|
-
/**
|
|
99
|
-
* Resets the global root scope.
|
|
100
|
-
* Intended for tests to ensure isolation between runs.
|
|
101
|
-
*/
|
|
102
|
-
export declare function resetGlobalScope(): void;
|
|
103
|
-
/**
|
|
104
|
-
* Creates a reactive context that wraps a signal.
|
|
105
|
-
*
|
|
106
|
-
* This is the recommended way to share reactive state across scopes.
|
|
107
|
-
* It combines the hierarchical lookup of Context with the reactivity of Signals.
|
|
108
|
-
*
|
|
109
|
-
* Example:
|
|
110
|
-
* ```ts
|
|
111
|
-
* const Theme = createSignalContext("theme", "dark");
|
|
112
|
-
*
|
|
113
|
-
* scope(() => {
|
|
114
|
-
* // Parent scope: create and provide the signal
|
|
115
|
-
* const theme = Theme.provide();
|
|
116
|
-
*
|
|
117
|
-
* effect(() => {
|
|
118
|
-
* console.log("Theme:", theme()); // Reactive!
|
|
119
|
-
* });
|
|
120
|
-
*
|
|
121
|
-
* theme.set("light"); // Updates propagate to all consumers
|
|
122
|
-
* });
|
|
123
|
-
*
|
|
124
|
-
* // Child scope somewhere in the tree
|
|
125
|
-
* scope(() => {
|
|
126
|
-
* const theme = Theme.inject(); // Get the signal from parent
|
|
127
|
-
* console.log(theme()); // "light"
|
|
128
|
-
* });
|
|
129
|
-
* ```
|
|
130
|
-
*/
|
|
131
|
-
export interface SignalContext<T> {
|
|
132
|
-
/**
|
|
133
|
-
* Create a signal with the initial value and provide it in the current scope.
|
|
134
|
-
* Returns the signal for immediate use.
|
|
135
|
-
*
|
|
136
|
-
* @param initialValue - Override the default initial value (optional)
|
|
137
|
-
*/
|
|
138
|
-
provide: (initialValue?: T) => Signal<T>;
|
|
139
|
-
/**
|
|
140
|
-
* Inject the signal from an ancestor scope.
|
|
141
|
-
* Throws if no provider exists in the scope hierarchy.
|
|
142
|
-
*/
|
|
143
|
-
inject: () => Signal<T>;
|
|
144
|
-
/**
|
|
145
|
-
* Try to inject the signal from an ancestor scope.
|
|
146
|
-
* Returns { found: true, signal } or { found: false, signal: undefined }.
|
|
147
|
-
*/
|
|
148
|
-
tryInject: () => {
|
|
149
|
-
found: true;
|
|
150
|
-
signal: Signal<T>;
|
|
151
|
-
} | {
|
|
152
|
-
found: false;
|
|
153
|
-
signal: undefined;
|
|
154
|
-
};
|
|
155
|
-
/**
|
|
156
|
-
* The underlying context token (for advanced use cases).
|
|
157
|
-
*/
|
|
158
|
-
token: ContextToken<Signal<T>>;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Create a reactive context that wraps a signal.
|
|
162
|
-
*
|
|
163
|
-
* @param name - Debug name for the context
|
|
164
|
-
* @param defaultValue - Default initial value for the signal
|
|
165
|
-
*/
|
|
166
|
-
export declare function createSignalContext<T>(name: string, defaultValue: T): SignalContext<T>;
|
|
167
|
-
export { createContext };
|