Skip to content

Commit b84fff0

Browse files
committed
refactor(compiler): add customized createNodes and setNodes IR
1 parent 8ba88c2 commit b84fff0

37 files changed

+1231
-1070
lines changed

packages/babel/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,14 @@ export default (): {
9494
statements.unshift(preambleResult)
9595
}
9696

97-
const helpers = ['setText', 'createTextNode'].filter((helper) => {
97+
const helpers = ['setNodes', 'createNodes'].filter((helper) => {
9898
const result = importSet.has(helper)
9999
result && importSet.delete(helper)
100100
return result
101101
})
102102
if (helpers.length) {
103103
statements.unshift(
104-
`import { ${helpers.map((i) => `${i} as _${i}`).join(', ')} } from 'vue-jsx-vapor/helper.js';\n`,
104+
`import { ${helpers.map((i) => `${i} as _${i}`).join(', ')} } from 'vue-jsx-vapor';\n`,
105105
)
106106
}
107107

packages/babel/test/transform.spec.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@ describe('transform', () => {
1313
},
1414
)!
1515
expect(code).toMatchInlineSnapshot(`
16-
"import { delegateEvents as _delegateEvents, template as _template, createIf as _createIf } from 'vue';
17-
import { setText as _setText } from 'vue-jsx-vapor/helper.js';
18-
const _t00 = _template("<div></div>", true);
16+
"import { child as _child, delegateEvents as _delegateEvents, template as _template, createIf as _createIf } from 'vue';
17+
import { setNodes as _setNodes } from 'vue-jsx-vapor';
18+
const _t00 = _template("<div> </div>", true);
1919
const _t10 = _template("<div>Hello</div>");
2020
const _t11 = _template("<div>World</div>");
2121
_delegateEvents("click", "dblclick");
2222
const a = (() => {
2323
const n0 = _t00();
24-
_setText(n0, () => Hello);
24+
const x0 = _child(n0);
25+
_setNodes(x0, () => Hello);
2526
n0.$evtclick = e => onClick(e);
2627
return n0;
2728
})();

packages/compiler/src/compile.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import {
44
type VaporCodegenResult as BaseVaporCodegenResult,
55
} from '@vue/compiler-vapor'
66
import { extend, isString } from '@vue/shared'
7+
import { customGenOperation } from './generate'
8+
79
import {
810
IRNodeTypes,
911
type HackOptions,
1012
type RootIRNode,
1113
type RootNode,
1214
} from './ir'
13-
1415
import {
1516
transform,
1617
type DirectiveTransform,
@@ -38,6 +39,7 @@ export { generate }
3839
export interface VaporCodegenResult
3940
extends Omit<BaseVaporCodegenResult, 'ast'> {
4041
ast: RootIRNode
42+
customHelpers: Set<string>
4143
}
4244

4345
// code/AST -> IR (transform) -> JS (generate)
@@ -98,7 +100,10 @@ export function compile(
98100
}),
99101
)
100102

101-
return generate(ir as any, resolvedOptions) as unknown as VaporCodegenResult
103+
return generate(ir as any, {
104+
...resolvedOptions,
105+
customGenOperation,
106+
}) as unknown as VaporCodegenResult
102107
}
103108

104109
export type CompilerOptions = HackOptions<BaseCompilerOptions> & {

packages/compiler/src/generate.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {
2+
genCall,
3+
genExpression,
4+
NEWLINE,
5+
type CodeFragment,
6+
type CodegenContext,
7+
} from '@vue/compiler-vapor'
8+
import {
9+
IRNodeTypes,
10+
type CreateNodesIRNode,
11+
type OperationNode,
12+
type SetNodesIRNode,
13+
} from './ir'
14+
import type { SimpleExpressionNode } from '@vue/compiler-dom'
15+
16+
export const customGenOperation = (
17+
oper: OperationNode,
18+
context: CodegenContext,
19+
) => {
20+
if (oper.type === IRNodeTypes.CREATE_NODES) {
21+
return genCreateNodes(oper, context)
22+
} else if (oper.type === IRNodeTypes.SET_NODES) {
23+
return genSetNodes(oper, context)
24+
}
25+
}
26+
27+
export function genSetNodes(
28+
oper: SetNodesIRNode,
29+
context: CodegenContext,
30+
): CodeFragment[] {
31+
const { helper } = context
32+
const { element, values, generated } = oper
33+
return [
34+
NEWLINE,
35+
...genCall(
36+
helper('setNodes'),
37+
`${generated ? 'x' : 'n'}${element}`,
38+
combineValues(values, context),
39+
),
40+
]
41+
}
42+
43+
export function genCreateNodes(
44+
oper: CreateNodesIRNode,
45+
context: CodegenContext,
46+
): CodeFragment[] {
47+
const { helper } = context
48+
const { id, values } = oper
49+
return [
50+
NEWLINE,
51+
`const n${id} = `,
52+
...genCall(helper('createNodes'), values && combineValues(values, context)),
53+
]
54+
}
55+
56+
function combineValues(
57+
values: SimpleExpressionNode[],
58+
context: CodegenContext,
59+
): CodeFragment[] {
60+
return values.flatMap((value, i) => {
61+
const exp = genExpression(value, context)
62+
if (i > 0) {
63+
exp.unshift(', ')
64+
}
65+
return exp
66+
})
67+
}

packages/compiler/src/ir/index.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export enum IRNodeTypes {
2525

2626
INSERT_NODE,
2727
PREPEND_NODE,
28-
CREATE_TEXT_NODE,
2928
CREATE_COMPONENT_NODE,
3029
SLOT_OUTLET_NODE,
3130

@@ -36,6 +35,9 @@ export enum IRNodeTypes {
3635
FOR,
3736

3837
GET_TEXT_CHILD,
38+
39+
CREATE_NODES,
40+
SET_NODES,
3941
}
4042

4143
export interface BaseIRNode {
@@ -78,6 +80,8 @@ export interface IfIRNode extends BaseIRNode {
7880
positive: BlockIRNode
7981
negative?: BlockIRNode | IfIRNode
8082
once?: boolean
83+
parent?: number
84+
anchor?: number
8185
}
8286

8387
export interface IRFor {
@@ -95,6 +99,8 @@ export interface ForIRNode extends BaseIRNode, IRFor {
9599
once: boolean
96100
component: boolean
97101
onlyChild: boolean
102+
parent?: number
103+
anchor?: number
98104
}
99105

100106
export interface SetPropIRNode extends BaseIRNode {
@@ -118,12 +124,11 @@ export interface SetDynamicEventsIRNode extends BaseIRNode {
118124
event: SimpleExpressionNode
119125
}
120126

121-
export interface SetTextIRNode extends BaseIRNode {
122-
type: IRNodeTypes.SET_TEXT
127+
export interface SetNodesIRNode extends BaseIRNode {
128+
type: IRNodeTypes.SET_NODES
123129
element: number
124130
values: SimpleExpressionNode[]
125131
generated?: boolean // whether this is a generated empty text node by `processTextLikeContainer`
126-
jsx?: boolean
127132
}
128133

129134
export type KeyOverride = [find: string, replacement: string]
@@ -160,11 +165,10 @@ export interface SetTemplateRefIRNode extends BaseIRNode {
160165
effect: boolean
161166
}
162167

163-
export interface CreateTextNodeIRNode extends BaseIRNode {
164-
type: IRNodeTypes.CREATE_TEXT_NODE
168+
export interface CreateNodesIRNode extends BaseIRNode {
169+
type: IRNodeTypes.CREATE_NODES
165170
id: number
166171
values?: SimpleExpressionNode[]
167-
jsx?: boolean
168172
}
169173

170174
export interface InsertNodeIRNode extends BaseIRNode {
@@ -200,6 +204,8 @@ export interface CreateComponentIRNode extends BaseIRNode {
200204
root: boolean
201205
once: boolean
202206
dynamic?: SimpleExpressionNode
207+
parent?: number
208+
anchor?: number
203209
}
204210

205211
export interface DeclareOldRefIRNode extends BaseIRNode {
@@ -213,6 +219,8 @@ export interface SlotOutletIRNode extends BaseIRNode {
213219
name: SimpleExpressionNode
214220
props: IRProps[]
215221
fallback?: BlockIRNode
222+
parent?: number
223+
anchor?: number
216224
}
217225

218226
export interface GetTextChildIRNode extends BaseIRNode {
@@ -224,12 +232,12 @@ export type IRNode = OperationNode | RootIRNode
224232
export type OperationNode =
225233
| SetPropIRNode
226234
| SetDynamicPropsIRNode
227-
| SetTextIRNode
235+
| SetNodesIRNode
228236
| SetEventIRNode
229237
| SetDynamicEventsIRNode
230238
| SetHtmlIRNode
231239
| SetTemplateRefIRNode
232-
| CreateTextNodeIRNode
240+
| CreateNodesIRNode
233241
| InsertNodeIRNode
234242
| PrependNodeIRNode
235243
| DirectiveIRNode
@@ -263,6 +271,7 @@ export interface IRDynamicInfo {
263271
children: IRDynamicInfo[]
264272
template?: number
265273
hasDynamicChild?: boolean
274+
operation?: OperationNode
266275
}
267276

268277
export interface IREffect {
@@ -290,3 +299,19 @@ export type VaporDirectiveNode = Overwrite<
290299
arg: Exclude<DirectiveNode['arg'], CompoundExpressionNode>
291300
}
292301
>
302+
303+
export type InsertionStateTypes =
304+
| IfIRNode
305+
| ForIRNode
306+
| SlotOutletIRNode
307+
| CreateComponentIRNode
308+
309+
export function isBlockOperation(op: OperationNode): op is InsertionStateTypes {
310+
const type = op.type
311+
return (
312+
type === IRNodeTypes.CREATE_COMPONENT_NODE ||
313+
type === IRNodeTypes.SLOT_OUTLET_NODE ||
314+
type === IRNodeTypes.IF ||
315+
type === IRNodeTypes.FOR
316+
)
317+
}

packages/compiler/src/transforms/expression.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function processConditionalExpression(
2626
return [
2727
() => {
2828
onExit()
29-
context.registerOperation(operation)
29+
context.dynamic.operation = operation
3030
},
3131
() => {
3232
const [branch, onExit] = createBranch(alternate, context)
@@ -63,7 +63,7 @@ export function processLogicalExpression(
6363
return [
6464
() => {
6565
onExit()
66-
context.registerOperation(operation)
66+
context.dynamic.operation = operation
6767
},
6868
() => {
6969
const [branch, onExit] = createBranch(

packages/compiler/src/transforms/transformChildren.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { DynamicFlag, IRNodeTypes, type IRDynamicInfo } from '../ir/index'
1+
import {
2+
DynamicFlag,
3+
IRNodeTypes,
4+
isBlockOperation,
5+
type IRDynamicInfo,
6+
} from '../ir/index'
27
import {
38
transformNode,
49
type NodeTransform,
@@ -66,22 +71,11 @@ function processDynamicChildren(context: TransformContext<Node>) {
6671
if (prevDynamics.length) {
6772
if (hasStaticTemplate) {
6873
context.childrenTemplate[index - prevDynamics.length] = `<!>`
69-
7074
prevDynamics[0].flags -= DynamicFlag.NON_TEMPLATE
7175
const anchor = (prevDynamics[0].anchor = context.increaseId())
72-
73-
context.registerOperation({
74-
type: IRNodeTypes.INSERT_NODE,
75-
elements: prevDynamics.map((child) => child.id!),
76-
parent: context.reference(),
77-
anchor,
78-
})
76+
registerInsertion(prevDynamics, context, anchor)
7977
} else {
80-
context.registerOperation({
81-
type: IRNodeTypes.PREPEND_NODE,
82-
elements: prevDynamics.map((child) => child.id!),
83-
parent: context.reference(),
84-
})
78+
registerInsertion(prevDynamics, context, -1 /* prepend */)
8579
}
8680
prevDynamics = []
8781
}
@@ -97,3 +91,29 @@ function processDynamicChildren(context: TransformContext<Node>) {
9791
})
9892
}
9993
}
94+
95+
function registerInsertion(
96+
dynamics: IRDynamicInfo[],
97+
context: TransformContext,
98+
anchor?: number,
99+
) {
100+
for (const child of dynamics) {
101+
if (child.template != null) {
102+
// template node due to invalid nesting - generate actual insertion
103+
context.registerOperation({
104+
type: IRNodeTypes.INSERT_NODE,
105+
elements: dynamics.map((child) => child.id!),
106+
parent: context.reference(),
107+
anchor,
108+
})
109+
} else {
110+
// block types
111+
for (const op of context.block.operation) {
112+
if (isBlockOperation(op) && op.id === child.id) {
113+
op.parent = context.reference()
114+
op.anchor = anchor
115+
}
116+
}
117+
}
118+
}
119+
}

packages/compiler/src/transforms/transformElement.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function transformComponentElement(
104104

105105
context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
106106

107-
context.registerOperation({
107+
context.dynamic.operation = {
108108
type: IRNodeTypes.CREATE_COMPONENT_NODE,
109109
id: context.reference(),
110110
tag,
@@ -113,7 +113,7 @@ function transformComponentElement(
113113
root: singleRoot,
114114
slots: [...context.slots],
115115
once: context.inVOnce,
116-
})
116+
}
117117
context.slots = []
118118
}
119119

0 commit comments

Comments
 (0)