mirror of https://github.com/vuejs/core.git
refactor: helpers, import type, cleanup
This commit is contained in:
parent
79fc4025c3
commit
d02629efa2
|
@ -3,7 +3,7 @@
|
||||||
exports[`basic 1`] = `
|
exports[`basic 1`] = `
|
||||||
"import { defineComponent as _defineComponent } from 'vue'
|
"import { defineComponent as _defineComponent } from 'vue'
|
||||||
import { watchEffect } 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>\`)
|
const t0 = template(\`<h1 id=\\"title\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button>\`)
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {
|
import {
|
||||||
CodegenResult,
|
type CodegenResult,
|
||||||
CompilerOptions,
|
type CompilerOptions,
|
||||||
RootNode,
|
type RootNode,
|
||||||
baseParse,
|
baseParse,
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { isString } from '@vue/shared'
|
import { isString } from '@vue/shared'
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import {
|
import type {
|
||||||
CodegenContext,
|
CodegenContext,
|
||||||
CodegenOptions,
|
CodegenOptions,
|
||||||
CodegenResult,
|
CodegenResult,
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { DynamicChildren, IRNodeTypes, RootIRNode } from './transform'
|
import { type DynamicChildren, type RootIRNode, IRNodeTypes } from './ir'
|
||||||
|
|
||||||
// IR -> JS codegen
|
// IR -> JS codegen
|
||||||
export function generate(
|
export function generate(
|
||||||
|
@ -13,26 +13,28 @@ export function generate(
|
||||||
} = {},
|
} = {},
|
||||||
): CodegenResult {
|
): CodegenResult {
|
||||||
let code = ''
|
let code = ''
|
||||||
let preamble = `import { watchEffect } from 'vue'
|
let preamble = ''
|
||||||
import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
|
|
||||||
|
|
||||||
const isSetupInlined = !!options.inline
|
const { helpers, vaporHelpers } = ir
|
||||||
|
if (ir.template.length) {
|
||||||
preamble += ir.template
|
preamble += ir.template
|
||||||
.map((template, i) => `const t${i} = template(\`${template.template}\`)\n`)
|
.map(
|
||||||
.join('')
|
(template, i) => `const t${i} = template(\`${template.template}\`)\n`,
|
||||||
|
)
|
||||||
|
.join('')
|
||||||
|
vaporHelpers.add('template')
|
||||||
|
}
|
||||||
|
|
||||||
code += `const root = t0()\n`
|
code += `const root = t0()\n`
|
||||||
|
|
||||||
if (ir.children[0]) {
|
if (ir.children[0]) {
|
||||||
code += `const {${genChildrens(
|
code += `const {${genChildren(ir.children[0].children)}} = children(root)\n`
|
||||||
ir.children[0].children,
|
vaporHelpers.add('children')
|
||||||
)}} = children(root)\n`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const opration of ir.opration) {
|
for (const opration of ir.opration) {
|
||||||
switch (opration.type) {
|
switch (opration.type) {
|
||||||
case IRNodeTypes.TEXT_NODE: {
|
case IRNodeTypes.TEXT_NODE: {
|
||||||
|
// TODO handle by runtime: document.createTextNode
|
||||||
code += `const n${opration.id} = document.createTextNode(${opration.content})\n`
|
code += `const n${opration.id} = document.createTextNode(${opration.content})\n`
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -46,6 +48,7 @@ import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
|
||||||
anchor = `, 0 /* InsertPosition.FIRST */`
|
anchor = `, 0 /* InsertPosition.FIRST */`
|
||||||
}
|
}
|
||||||
code += `insert(n${opration.element}, n${opration.parent}${anchor})\n`
|
code += `insert(n${opration.element}, n${opration.parent}${anchor})\n`
|
||||||
|
vaporHelpers.add('insert')
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -53,21 +56,28 @@ import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
|
||||||
|
|
||||||
for (const [expr, effects] of Object.entries(ir.effect)) {
|
for (const [expr, effects] of Object.entries(ir.effect)) {
|
||||||
let scope = `watchEffect(() => {\n`
|
let scope = `watchEffect(() => {\n`
|
||||||
|
helpers.add('watchEffect')
|
||||||
for (const effect of effects) {
|
for (const effect of effects) {
|
||||||
switch (effect.type) {
|
switch (effect.type) {
|
||||||
case IRNodeTypes.SET_PROP:
|
case IRNodeTypes.SET_PROP: {
|
||||||
scope += `setAttr(n${effect.element}, ${JSON.stringify(
|
scope += `setAttr(n${effect.element}, ${JSON.stringify(
|
||||||
effect.name,
|
effect.name,
|
||||||
)}, undefined, ${expr})\n`
|
)}, undefined, ${expr})\n`
|
||||||
|
vaporHelpers.add('setAttr')
|
||||||
break
|
break
|
||||||
case IRNodeTypes.SET_TEXT:
|
}
|
||||||
|
case IRNodeTypes.SET_TEXT: {
|
||||||
scope += `setText(n${effect.element}, undefined, ${expr})\n`
|
scope += `setText(n${effect.element}, undefined, ${expr})\n`
|
||||||
|
vaporHelpers.add('setText')
|
||||||
break
|
break
|
||||||
case IRNodeTypes.SET_EVENT:
|
}
|
||||||
|
case IRNodeTypes.SET_EVENT: {
|
||||||
scope += `on(n${effect.element}, ${JSON.stringify(
|
scope += `on(n${effect.element}, ${JSON.stringify(
|
||||||
effect.name,
|
effect.name,
|
||||||
)}, ${expr})\n`
|
)}, ${expr})\n`
|
||||||
|
vaporHelpers.add('on')
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope += '})\n'
|
scope += '})\n'
|
||||||
|
@ -76,7 +86,14 @@ import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
|
||||||
|
|
||||||
code += 'return root'
|
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 functionName = options.ssr ? `ssrRender` : `render`
|
||||||
|
const isSetupInlined = !!options.inline
|
||||||
if (isSetupInlined) {
|
if (isSetupInlined) {
|
||||||
code = `(() => {\n${code}\n})();`
|
code = `(() => {\n${code}\n})();`
|
||||||
} else {
|
} 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 = ''
|
let str = ''
|
||||||
for (const [index, child] of Object.entries(children)) {
|
for (const [index, child] of Object.entries(children)) {
|
||||||
str += ` ${index}: [`
|
str += ` ${index}: [`
|
||||||
|
@ -98,7 +115,7 @@ function genChildrens(children: DynamicChildren) {
|
||||||
str += `n${child.id}`
|
str += `n${child.id}`
|
||||||
}
|
}
|
||||||
if (Object.keys(child.children).length) {
|
if (Object.keys(child.children).length) {
|
||||||
str += `, {${genChildrens(child.children)}}`
|
str += `, {${genChildren(child.children)}}`
|
||||||
}
|
}
|
||||||
str += '],'
|
str += '],'
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,4 @@ export { parse } from '@vue/compiler-dom'
|
||||||
export { transform } from './transform'
|
export { transform } from './transform'
|
||||||
export { generate } from './generate'
|
export { generate } from './generate'
|
||||||
export { compile } from './compile'
|
export { compile } from './compile'
|
||||||
|
export * from './ir'
|
||||||
|
|
|
@ -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>
|
|
@ -1,85 +1,21 @@
|
||||||
import {
|
import type {
|
||||||
type NodeTypes,
|
NodeTypes,
|
||||||
RootNode,
|
RootNode,
|
||||||
Node,
|
Node,
|
||||||
TemplateChildNode,
|
TemplateChildNode,
|
||||||
ElementNode,
|
ElementNode,
|
||||||
AttributeNode,
|
AttributeNode,
|
||||||
SourceLocation,
|
|
||||||
InterpolationNode,
|
InterpolationNode,
|
||||||
TransformOptions,
|
TransformOptions,
|
||||||
DirectiveNode,
|
DirectiveNode,
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
|
import {
|
||||||
export const enum IRNodeTypes {
|
type DynamicChildren,
|
||||||
ROOT,
|
type EffectNode,
|
||||||
TEMPLATE_GENERATOR,
|
type OprationNode,
|
||||||
SET_PROP,
|
type RootIRNode,
|
||||||
SET_TEXT,
|
IRNodeTypes,
|
||||||
SET_EVENT,
|
} from './ir'
|
||||||
|
|
||||||
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>
|
|
||||||
|
|
||||||
export interface TransformContext<T extends Node = Node> {
|
export interface TransformContext<T extends Node = Node> {
|
||||||
node: T
|
node: T
|
||||||
|
@ -87,15 +23,17 @@ export interface TransformContext<T extends Node = Node> {
|
||||||
root: TransformContext<RootNode>
|
root: TransformContext<RootNode>
|
||||||
index: number
|
index: number
|
||||||
options: TransformOptions
|
options: TransformOptions
|
||||||
ir: RootIRNode
|
// ir: RootIRNode
|
||||||
template: string
|
template: string
|
||||||
children: DynamicChildren
|
children: DynamicChildren
|
||||||
store: boolean
|
store: boolean
|
||||||
ghost: boolean
|
ghost: boolean
|
||||||
|
|
||||||
getElementId(): number
|
getElementId(): number
|
||||||
registerEffect(expr: string, effectNode: EffectNode): void
|
|
||||||
registerTemplate(): number
|
registerTemplate(): number
|
||||||
|
registerEffect(expr: string, effectNode: EffectNode): void
|
||||||
|
registerOpration(...oprations: OprationNode[]): void
|
||||||
|
helper(name: string): string
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRootContext(
|
function createRootContext(
|
||||||
|
@ -104,7 +42,7 @@ function createRootContext(
|
||||||
options: TransformOptions,
|
options: TransformOptions,
|
||||||
): TransformContext<RootNode> {
|
): TransformContext<RootNode> {
|
||||||
let i = 0
|
let i = 0
|
||||||
const { effect: bindings } = ir
|
const { effect, opration, helpers, vaporHelpers } = ir
|
||||||
|
|
||||||
const ctx: TransformContext<RootNode> = {
|
const ctx: TransformContext<RootNode> = {
|
||||||
node,
|
node,
|
||||||
|
@ -112,15 +50,14 @@ function createRootContext(
|
||||||
index: 0,
|
index: 0,
|
||||||
root: undefined as any, // set later
|
root: undefined as any, // set later
|
||||||
options,
|
options,
|
||||||
ir,
|
|
||||||
children: {},
|
children: {},
|
||||||
store: false,
|
store: false,
|
||||||
ghost: false,
|
ghost: false,
|
||||||
|
|
||||||
getElementId: () => i++,
|
getElementId: () => i++,
|
||||||
registerEffect(expr, effectNode) {
|
registerEffect(expr, effectNode) {
|
||||||
if (!bindings[expr]) bindings[expr] = []
|
if (!effect[expr]) effect[expr] = []
|
||||||
bindings[expr].push(effectNode)
|
effect[expr].push(effectNode)
|
||||||
},
|
},
|
||||||
|
|
||||||
template: '',
|
template: '',
|
||||||
|
@ -137,6 +74,14 @@ function createRootContext(
|
||||||
})
|
})
|
||||||
return ir.template.length - 1
|
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
|
ctx.root = ctx
|
||||||
return ctx
|
return ctx
|
||||||
|
@ -178,12 +123,6 @@ export function transform(
|
||||||
root: RootNode,
|
root: RootNode,
|
||||||
options: TransformOptions = {},
|
options: TransformOptions = {},
|
||||||
): RootIRNode {
|
): RootIRNode {
|
||||||
// {
|
|
||||||
// type: IRNodeTypes.TEMPLATE_GENERATOR,
|
|
||||||
// template,
|
|
||||||
// loc: root.loc
|
|
||||||
// }
|
|
||||||
|
|
||||||
const ir: RootIRNode = {
|
const ir: RootIRNode = {
|
||||||
type: IRNodeTypes.ROOT,
|
type: IRNodeTypes.ROOT,
|
||||||
loc: root.loc,
|
loc: root.loc,
|
||||||
|
@ -191,7 +130,8 @@ export function transform(
|
||||||
children: {},
|
children: {},
|
||||||
effect: Object.create(null),
|
effect: Object.create(null),
|
||||||
opration: [],
|
opration: [],
|
||||||
helpers: new Set(['template']),
|
helpers: new Set([]),
|
||||||
|
vaporHelpers: new Set([]),
|
||||||
}
|
}
|
||||||
const ctx = createRootContext(ir, root, options)
|
const ctx = createRootContext(ir, root, options)
|
||||||
transformChildren(ctx, true)
|
transformChildren(ctx, true)
|
||||||
|
@ -303,7 +243,7 @@ function transformInterpolation(
|
||||||
anchor = isFirst ? 'first' : 'last'
|
anchor = isFirst ? 'first' : 'last'
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.ir.opration.push(
|
ctx.registerOpration(
|
||||||
{
|
{
|
||||||
type: IRNodeTypes.TEXT_NODE,
|
type: IRNodeTypes.TEXT_NODE,
|
||||||
loc: node.loc,
|
loc: node.loc,
|
||||||
|
@ -379,6 +319,7 @@ function transformProp(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: reference packages/compiler-core/src/transforms/transformExpression.ts
|
||||||
function processExpression(ctx: TransformContext, expr: string) {
|
function processExpression(ctx: TransformContext, expr: string) {
|
||||||
if (ctx.options.bindingMetadata?.[expr] === 'setup-ref') {
|
if (ctx.options.bindingMetadata?.[expr] === 'setup-ref') {
|
||||||
expr += '.value'
|
expr += '.value'
|
||||||
|
|
Loading…
Reference in New Issue