refactor: helpers, import type, cleanup

This commit is contained in:
三咲智子 Kevin Deng 2023-11-24 11:07:31 +08:00
parent 79fc4025c3
commit d02629efa2
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
6 changed files with 140 additions and 109 deletions

View File

@ -3,7 +3,7 @@
exports[`basic 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
import { watchEffect } from 'vue'
import { template, setAttr, setText, children, on, insert } from 'vue/vapor'
import { template, insert, setText, on } from 'vue/vapor'
const t0 = template(\`<h1 id=\\"title\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button>\`)
import { ref, computed } from 'vue'

View File

@ -1,7 +1,7 @@
import {
CodegenResult,
CompilerOptions,
RootNode,
type CodegenResult,
type CompilerOptions,
type RootNode,
baseParse,
} from '@vue/compiler-dom'
import { isString } from '@vue/shared'

View File

@ -1,9 +1,9 @@
import {
import type {
CodegenContext,
CodegenOptions,
CodegenResult,
} from '@vue/compiler-dom'
import { DynamicChildren, IRNodeTypes, RootIRNode } from './transform'
import { type DynamicChildren, type RootIRNode, IRNodeTypes } from './ir'
// IR -> JS codegen
export function generate(
@ -13,26 +13,28 @@ export function generate(
} = {},
): CodegenResult {
let code = ''
let preamble = `import { watchEffect } from 'vue'
import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
const isSetupInlined = !!options.inline
let preamble = ''
const { helpers, vaporHelpers } = ir
if (ir.template.length) {
preamble += ir.template
.map((template, i) => `const t${i} = template(\`${template.template}\`)\n`)
.map(
(template, i) => `const t${i} = template(\`${template.template}\`)\n`,
)
.join('')
vaporHelpers.add('template')
}
code += `const root = t0()\n`
if (ir.children[0]) {
code += `const {${genChildrens(
ir.children[0].children,
)}} = children(root)\n`
code += `const {${genChildren(ir.children[0].children)}} = children(root)\n`
vaporHelpers.add('children')
}
for (const opration of ir.opration) {
switch (opration.type) {
case IRNodeTypes.TEXT_NODE: {
// TODO handle by runtime: document.createTextNode
code += `const n${opration.id} = document.createTextNode(${opration.content})\n`
break
}
@ -46,6 +48,7 @@ import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
anchor = `, 0 /* InsertPosition.FIRST */`
}
code += `insert(n${opration.element}, n${opration.parent}${anchor})\n`
vaporHelpers.add('insert')
}
break
}
@ -53,30 +56,44 @@ import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
for (const [expr, effects] of Object.entries(ir.effect)) {
let scope = `watchEffect(() => {\n`
helpers.add('watchEffect')
for (const effect of effects) {
switch (effect.type) {
case IRNodeTypes.SET_PROP:
case IRNodeTypes.SET_PROP: {
scope += `setAttr(n${effect.element}, ${JSON.stringify(
effect.name,
)}, undefined, ${expr})\n`
vaporHelpers.add('setAttr')
break
case IRNodeTypes.SET_TEXT:
}
case IRNodeTypes.SET_TEXT: {
scope += `setText(n${effect.element}, undefined, ${expr})\n`
vaporHelpers.add('setText')
break
case IRNodeTypes.SET_EVENT:
}
case IRNodeTypes.SET_EVENT: {
scope += `on(n${effect.element}, ${JSON.stringify(
effect.name,
)}, ${expr})\n`
vaporHelpers.add('on')
break
}
}
}
scope += '})\n'
code += scope
}
code += 'return root'
if (vaporHelpers.size)
preamble =
`import { ${[...vaporHelpers].join(', ')} } from 'vue/vapor'\n` + preamble
if (helpers.size)
preamble = `import { ${[...helpers].join(', ')} } from 'vue'\n` + preamble
const functionName = options.ssr ? `ssrRender` : `render`
const isSetupInlined = !!options.inline
if (isSetupInlined) {
code = `(() => {\n${code}\n})();`
} else {
@ -90,7 +107,7 @@ import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
}
}
function genChildrens(children: DynamicChildren) {
function genChildren(children: DynamicChildren) {
let str = ''
for (const [index, child] of Object.entries(children)) {
str += ` ${index}: [`
@ -98,7 +115,7 @@ function genChildrens(children: DynamicChildren) {
str += `n${child.id}`
}
if (Object.keys(child.children).length) {
str += `, {${genChildrens(child.children)}}`
str += `, {${genChildren(child.children)}}`
}
str += '],'
}

View File

@ -2,3 +2,4 @@ export { parse } from '@vue/compiler-dom'
export { transform } from './transform'
export { generate } from './generate'
export { compile } from './compile'
export * from './ir'

View File

@ -0,0 +1,72 @@
import type { SourceLocation } from '@vue/compiler-dom'
export const enum IRNodeTypes {
ROOT,
TEMPLATE_GENERATOR,
SET_PROP,
SET_TEXT,
SET_EVENT,
INSERT_NODE,
TEXT_NODE,
}
export interface IRNode {
type: IRNodeTypes
loc: SourceLocation
}
export interface RootIRNode extends IRNode {
type: IRNodeTypes.ROOT
template: Array<TemplateGeneratorIRNode>
children: DynamicChildren
effect: Record<string, EffectNode[]>
opration: OprationNode[]
helpers: Set<string>
vaporHelpers: Set<string>
}
export interface TemplateGeneratorIRNode extends IRNode {
type: IRNodeTypes.TEMPLATE_GENERATOR
template: string
}
export interface SetPropIRNode extends IRNode {
type: IRNodeTypes.SET_PROP
element: number
name: string
}
export interface SetTextIRNode extends IRNode {
type: IRNodeTypes.SET_TEXT
element: number
}
export interface SetEventIRNode extends IRNode {
type: IRNodeTypes.SET_EVENT
element: number
name: string
}
export interface TextNodeIRNode extends IRNode {
type: IRNodeTypes.TEXT_NODE
id: number
content: string
}
export interface InsertNodeIRNode extends IRNode {
type: IRNodeTypes.INSERT_NODE
element: number
parent: number
anchor: number | 'first' | 'last'
}
export type EffectNode = SetPropIRNode | SetTextIRNode | SetEventIRNode
export type OprationNode = TextNodeIRNode | InsertNodeIRNode
export interface DynamicChild {
id: number | null
store: boolean
children: DynamicChildren
}
export type DynamicChildren = Record<number, DynamicChild>

View File

@ -1,85 +1,21 @@
import {
type NodeTypes,
import type {
NodeTypes,
RootNode,
Node,
TemplateChildNode,
ElementNode,
AttributeNode,
SourceLocation,
InterpolationNode,
TransformOptions,
DirectiveNode,
} from '@vue/compiler-dom'
export const enum IRNodeTypes {
ROOT,
TEMPLATE_GENERATOR,
SET_PROP,
SET_TEXT,
SET_EVENT,
INSERT_NODE,
TEXT_NODE,
}
export interface IRNode {
type: IRNodeTypes
loc: SourceLocation
}
export interface RootIRNode extends IRNode {
type: IRNodeTypes.ROOT
template: Array<TemplateGeneratorIRNode>
children: DynamicChildren
effect: Record<string, EffectNode[]>
opration: OprationNode[]
helpers: Set<string>
}
export interface TemplateGeneratorIRNode extends IRNode {
type: IRNodeTypes.TEMPLATE_GENERATOR
template: string
}
export interface SetPropIRNode extends IRNode {
type: IRNodeTypes.SET_PROP
element: number
name: string
}
export interface SetTextIRNode extends IRNode {
type: IRNodeTypes.SET_TEXT
element: number
}
export interface SetEventIRNode extends IRNode {
type: IRNodeTypes.SET_EVENT
element: number
name: string
}
export interface TextNodeIRNode extends IRNode {
type: IRNodeTypes.TEXT_NODE
id: number
content: string
}
export interface InsertNodeIRNode extends IRNode {
type: IRNodeTypes.INSERT_NODE
element: number
parent: number
anchor: number | 'first' | 'last'
}
export type EffectNode = SetPropIRNode | SetTextIRNode | SetEventIRNode
export type OprationNode = TextNodeIRNode | InsertNodeIRNode
export interface DynamicChild {
id: number | null
store: boolean
children: DynamicChildren
}
export type DynamicChildren = Record<number, DynamicChild>
import {
type DynamicChildren,
type EffectNode,
type OprationNode,
type RootIRNode,
IRNodeTypes,
} from './ir'
export interface TransformContext<T extends Node = Node> {
node: T
@ -87,15 +23,17 @@ export interface TransformContext<T extends Node = Node> {
root: TransformContext<RootNode>
index: number
options: TransformOptions
ir: RootIRNode
// ir: RootIRNode
template: string
children: DynamicChildren
store: boolean
ghost: boolean
getElementId(): number
registerEffect(expr: string, effectNode: EffectNode): void
registerTemplate(): number
registerEffect(expr: string, effectNode: EffectNode): void
registerOpration(...oprations: OprationNode[]): void
helper(name: string): string
}
function createRootContext(
@ -104,7 +42,7 @@ function createRootContext(
options: TransformOptions,
): TransformContext<RootNode> {
let i = 0
const { effect: bindings } = ir
const { effect, opration, helpers, vaporHelpers } = ir
const ctx: TransformContext<RootNode> = {
node,
@ -112,15 +50,14 @@ function createRootContext(
index: 0,
root: undefined as any, // set later
options,
ir,
children: {},
store: false,
ghost: false,
getElementId: () => i++,
registerEffect(expr, effectNode) {
if (!bindings[expr]) bindings[expr] = []
bindings[expr].push(effectNode)
if (!effect[expr]) effect[expr] = []
effect[expr].push(effectNode)
},
template: '',
@ -137,6 +74,14 @@ function createRootContext(
})
return ir.template.length - 1
},
registerOpration(...node) {
opration.push(...node)
},
// TODO not used yet
helper(name, vapor = true) {
;(vapor ? vaporHelpers : helpers).add(name)
return name
},
}
ctx.root = ctx
return ctx
@ -178,12 +123,6 @@ export function transform(
root: RootNode,
options: TransformOptions = {},
): RootIRNode {
// {
// type: IRNodeTypes.TEMPLATE_GENERATOR,
// template,
// loc: root.loc
// }
const ir: RootIRNode = {
type: IRNodeTypes.ROOT,
loc: root.loc,
@ -191,7 +130,8 @@ export function transform(
children: {},
effect: Object.create(null),
opration: [],
helpers: new Set(['template']),
helpers: new Set([]),
vaporHelpers: new Set([]),
}
const ctx = createRootContext(ir, root, options)
transformChildren(ctx, true)
@ -303,7 +243,7 @@ function transformInterpolation(
anchor = isFirst ? 'first' : 'last'
}
ctx.ir.opration.push(
ctx.registerOpration(
{
type: IRNodeTypes.TEXT_NODE,
loc: node.loc,
@ -379,6 +319,7 @@ function transformProp(
}
}
// TODO: reference packages/compiler-core/src/transforms/transformExpression.ts
function processExpression(ctx: TransformContext, expr: string) {
if (ctx.options.bindingMetadata?.[expr] === 'setup-ref') {
expr += '.value'