@sigil-dev/compiler 0.9.6 → 0.9.7
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/README.md +162 -162
- package/package.json +1 -1
- package/src/babel/index.ts +614 -608
- package/src/babel/jsx/anchor-mount.ts +408 -408
- package/src/babel/jsx/children.ts +108 -108
- package/src/babel/jsx/element.ts +863 -876
- package/src/babel/jsx/fragment.ts +259 -259
- package/src/babel/jsx/ssr.ts +45 -0
- package/test/hydration.test.ts +276 -276
- package/test/jsx.test.ts +10 -5
- package/test/scoped-css.test.ts +2 -2
- package/test/ssr-boolean-attrs.test.ts +56 -0
- package/test/style-object.test.ts +13 -13
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
import { types as t } from "@babel/core";
|
|
2
|
-
import { processElement } from "./element";
|
|
3
|
-
import { processFragment } from "./fragment";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Collect children from a JSX element into a children expression.
|
|
7
|
-
* Returns null if no meaningful children exist.
|
|
8
|
-
*
|
|
9
|
-
* DOM mode evaluates each JSX child immediately — the component receives real
|
|
10
|
-
* nodes. Hydrate mode emits thunks instead: a component's children live inside
|
|
11
|
-
* *its* root element, a subtree the call site cannot see, so they must claim
|
|
12
|
-
* from the pool that `hydrateSlot` pushes at the `{children}` site rather than
|
|
13
|
-
* from the caller's pool. Evaluating them eagerly here made them steal the
|
|
14
|
-
* component's own SSR root and re-render it (double render).
|
|
15
|
-
*/
|
|
16
|
-
export function collectChildren(
|
|
17
|
-
node: t.JSXElement,
|
|
18
|
-
_statements: t.Statement[],
|
|
19
|
-
genId: () => string,
|
|
20
|
-
signals: Set<string>,
|
|
21
|
-
hash?: string,
|
|
22
|
-
hydrate?: boolean,
|
|
23
|
-
nodesVar?: string,
|
|
24
|
-
): t.Expression | null {
|
|
25
|
-
const childrenElements: t.Expression[] = [];
|
|
26
|
-
let hasOnlyText = true;
|
|
27
|
-
// Deferred children open their own scope from the hydration stack.
|
|
28
|
-
const childNodesVar = hydrate ? "__nodes" : nodesVar;
|
|
29
|
-
|
|
30
|
-
for (const child of node.children) {
|
|
31
|
-
if (t.isJSXText(child)) {
|
|
32
|
-
const text = child.value.trim();
|
|
33
|
-
if (!text) continue;
|
|
34
|
-
childrenElements.push(t.stringLiteral(text));
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let jsx: t.JSXElement | t.JSXFragment | null = null;
|
|
39
|
-
if (t.isJSXElement(child) || t.isJSXFragment(child)) {
|
|
40
|
-
jsx = child;
|
|
41
|
-
} else if (t.isJSXExpressionContainer(child)) {
|
|
42
|
-
const expr = child.expression;
|
|
43
|
-
if (t.isJSXEmptyExpression(expr)) continue;
|
|
44
|
-
if (t.isJSXElement(expr) || t.isJSXFragment(expr)) {
|
|
45
|
-
jsx = expr;
|
|
46
|
-
} else {
|
|
47
|
-
// Plain expression child — pass the value straight through.
|
|
48
|
-
hasOnlyText = false;
|
|
49
|
-
childrenElements.push(expr);
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
hasOnlyText = false;
|
|
57
|
-
const childStatements: t.Statement[] = [];
|
|
58
|
-
const childVar = t.isJSXElement(jsx)
|
|
59
|
-
? processElement(
|
|
60
|
-
jsx,
|
|
61
|
-
childStatements,
|
|
62
|
-
genId,
|
|
63
|
-
signals,
|
|
64
|
-
hash,
|
|
65
|
-
hydrate,
|
|
66
|
-
childNodesVar,
|
|
67
|
-
)
|
|
68
|
-
: processFragment(
|
|
69
|
-
jsx,
|
|
70
|
-
childStatements,
|
|
71
|
-
genId,
|
|
72
|
-
signals,
|
|
73
|
-
hash,
|
|
74
|
-
hydrate,
|
|
75
|
-
childNodesVar,
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
const body: t.Statement[] = [];
|
|
79
|
-
if (hydrate) {
|
|
80
|
-
// const __nodes = getHydrationNodes() — resolved when the thunk runs
|
|
81
|
-
body.push(
|
|
82
|
-
t.variableDeclaration("const", [
|
|
83
|
-
t.variableDeclarator(
|
|
84
|
-
t.identifier("__nodes"),
|
|
85
|
-
t.callExpression(t.identifier("getHydrationNodes"), []),
|
|
86
|
-
),
|
|
87
|
-
]),
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
body.push(...childStatements, t.returnStatement(t.identifier(childVar)));
|
|
91
|
-
const thunk = t.arrowFunctionExpression([], t.blockStatement(body));
|
|
92
|
-
childrenElements.push(hydrate ? thunk : t.callExpression(thunk, []));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (childrenElements.length === 0) return null;
|
|
96
|
-
// Build the inner value: string for single text, array otherwise
|
|
97
|
-
let inner: t.Expression;
|
|
98
|
-
if (
|
|
99
|
-
childrenElements.length === 1 &&
|
|
100
|
-
hasOnlyText &&
|
|
101
|
-
t.isStringLiteral(childrenElements[0])
|
|
102
|
-
) {
|
|
103
|
-
inner = childrenElements[0];
|
|
104
|
-
} else {
|
|
105
|
-
inner = t.arrayExpression(childrenElements);
|
|
106
|
-
}
|
|
107
|
-
return inner;
|
|
108
|
-
}
|
|
1
|
+
import { types as t } from "@babel/core";
|
|
2
|
+
import { processElement } from "./element";
|
|
3
|
+
import { processFragment } from "./fragment";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Collect children from a JSX element into a children expression.
|
|
7
|
+
* Returns null if no meaningful children exist.
|
|
8
|
+
*
|
|
9
|
+
* DOM mode evaluates each JSX child immediately — the component receives real
|
|
10
|
+
* nodes. Hydrate mode emits thunks instead: a component's children live inside
|
|
11
|
+
* *its* root element, a subtree the call site cannot see, so they must claim
|
|
12
|
+
* from the pool that `hydrateSlot` pushes at the `{children}` site rather than
|
|
13
|
+
* from the caller's pool. Evaluating them eagerly here made them steal the
|
|
14
|
+
* component's own SSR root and re-render it (double render).
|
|
15
|
+
*/
|
|
16
|
+
export function collectChildren(
|
|
17
|
+
node: t.JSXElement,
|
|
18
|
+
_statements: t.Statement[],
|
|
19
|
+
genId: () => string,
|
|
20
|
+
signals: Set<string>,
|
|
21
|
+
hash?: string,
|
|
22
|
+
hydrate?: boolean,
|
|
23
|
+
nodesVar?: string,
|
|
24
|
+
): t.Expression | null {
|
|
25
|
+
const childrenElements: t.Expression[] = [];
|
|
26
|
+
let hasOnlyText = true;
|
|
27
|
+
// Deferred children open their own scope from the hydration stack.
|
|
28
|
+
const childNodesVar = hydrate ? "__nodes" : nodesVar;
|
|
29
|
+
|
|
30
|
+
for (const child of node.children) {
|
|
31
|
+
if (t.isJSXText(child)) {
|
|
32
|
+
const text = child.value.trim();
|
|
33
|
+
if (!text) continue;
|
|
34
|
+
childrenElements.push(t.stringLiteral(text));
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let jsx: t.JSXElement | t.JSXFragment | null = null;
|
|
39
|
+
if (t.isJSXElement(child) || t.isJSXFragment(child)) {
|
|
40
|
+
jsx = child;
|
|
41
|
+
} else if (t.isJSXExpressionContainer(child)) {
|
|
42
|
+
const expr = child.expression;
|
|
43
|
+
if (t.isJSXEmptyExpression(expr)) continue;
|
|
44
|
+
if (t.isJSXElement(expr) || t.isJSXFragment(expr)) {
|
|
45
|
+
jsx = expr;
|
|
46
|
+
} else {
|
|
47
|
+
// Plain expression child — pass the value straight through.
|
|
48
|
+
hasOnlyText = false;
|
|
49
|
+
childrenElements.push(expr);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
hasOnlyText = false;
|
|
57
|
+
const childStatements: t.Statement[] = [];
|
|
58
|
+
const childVar = t.isJSXElement(jsx)
|
|
59
|
+
? processElement(
|
|
60
|
+
jsx,
|
|
61
|
+
childStatements,
|
|
62
|
+
genId,
|
|
63
|
+
signals,
|
|
64
|
+
hash,
|
|
65
|
+
hydrate,
|
|
66
|
+
childNodesVar,
|
|
67
|
+
)
|
|
68
|
+
: processFragment(
|
|
69
|
+
jsx,
|
|
70
|
+
childStatements,
|
|
71
|
+
genId,
|
|
72
|
+
signals,
|
|
73
|
+
hash,
|
|
74
|
+
hydrate,
|
|
75
|
+
childNodesVar,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const body: t.Statement[] = [];
|
|
79
|
+
if (hydrate) {
|
|
80
|
+
// const __nodes = getHydrationNodes() — resolved when the thunk runs
|
|
81
|
+
body.push(
|
|
82
|
+
t.variableDeclaration("const", [
|
|
83
|
+
t.variableDeclarator(
|
|
84
|
+
t.identifier("__nodes"),
|
|
85
|
+
t.callExpression(t.identifier("getHydrationNodes"), []),
|
|
86
|
+
),
|
|
87
|
+
]),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
body.push(...childStatements, t.returnStatement(t.identifier(childVar)));
|
|
91
|
+
const thunk = t.arrowFunctionExpression([], t.blockStatement(body));
|
|
92
|
+
childrenElements.push(hydrate ? thunk : t.callExpression(thunk, []));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (childrenElements.length === 0) return null;
|
|
96
|
+
// Build the inner value: string for single text, array otherwise
|
|
97
|
+
let inner: t.Expression;
|
|
98
|
+
if (
|
|
99
|
+
childrenElements.length === 1 &&
|
|
100
|
+
hasOnlyText &&
|
|
101
|
+
t.isStringLiteral(childrenElements[0])
|
|
102
|
+
) {
|
|
103
|
+
inner = childrenElements[0];
|
|
104
|
+
} else {
|
|
105
|
+
inner = t.arrayExpression(childrenElements);
|
|
106
|
+
}
|
|
107
|
+
return inner;
|
|
108
|
+
}
|