@praxisjs/runtime 0.2.8 → 0.2.10
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/CHANGELOG.md +41 -0
- package/dist/component.d.ts.map +1 -1
- package/dist/component.js +35 -32
- package/dist/component.js.map +1 -1
- package/package.json +3 -3
- package/src/component.ts +36 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# @praxisjs/runtime
|
|
2
2
|
|
|
3
|
+
## 0.2.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [2c61a25]
|
|
8
|
+
- @praxisjs/decorators@0.7.2
|
|
9
|
+
|
|
10
|
+
## 0.2.9
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 6c353ba: Add `untrack` utility and isolate component mounting from outer reactive contexts
|
|
15
|
+
|
|
16
|
+
**`@praxisjs/core`** exports two new functions from the public API:
|
|
17
|
+
|
|
18
|
+
- `peek(signal)` — reads a signal once without subscribing to it (was already in `/internal`, now public)
|
|
19
|
+
- `untrack(fn)` — runs a function with no active effect, suppressing all signal tracking inside it
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { peek, untrack } from "@praxisjs/core";
|
|
23
|
+
|
|
24
|
+
// read a signal without creating a dependency
|
|
25
|
+
if (peek(this.max) > peek(this.count)) {
|
|
26
|
+
this.count++;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// suppress tracking for a block of reads
|
|
30
|
+
const snapshot = untrack(() => this.totalCost);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**`@praxisjs/runtime`** — `mountComponent` now runs entirely inside `untrack`. This fixes a bug where components mounted inside a reactive context (e.g. the router) would accidentally subscribe the outer effect to any signal read during construction or render. The symptoms were:
|
|
34
|
+
|
|
35
|
+
- Eager reads like `description={this.count}` in JSX causing the router to re-mount the component on every state change, resetting state to its initial value
|
|
36
|
+
- `@Debug()` (and any decorator that reads a signal in its `addInitializer`) triggering the same re-mount loop
|
|
37
|
+
|
|
38
|
+
Reactive subscriptions set up via `{() => signal}` in JSX are unaffected — each arrow function creates its own isolated effect.
|
|
39
|
+
|
|
40
|
+
- Updated dependencies [6c353ba]
|
|
41
|
+
- @praxisjs/core@1.2.0
|
|
42
|
+
- @praxisjs/decorators@0.7.1
|
|
43
|
+
|
|
3
44
|
## 0.2.8
|
|
4
45
|
|
|
5
46
|
### Patch Changes
|
package/dist/component.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,KAAK,oBAAoB,EAAG,MAAM,2BAA2B,CAAC;AAKpF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,wBAAgB,cAAc,CAC5B,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,WAAW,EAAE,KAAK,GACjB,IAAI,EAAE,CA+CR;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/component.js
CHANGED
|
@@ -1,42 +1,45 @@
|
|
|
1
|
+
import { untrack } from "@praxisjs/core/internal";
|
|
1
2
|
import { initSlots } from "@praxisjs/decorators";
|
|
2
3
|
import { isComponent } from "@praxisjs/shared/internal";
|
|
3
4
|
import { mountChildren } from "./children";
|
|
4
5
|
import { runInScope } from "./context";
|
|
5
6
|
export function mountComponent(ctor, props, parentScope) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const start = document.createComment(`[${ctor.name}]`);
|
|
13
|
-
const end = document.createComment(`[/${ctor.name}]`);
|
|
14
|
-
// Expose anchor so decorators like @Virtual can find the parent element
|
|
15
|
-
instance._anchor = end;
|
|
16
|
-
instance.onBeforeMount?.();
|
|
17
|
-
const container = document.createDocumentFragment();
|
|
18
|
-
container.appendChild(start);
|
|
19
|
-
let dom = null;
|
|
20
|
-
runInScope(scope, () => {
|
|
21
|
-
try {
|
|
22
|
-
dom = instance.render();
|
|
7
|
+
return untrack(() => {
|
|
8
|
+
const scope = parentScope.fork();
|
|
9
|
+
const instance = new ctor({ ...props });
|
|
10
|
+
const rawChildren = props.children;
|
|
11
|
+
if (rawChildren != null) {
|
|
12
|
+
initSlots(instance, rawChildren);
|
|
23
13
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
14
|
+
const start = document.createComment(`[${ctor.name}]`);
|
|
15
|
+
const end = document.createComment(`[/${ctor.name}]`);
|
|
16
|
+
// Expose anchor so decorators like @Virtual can find the parent element
|
|
17
|
+
instance._anchor = end;
|
|
18
|
+
instance.onBeforeMount?.();
|
|
19
|
+
const container = document.createDocumentFragment();
|
|
20
|
+
container.appendChild(start);
|
|
21
|
+
let dom = null;
|
|
22
|
+
runInScope(scope, () => {
|
|
23
|
+
try {
|
|
24
|
+
dom = instance.render();
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
instance.onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
mountChildren(container, dom, scope);
|
|
31
|
+
container.appendChild(end);
|
|
32
|
+
queueMicrotask(() => {
|
|
33
|
+
instance._mounted = true;
|
|
34
|
+
instance.onMount?.();
|
|
35
|
+
});
|
|
36
|
+
scope.add(() => {
|
|
37
|
+
instance.onUnmount?.();
|
|
38
|
+
instance._mounted = false;
|
|
39
|
+
});
|
|
40
|
+
// Return the nodes from the fragment as an array so the caller can append them
|
|
41
|
+
return Array.from(container.childNodes);
|
|
37
42
|
});
|
|
38
|
-
// Return the nodes from the fragment as an array so the caller can append them
|
|
39
|
-
return Array.from(container.childNodes);
|
|
40
43
|
}
|
|
41
44
|
export { isComponent };
|
|
42
45
|
//# sourceMappingURL=component.js.map
|
package/dist/component.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,WAAW,EAA8B,MAAM,2BAA2B,CAAC;AAEpF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,MAAM,UAAU,cAAc,CAC5B,IAA0B,EAC1B,KAA8B,EAC9B,WAAkB;IAElB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,WAAW,EAA8B,MAAM,2BAA2B,CAAC;AAEpF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,MAAM,UAAU,cAAc,CAC5B,IAA0B,EAC1B,KAA8B,EAC9B,WAAkB;IAElB,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;QAEjC,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QAExC,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC;QACnC,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACnC,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACvD,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QAEtD,wEAAwE;QACxE,QAAQ,CAAC,OAAO,GAAG,GAAG,CAAC;QAEvB,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC;QAE3B,MAAM,SAAS,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;QACpD,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAE7B,IAAI,GAAG,GAAyB,IAAI,CAAC;QACrC,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC;gBACH,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC1B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,aAAa,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;QACrC,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAE3B,cAAc,CAAC,GAAG,EAAE;YAClB,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;YACzB,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YACb,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;YACvB,QAAQ,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,+EAA+E;QAC/E,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/runtime",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"typescript": "^5.9.3"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@praxisjs/core": "1.
|
|
18
|
-
"@praxisjs/decorators": "0.7.
|
|
17
|
+
"@praxisjs/core": "1.2.0",
|
|
18
|
+
"@praxisjs/decorators": "0.7.2",
|
|
19
19
|
"@praxisjs/shared": "0.2.0"
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
package/src/component.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { untrack } from "@praxisjs/core/internal";
|
|
1
2
|
import { initSlots } from "@praxisjs/decorators";
|
|
2
3
|
import { isComponent, type ComponentConstructor } from "@praxisjs/shared/internal";
|
|
3
4
|
|
|
@@ -11,50 +12,52 @@ export function mountComponent(
|
|
|
11
12
|
props: Record<string, unknown>,
|
|
12
13
|
parentScope: Scope,
|
|
13
14
|
): Node[] {
|
|
14
|
-
|
|
15
|
+
return untrack(() => {
|
|
16
|
+
const scope = parentScope.fork();
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
const instance = new ctor({ ...props });
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const rawChildren = props.children;
|
|
21
|
+
if (rawChildren != null) {
|
|
22
|
+
initSlots(instance, rawChildren);
|
|
23
|
+
}
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const start = document.createComment(`[${ctor.name}]`);
|
|
26
|
+
const end = document.createComment(`[/${ctor.name}]`);
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
// Expose anchor so decorators like @Virtual can find the parent element
|
|
29
|
+
instance._anchor = end;
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
instance.onBeforeMount?.();
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
const container = document.createDocumentFragment();
|
|
34
|
+
container.appendChild(start);
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
let dom: Node | Node[] | null = null;
|
|
37
|
+
runInScope(scope, () => {
|
|
38
|
+
try {
|
|
39
|
+
dom = instance.render();
|
|
40
|
+
} catch (e) {
|
|
41
|
+
instance.onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
mountChildren(container, dom, scope);
|
|
46
|
+
container.appendChild(end);
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
queueMicrotask(() => {
|
|
49
|
+
instance._mounted = true;
|
|
50
|
+
instance.onMount?.();
|
|
51
|
+
});
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
scope.add(() => {
|
|
54
|
+
instance.onUnmount?.();
|
|
55
|
+
instance._mounted = false;
|
|
56
|
+
});
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
// Return the nodes from the fragment as an array so the caller can append them
|
|
59
|
+
return Array.from(container.childNodes);
|
|
60
|
+
});
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
export { isComponent };
|