From 44069ab6e8329c085acebd9cac26cbb3fabff00e Mon Sep 17 00:00:00 2001 From: HcySunYang Date: Tue, 6 Apr 2021 16:36:33 +0800 Subject: [PATCH 1/3] refactor: the assets resolution of the script setup --- .../compiler-core/__tests__/codegen.spec.ts | 17 +++++++- .../transforms/transformElement.spec.ts | 22 ++++++---- packages/compiler-core/src/ast.ts | 6 +-- packages/compiler-core/src/codegen.ts | 15 +++++-- packages/compiler-core/src/transform.ts | 18 +++++--- .../src/transforms/transformElement.ts | 33 +++++++++++--- .../__snapshots__/compileScript.spec.ts.snap | 18 +++++--- .../__tests__/compileScript.spec.ts | 22 +++++++--- .../src/transforms/ssrTransformComponent.ts | 2 +- .../__tests__/helpers/resolveAssets.spec.ts | 43 +++++++++++++++++++ .../runtime-core/src/helpers/resolveAssets.ts | 19 +++++--- 11 files changed, 167 insertions(+), 48 deletions(-) diff --git a/packages/compiler-core/__tests__/codegen.spec.ts b/packages/compiler-core/__tests__/codegen.spec.ts index 75001f94aff..a49e6d335b9 100644 --- a/packages/compiler-core/__tests__/codegen.spec.ts +++ b/packages/compiler-core/__tests__/codegen.spec.ts @@ -35,6 +35,7 @@ import { } from '../src/runtimeHelpers' import { createElementWithCodegen, genFlagText } from './testUtils' import { PatchFlags } from '@vue/shared' +import { AssetData } from '../src/transform' function createRoot(options: Partial = {}): RootNode { return { @@ -53,6 +54,13 @@ function createRoot(options: Partial = {}): RootNode { } } +function createAsset(name: string): AssetData { + return { + name, + warnMissing: true + } +} + describe('compiler: codegen', () => { test('module mode preamble', () => { const root = createRoot({ @@ -126,8 +134,13 @@ describe('compiler: codegen', () => { test('assets + temps', () => { const root = createRoot({ - components: [`Foo`, `bar-baz`, `barbaz`, `Qux__self`], - directives: [`my_dir_0`, `my_dir_1`], + components: [ + createAsset(`Foo`), + createAsset(`bar-baz`), + createAsset(`barbaz`), + createAsset(`Qux__self`) + ], + directives: [createAsset(`my_dir_0`), createAsset(`my_dir_1`)], temps: 3 }) const { code } = generate(root, { mode: 'function' }) diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts index 33fdb7dba19..882b5d10a92 100644 --- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts @@ -69,7 +69,7 @@ describe('compiler: element transform', () => { test('import + resolve component', () => { const { root } = parseWithElementTransform(``) expect(root.helpers).toContain(RESOLVE_COMPONENT) - expect(root.components).toContain(`Foo`) + expect(root.components).toEqual([{ name: 'Foo', warnMissing: true }]) }) test('resolve implcitly self-referencing component', () => { @@ -77,7 +77,9 @@ describe('compiler: element transform', () => { filename: `/foo/bar/Example.vue?vue&type=template` }) expect(root.helpers).toContain(RESOLVE_COMPONENT) - expect(root.components).toContain(`Example__self`) + expect(root.components).toEqual([ + { name: 'Example__self', warnMissing: true } + ]) }) test('resolve component from setup bindings', () => { @@ -86,8 +88,8 @@ describe('compiler: element transform', () => { Example: BindingTypes.SETUP_MAYBE_REF } }) - expect(root.helpers).not.toContain(RESOLVE_COMPONENT) - expect(node.tag).toBe(`$setup["Example"]`) + expect(root.helpers).toContain(RESOLVE_COMPONENT) + expect(node.tag).toBe(`_component_Example`) }) test('do not resolve component from non-script-setup bindings', () => { @@ -99,7 +101,7 @@ describe('compiler: element transform', () => { bindingMetadata }) expect(root.helpers).toContain(RESOLVE_COMPONENT) - expect(root.components).toContain(`Example`) + expect(root.components).toEqual([{ name: 'Example', warnMissing: true }]) }) test('static props', () => { @@ -476,7 +478,7 @@ describe('compiler: element transform', () => { } ) expect(root.helpers).toContain(RESOLVE_DIRECTIVE) - expect(root.directives).toContain(`foo`) + expect(root.directives).toEqual([{ name: 'foo', warnMissing: true }]) expect(node).toMatchObject({ tag: `"div"`, props: undefined, @@ -536,9 +538,11 @@ describe('compiler: element transform', () => { `
` ) expect(root.helpers).toContain(RESOLVE_DIRECTIVE) - expect(root.directives).toContain(`foo`) - expect(root.directives).toContain(`bar`) - expect(root.directives).toContain(`baz`) + expect(root.directives).toEqual([ + { name: 'foo', warnMissing: true }, + { name: 'bar', warnMissing: true }, + { name: 'baz', warnMissing: true } + ]) expect(node).toMatchObject({ directives: { diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts index df843520209..7d17ed96458 100644 --- a/packages/compiler-core/src/ast.ts +++ b/packages/compiler-core/src/ast.ts @@ -11,7 +11,7 @@ import { WITH_DIRECTIVES } from './runtimeHelpers' import { PropsExpression } from './transforms/transformElement' -import { ImportItem, TransformContext } from './transform' +import { ImportItem, TransformContext, AssetData } from './transform' // Vue template is a platform-agnostic superset of HTML (syntax only). // More namespaces like SVG and MathML are declared by platform specific @@ -101,8 +101,8 @@ export interface RootNode extends Node { type: NodeTypes.ROOT children: TemplateChildNode[] helpers: symbol[] - components: string[] - directives: string[] + components: AssetData[] + directives: AssetData[] hoists: (JSChildNode | null)[] imports: ImportItem[] cached: number diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 6367743d8bc..1591f6412c2 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -53,7 +53,7 @@ import { WITH_CTX, RESOLVE_FILTER } from './runtimeHelpers' -import { ImportItem } from './transform' +import { AssetData, ImportItem } from './transform' const PURE_ANNOTATION = `/*#__PURE__*/` const WITH_ID = `_withId` @@ -464,7 +464,7 @@ function genModulePreamble( } function genAssets( - assets: string[], + assets: AssetData[], type: 'component' | 'directive' | 'filter', { helper, push, newline }: CodegenContext ) { @@ -476,15 +476,22 @@ function genAssets( : RESOLVE_DIRECTIVE ) for (let i = 0; i < assets.length; i++) { - let id = assets[i] + const data = assets[i] + let id = data.name // potential component implicit self-reference inferred from SFC filename const maybeSelfReference = id.endsWith('__self') if (maybeSelfReference) { id = id.slice(0, -6) } + const needFallbackArg = !!data.fallback + const needWarnArg = needFallbackArg || !data.warnMissing + const needMaybeSelfReferenceArg = + type === 'component' && (needWarnArg || maybeSelfReference) push( `const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${ - maybeSelfReference ? `, true` : `` + needMaybeSelfReferenceArg ? `, ${JSON.stringify(data.warnMissing)}` : `` + }${needWarnArg ? `, ${JSON.stringify(data.warnMissing)}` : ``}${ + needFallbackArg ? `, ${data.fallback}` : `` })` ) if (i < assets.length - 1) { diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index add7ea13c4b..0ce29f71cfd 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -83,6 +83,12 @@ export interface ImportItem { path: string } +export interface AssetData { + name: string + warnMissing: boolean + fallback?: string +} + export interface TransformContext extends Required< Omit @@ -91,8 +97,8 @@ export interface TransformContext selfName: string | null root: RootNode helpers: Map - components: Set - directives: Set + components: Map + directives: Map hoists: (JSChildNode | null)[] imports: ImportItem[] temps: number @@ -175,8 +181,8 @@ export function createTransformContext( // state root, helpers: new Map(), - components: new Set(), - directives: new Set(), + components: new Map(), + directives: new Map(), hoists: [], imports: [], constantCache: new Map(), @@ -322,8 +328,8 @@ export function transform(root: RootNode, options: TransformOptions) { } // finalize meta information root.helpers = [...context.helpers.keys()] - root.components = [...context.components] - root.directives = [...context.directives] + root.components = [...context.components.values()] + root.directives = [...context.directives.values()] root.imports = context.imports root.hoists = context.hoists root.temps = context.temps diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index dba1a99b487..5c7c8f90ec2 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -277,7 +277,13 @@ export function resolveComponentType( if (!__BROWSER__) { const fromSetup = resolveSetupReference(tag, context) if (fromSetup) { - return fromSetup + context.helper(RESOLVE_COMPONENT) + context.components.set(tag, { + name: tag, + warnMissing: false, + fallback: fromSetup + }) + return `${toValidAssetId(tag, `component`)}` } } @@ -291,13 +297,19 @@ export function resolveComponentType( // codegen.ts has special check for __self postfix when generating // component imports, which will pass additional `maybeSelfReference` flag // to `resolveComponent`. - context.components.add(tag + `__self`) + context.components.set(tag, { + name: tag + `__self`, + warnMissing: true + }) return toValidAssetId(tag, `component`) } // 5. user component (resolve) context.helper(RESOLVE_COMPONENT) - context.components.add(tag) + context.components.set(tag, { + name: tag, + warnMissing: true + }) return toValidAssetId(tag, `component`) } @@ -708,16 +720,23 @@ function buildDirectiveArgs( dirArgs.push(context.helperString(runtime)) } else { // user directive. + context.helper(RESOLVE_DIRECTIVE) // see if we have directives exposed via