diff --git a/packages/uni-cli-shared/__tests__/transformImports.spec.ts b/packages/uni-cli-shared/__tests__/transformImports.spec.ts index 200e393a75f498fb9ab9ad9a081edcc2a5077a38..9a4cd7efce0b610fb23a1954c0f9f2d06e6b3bce 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 58b809545ef2d9d1ac4a32210eb01146c3cdd3f6..100e5150149ef805716f288934e23dffe1bd083b 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 c835c19d512e846d14cac28abd5722d050349ae0..e4f42134796977a7b2c97f53b430b2924f6b4cf1 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 192fea5b6e9f6289fd180406f1e7af575891b69d..8765e1b1a36e43ff3a25fd4a592cce909799f84c 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 f9d7e53c19c70b1700d3c31b99f5f8db87d097e7..5555cb91bce0fd96113121194f1825ba55b1c534 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 a0a58b713ba4f939c7e5d671243a8820e31c5f93..1b2362cda4fd505567f366070285ad08695a7ea6 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 eb1e69f5ed7564455ad04494fc795854e781fca8..981f5c0d69c82b2cfb6236ec1da05a71d489c3f8 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) {