From: 三咲智子 Kevin Deng Date: Tue, 30 Jan 2024 11:35:29 +0000 (+0800) Subject: refactor(compiler-vapor): simplify codegen context X-Git-Tag: v3.6.0-alpha.1~16^2~632 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d942be14f245b5d54db28ffd8b6c1cacfb819ee8;p=thirdparty%2Fvuejs%2Fcore.git refactor(compiler-vapor): simplify codegen context --- diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index e629138617..240cc73474 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -18,7 +18,7 @@ import { type WithDirectiveIRNode, } from './ir' import { SourceMapGenerator } from 'source-map-js' -import { isString } from '@vue/shared' +import { extend, isString } from '@vue/shared' import type { ParserPlugin } from '@babel/parser' import { genSetProp } from './generators/prop' import { genCreateTextNode, genSetText } from './generators/text' @@ -38,7 +38,9 @@ interface CodegenOptions extends BaseCodegenOptions { // @ts-expect-error function checkNever(x: never): never {} -export interface CodegenContext extends Required { +export interface CodegenContext { + options: Required + source: string code: string line: number @@ -53,8 +55,8 @@ export interface CodegenContext extends Required { loc?: SourceLocation, name?: string, ): void - pushNewline( - code: string, + newline( + code?: string, newlineIndex?: number, loc?: SourceLocation, name?: string, @@ -63,9 +65,8 @@ export interface CodegenContext extends Required { codes: [left: string, right: string, segment?: string], ...fn: Array void)> ): void - pushFnCall(name: string, ...args: Array void)>): void + pushCall(name: string, ...args: Array void)>): void withIndent(fn: () => void): void - newline(): void helpers: Set vaporHelpers: Set @@ -73,47 +74,33 @@ export interface CodegenContext extends Required { vaporHelper(name: string): string } -function createCodegenContext( - ir: RootIRNode, - { - mode = 'function', - prefixIdentifiers = mode === 'module', - sourceMap = false, - filename = `template.vue.html`, - scopeId = null, - optimizeImports = false, - runtimeGlobalName = `Vue`, - runtimeModuleName = `vue`, - ssrRuntimeModuleName = 'vue/server-renderer', - ssr = false, - isTS = false, - inSSR = false, - inline = false, - bindingMetadata = {}, - expressionPlugins = [], - }: CodegenOptions, -) { +function createCodegenContext(ir: RootIRNode, options: CodegenOptions) { const helpers = new Set([]) const vaporHelpers = new Set([]) const context: CodegenContext = { - mode, - prefixIdentifiers, - sourceMap, - filename, - scopeId, - optimizeImports, - runtimeGlobalName, - runtimeModuleName, - ssrRuntimeModuleName, - ssr, - isTS, - inSSR, - bindingMetadata, - expressionPlugins, - inline, + options: extend( + { + mode: 'function', + prefixIdentifiers: options.mode === 'module', + sourceMap: false, + filename: `template.vue.html`, + scopeId: null, + optimizeImports: false, + runtimeGlobalName: `Vue`, + runtimeModuleName: `vue`, + ssrRuntimeModuleName: 'vue/server-renderer', + ssr: false, + isTS: false, + inSSR: false, + inline: false, + bindingMetadata: {}, + expressionPlugins: [], + }, + options, + ), source: ir.source, - code: ``, + code: '', column: 1, line: 1, offset: 0, @@ -129,6 +116,7 @@ function createCodegenContext( vaporHelpers.add(name) return `_${name}` }, + push(code, newlineIndex = NewlineType.None, loc, name) { context.code += code if (!__BROWSER__ && context.map) { @@ -174,23 +162,21 @@ function createCodegenContext( } } }, - pushNewline(code, newlineIndex, node) { - context.newline() - context.push(code, newlineIndex, node) + newline(code, newlineIndex, node) { + context.push(`\n${` `.repeat(context.indentLevel)}`, NewlineType.Start) + code && context.push(code, newlineIndex, node) }, pushMulti([left, right, seg], ...fns) { fns = fns.filter(Boolean) context.push(left) - for (let i = 0; i < fns.length; i++) { - const fn = fns[i] as string | (() => void) - + for (const [i, fn] of fns.entries()) { if (isString(fn)) context.push(fn) - else fn() + else (fn as () => void)() if (seg && i < fns.length - 1) context.push(seg) } context.push(right) }, - pushFnCall(name, ...args) { + pushCall(name, ...args) { context.push(name) context.pushMulti(['(', ')', ', '], ...args) }, @@ -199,11 +185,10 @@ function createCodegenContext( fn() --context.indentLevel }, - newline() { - context.push(`\n${` `.repeat(context.indentLevel)}`, NewlineType.Start) - }, } + const filename = context.options.filename + function addMapping(loc: Position, name: string | null = null) { // we use the private property to directly add the mapping // because the addMapping() implementation in source-map-js has a bunch of @@ -221,7 +206,7 @@ function createCodegenContext( }) } - if (!__BROWSER__ && sourceMap) { + if (!__BROWSER__ && context.options.sourceMap) { // lazy require source-map implementation, only in non-browser builds context.map = new SourceMapGenerator() context.map.setSourceContent(filename, context.source) @@ -243,15 +228,7 @@ export function generate( options: CodegenOptions = {}, ): VaporCodegenResult { const ctx = createCodegenContext(ir, options) - const { - push, - pushNewline, - withIndent, - newline, - helpers, - vaporHelper, - vaporHelpers, - } = ctx + const { push, withIndent, newline, helpers, vaporHelper, vaporHelpers } = ctx const functionName = 'render' const isSetupInlined = !!options.inline @@ -260,21 +237,21 @@ export function generate( } else { // placeholder for preamble newline() - pushNewline(`export function ${functionName}(_ctx) {`) + newline(`export function ${functionName}(_ctx) {`) } withIndent(() => { ir.template.forEach((template, i) => { if (template.type === IRNodeTypes.TEMPLATE_FACTORY) { // TODO source map? - pushNewline( + newline( `const t${i} = ${vaporHelper('template')}(${JSON.stringify( template.template, )})`, ) } else { // fragment - pushNewline(`const t${i} = ${vaporHelper('fragment')}()`) + newline(`const t${i} = ${vaporHelper('fragment')}()`) } }) @@ -380,14 +357,12 @@ export function genBlockFunctionContent( ir: BlockFunctionIRNode | RootIRNode, ctx: CodegenContext, ) { - const { pushNewline, withIndent, vaporHelper } = ctx - pushNewline(`const n${ir.dynamic.id} = t${ir.templateIndex}()`) + const { newline, withIndent, vaporHelper } = ctx + newline(`const n${ir.dynamic.id} = t${ir.templateIndex}()`) const children = genChildren(ir.dynamic.children) if (children) { - pushNewline( - `const ${children} = ${vaporHelper('children')}(n${ir.dynamic.id})`, - ) + newline(`const ${children} = ${vaporHelper('children')}(n${ir.dynamic.id})`) } const directiveOps = ir.operation.filter( @@ -403,16 +378,16 @@ export function genBlockFunctionContent( } for (const { operations } of ir.effect) { - pushNewline(`${vaporHelper('renderEffect')}(() => {`) + newline(`${vaporHelper('renderEffect')}(() => {`) withIndent(() => { for (const operation of operations) { genOperation(operation, ctx) } }) - pushNewline('})') + newline('})') } - pushNewline(`return n${ir.dynamic.id}`) + newline(`return n${ir.dynamic.id}`) } function groupDirective(ops: WithDirectiveIRNode[]): WithDirectiveIRNode[][] { diff --git a/packages/compiler-vapor/src/generators/directive.ts b/packages/compiler-vapor/src/generators/directive.ts index f3a1af67a9..2c9d9143c7 100644 --- a/packages/compiler-vapor/src/generators/directive.ts +++ b/packages/compiler-vapor/src/generators/directive.ts @@ -8,11 +8,17 @@ export function genWithDirective( opers: WithDirectiveIRNode[], context: CodegenContext, ) { - const { push, newline, pushFnCall, pushMulti, vaporHelper, bindingMetadata } = - context + const { + push, + newline, + pushCall, + pushMulti, + vaporHelper, + options: { bindingMetadata }, + } = context newline() - pushFnCall( + pushCall( vaporHelper('withDirectives'), // 1st arg: node `n${opers[0].element}`, diff --git a/packages/compiler-vapor/src/generators/dom.ts b/packages/compiler-vapor/src/generators/dom.ts index dcc9324060..17a3e27cc7 100644 --- a/packages/compiler-vapor/src/generators/dom.ts +++ b/packages/compiler-vapor/src/generators/dom.ts @@ -5,37 +5,35 @@ import type { PrependNodeIRNode, } from '../ir' -export function genInsertNode(oper: InsertNodeIRNode, context: CodegenContext) { - const { newline, pushFnCall, vaporHelper } = context +export function genInsertNode( + oper: InsertNodeIRNode, + { newline, pushCall, vaporHelper }: CodegenContext, +) { const elements = ([] as number[]).concat(oper.element) let element = elements.map(el => `n${el}`).join(', ') if (elements.length > 1) element = `[${element}]` newline() - pushFnCall( - vaporHelper('insert'), - element, - `n${oper.parent}`, - `n${oper.anchor}`, - ) + pushCall(vaporHelper('insert'), element, `n${oper.parent}`, `n${oper.anchor}`) } export function genPrependNode( oper: PrependNodeIRNode, - context: CodegenContext, + { newline, pushCall, vaporHelper }: CodegenContext, ) { - const { newline, pushFnCall, vaporHelper } = context newline() - pushFnCall( + pushCall( vaporHelper('prepend'), `n${oper.parent}`, oper.elements.map(el => `n${el}`).join(', '), ) } -export function genAppendNode(oper: AppendNodeIRNode, context: CodegenContext) { - const { newline, pushFnCall, vaporHelper } = context +export function genAppendNode( + oper: AppendNodeIRNode, + { newline, pushCall, vaporHelper }: CodegenContext, +) { newline() - pushFnCall( + pushCall( vaporHelper('append'), `n${oper.parent}`, oper.elements.map(el => `n${el}`).join(', '), diff --git a/packages/compiler-vapor/src/generators/event.ts b/packages/compiler-vapor/src/generators/event.ts index bec6528e94..f369315d99 100644 --- a/packages/compiler-vapor/src/generators/event.ts +++ b/packages/compiler-vapor/src/generators/event.ts @@ -8,11 +8,18 @@ const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*(:[^=]+)?=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/ export function genSetEvent(oper: SetEventIRNode, context: CodegenContext) { - const { vaporHelper, push, newline, pushMulti, pushFnCall } = context + const { + vaporHelper, + push, + newline, + pushMulti, + pushCall, + options: ctxOptions, + } = context const { keys, nonKeys, options } = oper.modifiers newline() - pushFnCall( + pushCall( vaporHelper('on'), // 1st arg: event name () => push(`n${oper.element}`), @@ -44,7 +51,7 @@ export function genSetEvent(oper: SetEventIRNode, context: CodegenContext) { ;(keys.length ? pushWithKeys : pushNoop)(() => (nonKeys.length ? pushWithModifiers : pushNoop)(() => { - genEventHandler(context) + genEventHandler() }), ) }, @@ -53,10 +60,10 @@ export function genSetEvent(oper: SetEventIRNode, context: CodegenContext) { (() => push(`{ ${options.map(v => `${v}: true`).join(', ')} }`)), ) - function genEventHandler(context: CodegenContext) { + function genEventHandler() { const exp = oper.value if (exp && exp.content.trim()) { - const isMemberExp = isMemberExpression(exp.content, context) + const isMemberExp = isMemberExpression(exp.content, ctxOptions) const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content)) const hasMultipleStatements = exp.content.includes(`;`) diff --git a/packages/compiler-vapor/src/generators/expression.ts b/packages/compiler-vapor/src/generators/expression.ts index d6ae21f518..90019290ec 100644 --- a/packages/compiler-vapor/src/generators/expression.ts +++ b/packages/compiler-vapor/src/generators/expression.ts @@ -15,7 +15,10 @@ export function genExpression( context: CodegenContext, knownIds: Record = Object.create(null), ): void { - const { push } = context + const { + push, + options: { prefixIdentifiers }, + } = context if (isString(node)) return push(node) const { content: rawExpr, ast, isStatic, loc } = node @@ -24,7 +27,7 @@ export function genExpression( } if ( __BROWSER__ || - !context.prefixIdentifiers || + !prefixIdentifiers || !node.content.trim() || // there was a parsing error ast === false || @@ -81,9 +84,10 @@ const isLiteralWhitelisted = /*#__PURE__*/ makeMap('true,false,null,this') function genIdentifier( id: string, - { inline, bindingMetadata, vaporHelper, push }: CodegenContext, + { options, vaporHelper, push }: CodegenContext, loc?: SourceLocation, ): void { + const { inline, bindingMetadata } = options let name: string | undefined = id if (inline) { switch (bindingMetadata[id]) { diff --git a/packages/compiler-vapor/src/generators/html.ts b/packages/compiler-vapor/src/generators/html.ts index 1a26f4bf2d..3ca7c56956 100644 --- a/packages/compiler-vapor/src/generators/html.ts +++ b/packages/compiler-vapor/src/generators/html.ts @@ -3,9 +3,9 @@ import type { SetHtmlIRNode } from '../ir' import { genExpression } from './expression' export function genSetHtml(oper: SetHtmlIRNode, context: CodegenContext) { - const { newline, pushFnCall, vaporHelper } = context + const { newline, pushCall, vaporHelper } = context newline() - pushFnCall(vaporHelper('setHtml'), `n${oper.element}`, () => + pushCall(vaporHelper('setHtml'), `n${oper.element}`, () => genExpression(oper.value, context), ) } diff --git a/packages/compiler-vapor/src/generators/if.ts b/packages/compiler-vapor/src/generators/if.ts index 0019273f82..72b2b09919 100644 --- a/packages/compiler-vapor/src/generators/if.ts +++ b/packages/compiler-vapor/src/generators/if.ts @@ -7,7 +7,7 @@ export function genIf( context: CodegenContext, isNested = false, ) { - const { pushFnCall, vaporHelper, pushNewline, push } = context + const { pushCall, vaporHelper, newline, push } = context const { condition, positive, negative } = oper let positiveArg = () => genBlockFunction(positive, context) @@ -24,8 +24,8 @@ export function genIf( } } - if (!isNested) pushNewline(`const n${oper.id} = `) - pushFnCall( + if (!isNested) newline(`const n${oper.id} = `) + pushCall( vaporHelper('createIf'), () => { push('() => (') @@ -38,11 +38,11 @@ export function genIf( } function genBlockFunction(oper: BlockFunctionIRNode, context: CodegenContext) { - const { pushNewline, push, withIndent } = context + const { newline, push, withIndent } = context push('() => {') withIndent(() => { genBlockFunctionContent(oper, context) }) - pushNewline('}') + newline('}') } diff --git a/packages/compiler-vapor/src/generators/modelValue.ts b/packages/compiler-vapor/src/generators/modelValue.ts index 1cc76246d6..f596cb2c9a 100644 --- a/packages/compiler-vapor/src/generators/modelValue.ts +++ b/packages/compiler-vapor/src/generators/modelValue.ts @@ -7,10 +7,16 @@ export function genSetModelValue( oper: SetModelValueIRNode, context: CodegenContext, ) { - const { vaporHelper, push, newline, pushFnCall } = context + const { + vaporHelper, + push, + newline, + pushCall, + options: { isTS }, + } = context newline() - pushFnCall( + pushCall( vaporHelper('on'), // 1st arg: event name () => push(`n${oper.element}`), @@ -26,7 +32,7 @@ export function genSetModelValue( }, // 3rd arg: event handler () => { - push((context.isTS ? `($event: any)` : `$event`) + ' => ((') + push((isTS ? `($event: any)` : `$event`) + ' => ((') // TODO handle not a ref genExpression(oper.value, context) push(') = $event)') diff --git a/packages/compiler-vapor/src/generators/prop.ts b/packages/compiler-vapor/src/generators/prop.ts index 7fb40fedf7..204c2f2c5b 100644 --- a/packages/compiler-vapor/src/generators/prop.ts +++ b/packages/compiler-vapor/src/generators/prop.ts @@ -4,7 +4,7 @@ import { genExpression } from './expression' import { isString } from '@vue/shared' export function genSetProp(oper: SetPropIRNode, context: CodegenContext) { - const { pushFnCall, pushMulti, newline, vaporHelper, helper } = context + const { pushCall, pushMulti, newline, vaporHelper, helper } = context newline() @@ -27,7 +27,7 @@ export function genSetProp(oper: SetPropIRNode, context: CodegenContext) { } if (helperName) { - pushFnCall( + pushCall( vaporHelper(helperName), element, omitKey @@ -35,7 +35,7 @@ export function genSetProp(oper: SetPropIRNode, context: CodegenContext) { : () => { const expr = () => genExpression(oper.key, context) if (oper.runtimeCamelize) { - pushFnCall(helper('camelize'), expr) + pushCall(helper('camelize'), expr) } else { expr() } @@ -46,13 +46,13 @@ export function genSetProp(oper: SetPropIRNode, context: CodegenContext) { } } - pushFnCall( + pushCall( vaporHelper('setDynamicProp'), element, // 2. key name () => { if (oper.runtimeCamelize) { - pushFnCall(helper('camelize'), () => genExpression(oper.key, context)) + pushCall(helper('camelize'), () => genExpression(oper.key, context)) } else if (oper.modifier) { pushMulti([`\`${oper.modifier}\${`, `}\``], () => genExpression(oper.key, context), diff --git a/packages/compiler-vapor/src/generators/ref.ts b/packages/compiler-vapor/src/generators/ref.ts index 78b8024d78..bcd0c0880d 100644 --- a/packages/compiler-vapor/src/generators/ref.ts +++ b/packages/compiler-vapor/src/generators/ref.ts @@ -3,9 +3,9 @@ import type { SetRefIRNode } from '../ir' import { genExpression } from './expression' export function genSetRef(oper: SetRefIRNode, context: CodegenContext) { - const { newline, pushFnCall, vaporHelper } = context + const { newline, pushCall, vaporHelper } = context newline() - pushFnCall(vaporHelper('setRef'), `n${oper.element}`, () => + pushCall(vaporHelper('setRef'), `n${oper.element}`, () => genExpression(oper.value, context), ) } diff --git a/packages/compiler-vapor/src/generators/text.ts b/packages/compiler-vapor/src/generators/text.ts index 4c6cc02cf2..7752acd971 100644 --- a/packages/compiler-vapor/src/generators/text.ts +++ b/packages/compiler-vapor/src/generators/text.ts @@ -3,9 +3,9 @@ import type { CreateTextNodeIRNode, SetTextIRNode } from '../ir' import { genExpression } from './expression' export function genSetText(oper: SetTextIRNode, context: CodegenContext) { - const { pushFnCall, newline, vaporHelper } = context + const { pushCall, newline, vaporHelper } = context newline() - pushFnCall(vaporHelper('setText'), `n${oper.element}`, () => + pushCall(vaporHelper('setText'), `n${oper.element}`, () => genExpression(oper.value, context), ) } @@ -14,9 +14,9 @@ export function genCreateTextNode( oper: CreateTextNodeIRNode, context: CodegenContext, ) { - const { pushNewline, pushFnCall, vaporHelper } = context - pushNewline(`const n${oper.id} = `) - pushFnCall(vaporHelper('createTextNode'), () => + const { newline, pushCall, vaporHelper } = context + newline(`const n${oper.id} = `) + pushCall(vaporHelper('createTextNode'), () => genExpression(oper.value, context), ) }