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'
import {
- CodegenResult,
- CompilerOptions,
- RootNode,
+ type CodegenResult,
+ type CompilerOptions,
+ type RootNode,
baseParse,
} from '@vue/compiler-dom'
import { isString } from '@vue/shared'
-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(
} = {},
): CodegenResult {
let code = ''
- let preamble = `import { watchEffect } from 'vue'
-import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
+ let preamble = ''
- const isSetupInlined = !!options.inline
-
- preamble += ir.template
- .map((template, i) => `const t${i} = template(\`${template.template}\`)\n`)
- .join('')
+ const { helpers, vaporHelpers } = ir
+ if (ir.template.length) {
+ preamble += ir.template
+ .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
}
anchor = `, 0 /* InsertPosition.FIRST */`
}
code += `insert(n${opration.element}, n${opration.parent}${anchor})\n`
+ vaporHelpers.add('insert')
}
break
}
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 += '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 {
}
}
-function genChildrens(children: DynamicChildren) {
+function genChildren(children: DynamicChildren) {
let str = ''
for (const [index, child] of Object.entries(children)) {
str += ` ${index}: [`
str += `n${child.id}`
}
if (Object.keys(child.children).length) {
- str += `, {${genChildrens(child.children)}}`
+ str += `, {${genChildren(child.children)}}`
}
str += '],'
}
export { transform } from './transform'
export { generate } from './generate'
export { compile } from './compile'
+export * from './ir'
--- /dev/null
+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>
-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
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(
options: TransformOptions,
): TransformContext<RootNode> {
let i = 0
- const { effect: bindings } = ir
+ const { effect, opration, helpers, vaporHelpers } = ir
const ctx: TransformContext<RootNode> = {
node,
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: '',
})
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
root: RootNode,
options: TransformOptions = {},
): RootIRNode {
- // {
- // type: IRNodeTypes.TEMPLATE_GENERATOR,
- // template,
- // loc: root.loc
- // }
-
const ir: RootIRNode = {
type: IRNodeTypes.ROOT,
loc: root.loc,
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)
anchor = isFirst ? 'first' : 'last'
}
- ctx.ir.opration.push(
+ ctx.registerOpration(
{
type: IRNodeTypes.TEXT_NODE,
loc: node.loc,
}
}
+// TODO: reference packages/compiler-core/src/transforms/transformExpression.ts
function processExpression(ctx: TransformContext, expr: string) {
if (ctx.options.bindingMetadata?.[expr] === 'setup-ref') {
expr += '.value'