From: ygj6 <7699524+ygj6@users.noreply.github.com> Date: Tue, 10 May 2022 01:16:28 +0000 (+0800) Subject: fix(compiler-sfc): automatically infer component name from filename when using script... X-Git-Tag: v3.2.34-beta.1~93 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16939241b0f64cefea254b024a9b5a25caea93d9;p=thirdparty%2Fvuejs%2Fcore.git fix(compiler-sfc): automatically infer component name from filename when using script setup (#4997) close #4993 --- diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap index de223bf91d..cbe274ef9e 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap @@ -1,5 +1,48 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`SFC analyze + `, + undefined, + { + filename: 'FooBar.vue' + } + ) + expect(content).toMatch(`export default { + name: 'FooBar'`) + assertCode(content) + }) + + test('do not overwrite manual name (object)', () => { + const { content } = compile( + ` + + `, + undefined, + { + filename: 'FooBar.vue' + } + ) + expect(content).not.toMatch(`name: 'FooBar'`) + expect(content).toMatch(`name: 'Baz'`) + assertCode(content) + }) + + test('do not overwrite manual name (call)', () => { + const { content } = compile( + ` + + `, + undefined, + { + filename: 'FooBar.vue' + } + ) + expect(content).not.toMatch(`name: 'FooBar'`) + expect(content).toMatch(`name: 'Baz'`) + assertCode(content) + }) + }) }) diff --git a/packages/compiler-sfc/__tests__/utils.ts b/packages/compiler-sfc/__tests__/utils.ts index 206ff3681d..ffa12652c8 100644 --- a/packages/compiler-sfc/__tests__/utils.ts +++ b/packages/compiler-sfc/__tests__/utils.ts @@ -1,13 +1,19 @@ -import { parse, SFCScriptCompileOptions, compileScript } from '../src' +import { + parse, + SFCScriptCompileOptions, + compileScript, + SFCParseOptions +} from '../src' import { parse as babelParse } from '@babel/parser' export const mockId = 'xxxxxxxx' export function compileSFCScript( src: string, - options?: Partial + options?: Partial, + parseOptions?: SFCParseOptions ) { - const { descriptor } = parse(src) + const { descriptor } = parse(src, parseOptions) return compileScript(descriptor, { ...options, id: mockId diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index 3a3a260332..7c84f29b3b 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -11,7 +11,7 @@ import { isFunctionType, walkIdentifiers } from '@vue/compiler-dom' -import { SFCDescriptor, SFCScriptBlock } from './parse' +import { DEFAULT_FILENAME, SFCDescriptor, SFCScriptBlock } from './parse' import { parse as _parse, ParserOptions, ParserPlugin } from '@babel/parser' import { camelize, capitalize, generateCodeFrame, makeMap } from '@vue/shared' import { @@ -263,6 +263,7 @@ export function compileScript( let hasDefinePropsCall = false let hasDefineEmitCall = false let hasDefineExposeCall = false + let hasDefaultExportName = false let propsRuntimeDecl: Node | undefined let propsRuntimeDefaults: ObjectExpression | undefined let propsDestructureDecl: Node | undefined @@ -811,6 +812,25 @@ export function compileScript( } else if (node.type === 'ExportDefaultDeclaration') { // export default defaultExport = node + + // check if user has manually specified `name` option in export default + // if yes, skip infer later + let optionProperties + if (defaultExport.declaration.type === 'ObjectExpression') { + optionProperties = defaultExport.declaration.properties + } else if ( + defaultExport.declaration.type === 'CallExpression' && + defaultExport.declaration.arguments[0].type === 'ObjectExpression' + ) { + optionProperties = defaultExport.declaration.arguments[0].properties + } + hasDefaultExportName = !!optionProperties?.some( + s => + s.type === 'ObjectProperty' && + s.key.type === 'Identifier' && + s.key.name === 'name' + ) + // export default { ... } --> const __default__ = { ... } const start = node.start! + scriptStartOffset! const end = node.declaration.start! + scriptStartOffset! @@ -1364,6 +1384,12 @@ export function compileScript( // 11. finalize default export let runtimeOptions = `` + if (!hasDefaultExportName && filename && filename !== DEFAULT_FILENAME) { + const match = filename.match(/([^/\\]+)\.\w+$/) + if (match) { + runtimeOptions += `\n name: '${match[1]}',` + } + } if (hasInlinedSsrRenderFn) { runtimeOptions += `\n __ssrInlineRender: true,` } diff --git a/packages/compiler-sfc/src/parse.ts b/packages/compiler-sfc/src/parse.ts index ed44e53682..cc7873c29a 100644 --- a/packages/compiler-sfc/src/parse.ts +++ b/packages/compiler-sfc/src/parse.ts @@ -13,6 +13,8 @@ import { parseCssVars } from './cssVars' import { createCache } from './cache' import { hmrShouldReload, ImportBinding } from './compileScript' +export const DEFAULT_FILENAME = 'anonymous.vue' + export interface SFCParseOptions { filename?: string sourceMap?: boolean @@ -95,7 +97,7 @@ export function parse( source: string, { sourceMap = true, - filename = 'anonymous.vue', + filename = DEFAULT_FILENAME, sourceRoot = '', pad = false, ignoreEmpty = true,