From: 三咲智子 Kevin Deng Date: Sat, 27 Jan 2024 13:42:52 +0000 (+0800) Subject: refactor(compiler-vapor): codegen result X-Git-Tag: v3.6.0-alpha.1~16^2~654 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=164fd90df400fd1ce8eca9b31cff29a303a54132;p=thirdparty%2Fvuejs%2Fcore.git refactor(compiler-vapor): codegen result --- diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 821c85d4cf..81b512d892 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -62,11 +62,17 @@ const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}` type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode -export interface CodegenResult { +export interface BaseCodegenResult { code: string preamble: string - ast: RootNode + ast: unknown map?: RawSourceMap + helpers?: Set | Set +} + +export interface CodegenResult extends BaseCodegenResult { + ast: RootNode + helpers: Set } export enum NewlineType { @@ -359,6 +365,7 @@ export function generate( code: context.code, preamble: isSetupInlined ? preambleContext.code : ``, map: context.map ? context.map.toJSON() : undefined, + helpers: ast.helpers, } } diff --git a/packages/compiler-core/src/index.ts b/packages/compiler-core/src/index.ts index 4fdcd4052c..aff69dbc74 100644 --- a/packages/compiler-core/src/index.ts +++ b/packages/compiler-core/src/index.ts @@ -26,6 +26,7 @@ export { NewlineType, type CodegenContext, type CodegenResult, + type BaseCodegenResult, } from './codegen' export { ErrorCodes, diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index 3d1667e6cf..522d2c204f 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -846,7 +846,7 @@ export function compileScript( } // inline render function mode - we are going to compile the template and // inline it right here - const { code, ast, preamble, tips, errors } = compileTemplate({ + const { code, preamble, tips, errors, helpers } = compileTemplate({ filename, ast: sfc.template.ast, source: sfc.template.content, @@ -891,7 +891,7 @@ export function compileScript( // avoid duplicated unref import // as this may get injected by the render function preamble OR the // css vars codegen - if (ast && ast.helpers.has(UNREF)) { + if (helpers && helpers.has(UNREF)) { ctx.helperImports.delete('unref') } returned = code diff --git a/packages/compiler-sfc/src/compileTemplate.ts b/packages/compiler-sfc/src/compileTemplate.ts index 65e9bd5011..957269e011 100644 --- a/packages/compiler-sfc/src/compileTemplate.ts +++ b/packages/compiler-sfc/src/compileTemplate.ts @@ -1,5 +1,5 @@ import { - type CodegenResult, + type BaseCodegenResult, type CompilerError, type CompilerOptions, type ElementNode, @@ -34,18 +34,22 @@ import { warnOnce } from './warn' import { genCssVarsFromList } from './style/cssVars' export interface TemplateCompiler { - compile(source: string | RootNode, options: CompilerOptions): CodegenResult + compile( + source: string | RootNode, + options: CompilerOptions, + ): BaseCodegenResult parse(template: string, options: ParserOptions): RootNode } export interface SFCTemplateCompileResults { code: string - ast?: RootNode + ast?: unknown preamble?: string source: string tips: string[] errors: (string | CompilerError)[] map?: RawSourceMap + helpers?: Set } export interface SFCTemplateCompileOptions { @@ -238,25 +242,30 @@ function doCompileTemplate({ inAST = createRoot(template.children, inAST.source) } - let { code, ast, preamble, map } = compiler.compile(inAST || source, { - mode: 'module', - prefixIdentifiers: true, - hoistStatic: true, - cacheHandlers: true, - ssrCssVars: - ssr && ssrCssVars && ssrCssVars.length - ? genCssVarsFromList(ssrCssVars, shortId, isProd, true) - : '', - scopeId: scoped ? longId : undefined, - slotted, - sourceMap: true, - ...compilerOptions, - hmr: !isProd, - nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []), - filename, - onError: e => errors.push(e), - onWarn: w => warnings.push(w), - }) + let { code, ast, preamble, map, helpers } = compiler.compile( + inAST || source, + { + mode: 'module', + prefixIdentifiers: true, + hoistStatic: true, + cacheHandlers: true, + ssrCssVars: + ssr && ssrCssVars && ssrCssVars.length + ? genCssVarsFromList(ssrCssVars, shortId, isProd, true) + : '', + scopeId: scoped ? longId : undefined, + slotted, + sourceMap: true, + ...compilerOptions, + hmr: !isProd, + nodeTransforms: nodeTransforms.concat( + compilerOptions.nodeTransforms || [], + ), + filename, + onError: e => errors.push(e), + onWarn: w => warnings.push(w), + }, + ) // inMap should be the map produced by ./parse.ts which is a simple line-only // mapping. If it is present, we need to adjust the final map and errors to @@ -282,7 +291,16 @@ function doCompileTemplate({ return msg }) - return { code, ast, preamble, source, errors, tips, map } + return { + code, + ast, + preamble, + source, + errors, + tips, + map, + helpers, + } } function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap { diff --git a/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts b/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts index 8614c141bd..bebc1a8007 100644 --- a/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts @@ -7,20 +7,13 @@ import { import { type CompilerOptions, IRNodeTypes, - type RootIRNode, compile as _compile, generate, transform, } from '../../src' import { getBaseTransformPreset } from '../../src/compile' -function compileWithVHtml( - template: string, - options: CompilerOptions = {}, -): { - ir: RootIRNode - code: string -} { +function compileWithVHtml(template: string, options: CompilerOptions = {}) { const ast = parse(template, { prefixIdentifiers: true, ...options }) const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(true) const ir = transform(ast, { @@ -29,20 +22,26 @@ function compileWithVHtml( prefixIdentifiers: true, ...options, }) - const { code } = generate(ir, { prefixIdentifiers: true, ...options }) - return { ir, code } + const { code, helpers, vaporHelpers } = generate(ir, { + prefixIdentifiers: true, + ...options, + }) + return { ir, code, helpers, vaporHelpers } } describe('v-html', () => { test('should convert v-html to innerHTML', () => { - const { code, ir } = compileWithVHtml(`
`, { - bindingMetadata: { - code: BindingTypes.SETUP_REF, + const { code, ir, helpers, vaporHelpers } = compileWithVHtml( + `
`, + { + bindingMetadata: { + code: BindingTypes.SETUP_REF, + }, }, - }) + ) - expect(ir.vaporHelpers).contains('setHtml') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('setHtml') + expect(helpers.size).toBe(0) expect(ir.operation).toEqual([]) expect(ir.effect).toMatchObject([ @@ -73,12 +72,15 @@ describe('v-html', () => { test('should raise error and ignore children when v-html is present', () => { const onError = vi.fn() - const { code, ir } = compileWithVHtml(`
hello
`, { - onError, - }) + const { code, ir, helpers, vaporHelpers } = compileWithVHtml( + `
hello
`, + { + onError, + }, + ) - expect(ir.vaporHelpers).contains('setHtml') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('setHtml') + expect(helpers.size).toBe(0) // children should have been removed expect(ir.template).toMatchObject([{ template: '
' }]) diff --git a/packages/compiler-vapor/__tests__/transforms/vOn.spec.ts b/packages/compiler-vapor/__tests__/transforms/vOn.spec.ts index 7705e1e183..3b2d0c626f 100644 --- a/packages/compiler-vapor/__tests__/transforms/vOn.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vOn.spec.ts @@ -2,7 +2,6 @@ import { BindingTypes, ErrorCodes, NodeTypes, parse } from '@vue/compiler-dom' import { type CompilerOptions, IRNodeTypes, - type RootIRNode, compile as _compile, generate, transform, @@ -11,13 +10,7 @@ import { import { transformVOn } from '../../src/transforms/vOn' import { transformElement } from '../../src/transforms/transformElement' -function compileWithVOn( - template: string, - options: CompilerOptions = {}, -): { - ir: RootIRNode - code: string -} { +function compileWithVOn(template: string, options: CompilerOptions = {}) { const ast = parse(template, { prefixIdentifiers: true, ...options }) const ir = transform(ast, { nodeTransforms: [transformElement], @@ -27,20 +20,26 @@ function compileWithVOn( prefixIdentifiers: true, ...options, }) - const { code } = generate(ir, { prefixIdentifiers: true, ...options }) - return { ir, code } + const { code, helpers, vaporHelpers } = generate(ir, { + prefixIdentifiers: true, + ...options, + }) + return { ir, code, helpers, vaporHelpers } } describe('v-on', () => { test('simple expression', () => { - const { code, ir } = compileWithVOn(`
`, { - bindingMetadata: { - handleClick: BindingTypes.SETUP_CONST, + const { code, ir, helpers, vaporHelpers } = compileWithVOn( + `
`, + { + bindingMetadata: { + handleClick: BindingTypes.SETUP_CONST, + }, }, - }) + ) - expect(ir.vaporHelpers).contains('on') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('on') + expect(helpers.size).toBe(0) expect(ir.effect).toEqual([]) expect(ir.operation).toMatchObject([ @@ -99,11 +98,13 @@ describe('v-on', () => { }) test('dynamic arg', () => { - const { code, ir } = compileWithVOn(`
`) + const { code, ir, helpers, vaporHelpers } = compileWithVOn( + `
`, + ) - expect(ir.vaporHelpers).contains('on') - expect(ir.vaporHelpers).contains('renderEffect') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('on') + expect(vaporHelpers).contains('renderEffect') + expect(helpers.size).toBe(0) expect(ir.operation).toEqual([]) expect(ir.effect[0].operations[0]).toMatchObject({ @@ -133,13 +134,16 @@ describe('v-on', () => { }) test('dynamic arg with complex exp prefixing', () => { - const { ir, code } = compileWithVOn(`
`, { - prefixIdentifiers: true, - }) + const { ir, code, helpers, vaporHelpers } = compileWithVOn( + `
`, + { + prefixIdentifiers: true, + }, + ) - expect(ir.vaporHelpers).contains('on') - expect(ir.vaporHelpers).contains('renderEffect') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('on') + expect(vaporHelpers).contains('renderEffect') + expect(helpers.size).toBe(0) expect(ir.operation).toEqual([]) expect(ir.effect[0].operations[0]).toMatchObject({ @@ -161,10 +165,11 @@ describe('v-on', () => { }) test('should wrap as function if expression is inline statement', () => { - const { code, ir } = compileWithVOn(`
`) + const { code, ir, helpers, vaporHelpers } = + compileWithVOn(`
`) - expect(ir.vaporHelpers).contains('on') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('on') + expect(helpers.size).toBe(0) expect(ir.effect).toEqual([]) expect(ir.operation).toMatchObject([ @@ -395,10 +400,12 @@ describe('v-on', () => { }) test('case conversion for kebab-case events', () => { - const { ir, code } = compileWithVOn(`
`) + const { ir, code, helpers, vaporHelpers } = compileWithVOn( + `
`, + ) - expect(ir.vaporHelpers).contains('on') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('on') + expect(helpers.size).toBe(0) expect(ir.effect).toEqual([]) expect(ir.operation).toMatchObject([ @@ -443,15 +450,15 @@ describe('v-on', () => { test.todo('vue: prefixed events') test('should support multiple modifiers and event options w/ prefixIdentifiers: true', () => { - const { code, ir } = compileWithVOn( + const { code, ir, vaporHelpers } = compileWithVOn( `
`, { prefixIdentifiers: true, }, ) - expect(ir.vaporHelpers).contains('on') - expect(ir.vaporHelpers).contains('withModifiers') + expect(vaporHelpers).contains('on') + expect(vaporHelpers).contains('withModifiers') expect(ir.operation).toMatchObject([ { diff --git a/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts b/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts index d22297a1d6..d905f3957a 100644 --- a/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts @@ -2,20 +2,13 @@ import { BindingTypes, NodeTypes, parse } from '@vue/compiler-dom' import { type CompilerOptions, IRNodeTypes, - type RootIRNode, compile as _compile, generate as generate, transform, } from '../../src' import { getBaseTransformPreset } from '../../src/compile' -function compileWithOnce( - template: string, - options: CompilerOptions = {}, -): { - ir: RootIRNode - code: string -} { +function compileWithOnce(template: string, options: CompilerOptions = {}) { const ast = parse(template, { prefixIdentifiers: true, ...options }) const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(true) const ir = transform(ast, { @@ -24,13 +17,16 @@ function compileWithOnce( prefixIdentifiers: true, ...options, }) - const { code } = generate(ir, { prefixIdentifiers: true, ...options }) - return { ir, code } + const { code, helpers, vaporHelpers } = generate(ir, { + prefixIdentifiers: true, + ...options, + }) + return { ir, code, helpers, vaporHelpers } } describe('compiler: v-once', () => { test('basic', () => { - const { ir, code } = compileWithOnce( + const { ir, code, helpers } = compileWithOnce( `
{{ msg }} @@ -42,7 +38,7 @@ describe('compiler: v-once', () => { }, }, ) - expect(ir.helpers.size).toBe(0) + expect(helpers.size).toBe(0) expect(ir.effect).toEqual([]) expect(ir.operation).toMatchObject([ @@ -89,9 +85,9 @@ describe('compiler: v-once', () => { }) test('as root node', () => { - const { ir, code } = compileWithOnce(`
`) + const { ir, code, helpers } = compileWithOnce(`
`) - expect(ir.helpers.size).toBe(0) + expect(helpers.size).toBe(0) expect(ir.effect).toEqual([]) expect(ir.operation).toMatchObject([ @@ -116,8 +112,10 @@ describe('compiler: v-once', () => { }) test('on nested plain element', () => { - const { ir, code } = compileWithOnce(`
`) - expect(ir.helpers.size).toBe(0) + const { ir, code, helpers } = compileWithOnce( + `
`, + ) + expect(helpers.size).toBe(0) expect(ir.effect).toEqual([]) expect(ir.operation).toMatchObject([ @@ -145,8 +143,10 @@ describe('compiler: v-once', () => { test.todo('on slot outlet') test('inside v-once', () => { - const { ir, code } = compileWithOnce(`
`) - expect(ir.helpers.size).toBe(0) + const { ir, code, helpers } = compileWithOnce( + `
`, + ) + expect(helpers.size).toBe(0) expect(ir.effect).toMatchObject([]) expect(ir.operation).toMatchObject([]) diff --git a/packages/compiler-vapor/__tests__/transforms/vText.spec.ts b/packages/compiler-vapor/__tests__/transforms/vText.spec.ts index 2e7656671e..d103f3f1fe 100644 --- a/packages/compiler-vapor/__tests__/transforms/vText.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vText.spec.ts @@ -7,20 +7,13 @@ import { import { type CompilerOptions, IRNodeTypes, - type RootIRNode, compile as _compile, generate, transform, } from '../../src' import { getBaseTransformPreset } from '../../src/compile' -function compileWithVText( - template: string, - options: CompilerOptions = {}, -): { - ir: RootIRNode - code: string -} { +function compileWithVText(template: string, options: CompilerOptions = {}) { const ast = parse(template, { prefixIdentifiers: true, ...options }) const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(true) const ir = transform(ast, { @@ -29,20 +22,26 @@ function compileWithVText( prefixIdentifiers: true, ...options, }) - const { code } = generate(ir, { prefixIdentifiers: true, ...options }) - return { ir, code } + const { code, helpers, vaporHelpers } = generate(ir, { + prefixIdentifiers: true, + ...options, + }) + return { ir, code, helpers, vaporHelpers } } describe('v-text', () => { test('should convert v-text to textContent', () => { - const { code, ir } = compileWithVText(`
`, { - bindingMetadata: { - str: BindingTypes.SETUP_REF, + const { code, ir, helpers, vaporHelpers } = compileWithVText( + `
`, + { + bindingMetadata: { + str: BindingTypes.SETUP_REF, + }, }, - }) + ) - expect(ir.vaporHelpers).contains('setText') - expect(ir.helpers.size).toBe(0) + expect(vaporHelpers).contains('setText') + expect(helpers.size).toBe(0) expect(ir.operation).toEqual([]) diff --git a/packages/compiler-vapor/src/compile.ts b/packages/compiler-vapor/src/compile.ts index d271cc1bbc..f25e6f5a46 100644 --- a/packages/compiler-vapor/src/compile.ts +++ b/packages/compiler-vapor/src/compile.ts @@ -1,6 +1,5 @@ import { type CompilerOptions as BaseCompilerOptions, - type CodegenResult, ErrorCodes, type RootNode, createCompilerError, @@ -13,7 +12,7 @@ import { type NodeTransform, transform, } from './transform' -import { generate } from './generate' +import { type VaporCodegenResult, generate } from './generate' import { transformOnce } from './transforms/vOnce' import { transformElement } from './transforms/transformElement' import { transformVHtml } from './transforms/vHtml' @@ -33,7 +32,7 @@ export type CompilerOptions = HackOptions export function compile( source: string | RootNode, options: CompilerOptions = {}, -): CodegenResult { +): VaporCodegenResult { const onError = options.onError || defaultOnError const isModuleMode = options.mode === 'module' /* istanbul ignore if */ diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index 4022c5a6c5..1352fba7d7 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -1,6 +1,6 @@ import { type CodegenOptions as BaseCodegenOptions, - type CodegenResult, + type BaseCodegenResult, NewlineType, type Position, type SourceLocation, @@ -90,7 +90,8 @@ function createCodegenContext( expressionPlugins = [], }: CodegenOptions, ) { - const { helpers, vaporHelpers } = ir + const helpers = new Set([]) + const vaporHelpers = new Set([]) const context: CodegenContext = { mode, prefixIdentifiers, @@ -227,11 +228,17 @@ function createCodegenContext( return context } +export interface VaporCodegenResult extends BaseCodegenResult { + ast: RootIRNode + helpers: Set + vaporHelpers: Set +} + // IR -> JS codegen export function generate( ir: RootIRNode, options: CodegenOptions = {}, -): CodegenResult { +): VaporCodegenResult { const ctx = createCodegenContext(ir, options) const { push, @@ -333,9 +340,11 @@ export function generate( return { code: ctx.code, - ast: ir as any, + ast: ir, preamble, map: ctx.map ? ctx.map.toJSON() : undefined, + helpers, + vaporHelpers, } } diff --git a/packages/compiler-vapor/src/ir.ts b/packages/compiler-vapor/src/ir.ts index 1c2f6ee308..708262d722 100644 --- a/packages/compiler-vapor/src/ir.ts +++ b/packages/compiler-vapor/src/ir.ts @@ -45,8 +45,6 @@ export interface RootIRNode extends BaseIRNode { dynamic: IRDynamicInfo effect: IREffect[] operation: OperationNode[] - helpers: Set - vaporHelpers: Set } export interface TemplateFactoryIRNode extends BaseIRNode { diff --git a/packages/compiler-vapor/src/transform.ts b/packages/compiler-vapor/src/transform.ts index eb230da767..f0f311a7d8 100644 --- a/packages/compiler-vapor/src/transform.ts +++ b/packages/compiler-vapor/src/transform.ts @@ -56,7 +56,30 @@ export interface TransformContext { operation: OperationNode[], ): void registerOperation(...operations: OperationNode[]): void - helper(name: string): string +} + +const defaultOptions = { + filename: '', + prefixIdentifiers: false, + hoistStatic: false, + hmr: false, + cacheHandlers: false, + nodeTransforms: [], + directiveTransforms: {}, + transformHoist: null, + isBuiltInComponent: NOOP, + isCustomElement: NOOP, + expressionPlugins: [], + scopeId: null, + slotted: true, + ssr: false, + inSSR: false, + ssrCssVars: ``, + bindingMetadata: EMPTY_OBJ, + inline: false, + isTS: false, + onError: defaultOnError, + onWarn: defaultOnWarn, } // TODO use class for better perf @@ -66,40 +89,14 @@ function createRootContext( options: TransformOptions = {}, ): TransformContext { let globalId = 0 - const { effect, operation: operation, helpers, vaporHelpers } = ir + const { effect, operation: operation } = ir const ctx: TransformContext = { node, parent: null, index: 0, root: null!, // set later - options: extend( - {}, - { - filename: '', - prefixIdentifiers: false, - hoistStatic: false, - hmr: false, - cacheHandlers: false, - nodeTransforms: [], - directiveTransforms: {}, - transformHoist: null, - isBuiltInComponent: NOOP, - isCustomElement: NOOP, - expressionPlugins: [], - scopeId: null, - slotted: true, - ssr: false, - inSSR: false, - ssrCssVars: ``, - bindingMetadata: EMPTY_OBJ, - inline: false, - isTS: false, - onError: defaultOnError, - onWarn: defaultOnWarn, - }, - options, - ), + options: extend({}, defaultOptions, options), dynamic: ir.dynamic, inVOnce: false, @@ -162,11 +159,6 @@ function createRootContext( registerOperation(...node) { operation.push(...node) }, - // TODO not used yet - helper(name, vapor = true) { - ;(vapor ? vaporHelpers : helpers).add(name) - return name - }, } ctx.root = ctx ctx.reference() @@ -216,8 +208,6 @@ export function transform( }, effect: [], operation: [], - helpers: new Set([]), - vaporHelpers: new Set([]), } const ctx = createRootContext(ir, root, options)