From 0ced70cc1ce7239b921caab90d247302004785d4 Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Thu, 9 Dec 2021 17:10:20 +0800 Subject: [PATCH] feat(mp): Compatible with unplugin-vue-components (#3057) --- .../__tests__/transformImports.spec.ts | 37 +++++++++++++++ .../uni-cli-shared/src/mp/transformImports.ts | 46 +++++++++++++++++-- packages/uni-mp-alipay/__tests__/ref.spec.ts | 14 ++++-- .../uni-mp-compiler/__tests__/ref.spec.ts | 12 +++-- packages/uni-mp-compiler/src/codegen.ts | 21 +++++++++ .../src/transforms/transformElement.ts | 2 + .../src/plugins/usingComponents.ts | 1 + 7 files changed, 121 insertions(+), 12 deletions(-) diff --git a/packages/uni-cli-shared/__tests__/transformImports.spec.ts b/packages/uni-cli-shared/__tests__/transformImports.spec.ts index 200e393a7..9a4cd7efc 100644 --- a/packages/uni-cli-shared/__tests__/transformImports.spec.ts +++ b/packages/uni-cli-shared/__tests__/transformImports.spec.ts @@ -162,6 +162,43 @@ export function createApp() { }) }) + test(`unplugin-vue-components`, async () => { + const source = `import { ref, watch } from 'vue';/* unplugin-vue-components disabled */import __unplugin_components_0 from '${root}/components/test1.vue'; + const _sfc_main = { + setup() { + const visible = ref(false); + watch(visible, () => { + console.log("parent visible change"); + }); + return { + visible + }; + } + }; + import { o as _o, resolveComponent as _resolveComponent, p as _p } from "vue"; + const __BINDING_COMPONENTS__ = '{"Test1":{"name":"_component_Test","type":"unknown"}}'; + if (!Array) {const _component_Test = __unplugin_components_0;Math.max.call(null, _component_Test);} + function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return {}; + } + import _export_sfc from "plugin-vue:export-helper"; + export default /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); + ` + const { code, usingComponents } = await transformVueComponentImports( + source, + importer, + { + root, + resolve, + dynamicImport, + } + ) + expect(code).toContain( + `const __unplugin_components_0 = ()=>import('${root}/components/test1.vue')` + ) + expect(usingComponents).toMatchObject({ test1: '/components/test1' }) + }) + test(`PascalCase`, async () => { const source = `import test1 from "../../components/test1.vue"; import MyComponentName from "../../components/test1.vue"; diff --git a/packages/uni-cli-shared/src/mp/transformImports.ts b/packages/uni-cli-shared/src/mp/transformImports.ts index 58b809545..100e51501 100644 --- a/packages/uni-cli-shared/src/mp/transformImports.ts +++ b/packages/uni-cli-shared/src/mp/transformImports.ts @@ -1,13 +1,17 @@ import { parse, ParserPlugin } from '@babel/parser' import { + IfStatement, ImportDeclaration, + isBlockStatement, isCallExpression, isIdentifier, + isIfStatement, isImportDeclaration, isMemberExpression, isObjectExpression, isObjectProperty, isStringLiteral, + isUnaryExpression, isVariableDeclaration, ObjectProperty, Program, @@ -18,6 +22,7 @@ import { camelize, capitalize, hyphenate } from '@vue/shared' import { walk } from 'estree-walker' import MagicString from 'magic-string' import { PluginContext } from 'rollup' +import { addLeadingSlash } from '@dcloudio/uni-shared' import { M } from '../messages' import { BINDING_COMPONENTS } from '../constants' import { @@ -25,7 +30,6 @@ import { normalizeParsePlugins, removeExt, } from '../utils' -import { addLeadingSlash } from '@dcloudio/uni-shared' interface TransformVueComponentImportsOptions { root: string @@ -103,6 +107,7 @@ type BindingComponents = Record< * @returns */ function findBindingComponents(ast: Statement[]): BindingComponents { + const mapping = findUnpluginComponents(ast) for (const node of ast) { if (!isVariableDeclaration(node)) { continue @@ -117,10 +122,10 @@ function findBindingComponents(ast: Statement[]): BindingComponents { ) as Record return Object.keys(bindingComponents).reduce( (bindings, tag) => { - const binding = bindingComponents[tag] - bindings[binding.name] = { + const { name, type } = bindingComponents[tag] + bindings[mapping[name] || name] = { tag, - type: binding.type, + type: type, } return bindings }, @@ -130,6 +135,39 @@ function findBindingComponents(ast: Statement[]): BindingComponents { } return {} } + +function findUnpluginComponents(ast: Statement[]): Record { + const res = Object.create(null) + // if(!Array){} + const ifStatement = ast.find( + (statement) => + isIfStatement(statement) && + isUnaryExpression(statement.test) && + statement.test.operator === '!' && + isIdentifier(statement.test.argument) && + statement.test.argument.name === 'Array' + ) as IfStatement + if (!ifStatement) { + return res + } + if (!isBlockStatement(ifStatement.consequent)) { + return res + } + for (const node of ifStatement.consequent.body) { + if (!isVariableDeclaration(node)) { + continue + } + const { id, init } = node.declarations[0] + if ( + isIdentifier(id) && + isIdentifier(init) && + init.name.includes('unplugin_components') + ) { + res[id.name] = init.name + } + } + return res +} /** * 查找全局组件定义:app.component('component-a',{}) * @param ast diff --git a/packages/uni-mp-alipay/__tests__/ref.spec.ts b/packages/uni-mp-alipay/__tests__/ref.spec.ts index c835c19d5..e4f421347 100644 --- a/packages/uni-mp-alipay/__tests__/ref.spec.ts +++ b/packages/uni-mp-alipay/__tests__/ref.spec.ts @@ -23,7 +23,9 @@ describe('mp-alipay: transform ref', () => { assert( ``, ``, - `const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' + `import { resolveComponent as _resolveComponent } from "vue" +const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return {} @@ -35,8 +37,9 @@ export function render(_ctx, _cache) { assert( ``, ``, - `import { f as _f } from "vue" + `import { resolveComponent as _resolveComponent, f as _f } from "vue" const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return { a: _f(_ctx.items, (item, k0, i0) => { return { a: '2a9ec0b0-0' + '-' + i0 }; }) } @@ -80,7 +83,9 @@ export function render(_ctx, _cache) { assert( ``, ``, - `const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' + `import { resolveComponent as _resolveComponent } from "vue" +const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return { a: _ctx.custom } @@ -92,8 +97,9 @@ export function render(_ctx, _cache) { assert( ``, ``, - `import { f as _f } from "vue" + `import { resolveComponent as _resolveComponent, f as _f } from "vue" const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return { a: _f(_ctx.items, (item, k0, i0) => { return { a: '2a9ec0b0-0' + '-' + i0 }; }), b: _ctx.custom } diff --git a/packages/uni-mp-compiler/__tests__/ref.spec.ts b/packages/uni-mp-compiler/__tests__/ref.spec.ts index 192fea5b6..8765e1b1a 100644 --- a/packages/uni-mp-compiler/__tests__/ref.spec.ts +++ b/packages/uni-mp-compiler/__tests__/ref.spec.ts @@ -30,8 +30,9 @@ describe('compiler: transform ref', () => { assert( ``, ``, - `import { sr as _sr } from "vue" + `import { resolveComponent as _resolveComponent, sr as _sr } from "vue" const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return { a: _sr('custom', '2a9ec0b0-0') } @@ -44,8 +45,9 @@ export function render(_ctx, _cache) { assert( ``, ``, - `import { sr as _sr, f as _f } from "vue" + `import { resolveComponent as _resolveComponent, sr as _sr, f as _f } from "vue" const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _sr('custom', '2a9ec0b0-0' + '-' + i0), b: '2a9ec0b0-0' + '-' + i0 }; }) } @@ -127,8 +129,9 @@ export function render(_ctx, _cache) { assert( ``, ``, - `import { sr as _sr } from "vue" + `import { resolveComponent as _resolveComponent, sr as _sr } from "vue" const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return { a: _sr(_ctx.custom, '2a9ec0b0-0'), b: _ctx.custom } @@ -141,8 +144,9 @@ export function render(_ctx, _cache) { assert( ``, ``, - `import { sr as _sr, f as _f } from "vue" + `import { resolveComponent as _resolveComponent, sr as _sr, f as _f } from "vue" const __BINDING_COMPONENTS__ = '{"custom":{"name":"_component_custom","type":"unknown"}}' +if (!Array) {const _component_custom = _resolveComponent("custom");Math.max.call(null, _component_custom);} export function render(_ctx, _cache) { return { a: _f(_ctx.items, (item, k0, i0) => { return { a: _sr(_ctx.custom, '2a9ec0b0-0' + '-' + i0), b: '2a9ec0b0-0' + '-' + i0 }; }), b: _ctx.custom } diff --git a/packages/uni-mp-compiler/src/codegen.ts b/packages/uni-mp-compiler/src/codegen.ts index f9d7e53c1..5555cb91b 100644 --- a/packages/uni-mp-compiler/src/codegen.ts +++ b/packages/uni-mp-compiler/src/codegen.ts @@ -5,6 +5,7 @@ import { helperNameMap, InterpolationNode, NodeTypes, + RESOLVE_COMPONENT, RootNode, SimpleExpressionNode, TextNode, @@ -178,6 +179,26 @@ function genComponentImports( JSON.stringify(bindingComponents) + `'` ) + const resolveComponents: string[] = [] + const names: string[] = [] + Object.keys(bindingComponents).forEach((id) => { + const { type, name } = bindingComponents[id] + if (type === BindingComponentTypes.UNKNOWN) { + resolveComponents.push( + `const ${name} = _${helperNameMap[RESOLVE_COMPONENT]}("${id}");` + ) + names.push(name) + } + }) + if (resolveComponents.length) { + newline() + push(`if (!Array) {`) + resolveComponents.forEach((code) => { + push(code) + }) + push(`Math.max.call(null, ${names.join(', ')});`) + push(`}`) + } newline() importDeclarations.forEach((str) => push(str)) if (importDeclarations.length) { diff --git a/packages/uni-mp-compiler/src/transforms/transformElement.ts b/packages/uni-mp-compiler/src/transforms/transformElement.ts index a0a58b713..1b2362cda 100644 --- a/packages/uni-mp-compiler/src/transforms/transformElement.ts +++ b/packages/uni-mp-compiler/src/transforms/transformElement.ts @@ -16,6 +16,7 @@ import { findDir, DirectiveNode, ComponentNode, + RESOLVE_COMPONENT, } from '@vue/compiler-core' import { isComponentTag } from '@dcloudio/uni-shared' @@ -125,6 +126,7 @@ function processComponent(node: ComponentNode, context: TransformContext) { name: toValidAssetId(tag, `component`), type: BindingComponentTypes.UNKNOWN, } + context.helper(RESOLVE_COMPONENT) } function resolveSetupReference(name: string, context: TransformContext) { diff --git a/packages/uni-mp-vite/src/plugins/usingComponents.ts b/packages/uni-mp-vite/src/plugins/usingComponents.ts index eb1e69f5e..981f5c0d6 100644 --- a/packages/uni-mp-vite/src/plugins/usingComponents.ts +++ b/packages/uni-mp-vite/src/plugins/usingComponents.ts @@ -17,6 +17,7 @@ export function uniUsingComponentsPlugin( ): Plugin { return { name: 'vite:uni-mp-using-component', + enforce: 'post', async transform(source, id) { const { filename, query } = parseVueRequest(id) if (query.vue) { -- GitLab