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
+ {{ a }}`,
+ undefined,
+ {
+ filename: 'FooBar.vue'
+ }
+ )
+ expect(content).toMatch(`export default {
+ name: 'FooBar'`)
+ assertCode(content)
+ })
+
+ test('do not overwrite manual name (object)', () => {
+ const { content } = compile(
+ `
+
+ {{ a }}`,
+ 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(
+ `
+
+ {{ a }}`,
+ 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,