提交 0ced70cc 编写于 作者: fxy060608's avatar fxy060608

feat(mp): Compatible with unplugin-vue-components (#3057)

上级 ce3d9665
......@@ -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";
......
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<string, { name: string; type: 'unknown' | 'setup' | 'self' }>
return Object.keys(bindingComponents).reduce<BindingComponents>(
(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<string, string> {
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
......
......@@ -23,7 +23,9 @@ describe('mp-alipay: transform ref', () => {
assert(
`<custom ref="custom"/>`,
`<custom ref="__r" u-r="custom" u-i="2a9ec0b0-0" onVI="__l"/>`,
`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(
`<custom v-for="item in items" ref="custom"/>`,
`<custom a:for="{{a}}" a:for-item="item" ref="__r" u-r-i-f="custom" u-i="{{item.a}}" onVI="__l"/>`,
`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(
`<custom :ref="custom"/>`,
`<custom ref="__r" u-r="{{a}}" u-i="2a9ec0b0-0" onVI="__l"/>`,
`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(
`<custom v-for="item in items" :ref="custom"/>`,
`<custom a:for="{{a}}" a:for-item="item" ref="__r" u-r-i-f="{{b}}" u-i="{{item.a}}" onVI="__l"/>`,
`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 }
......
......@@ -30,8 +30,9 @@ describe('compiler: transform ref', () => {
assert(
`<custom ref="custom"/>`,
`<custom class="r" u-r="custom" u-i="2a9ec0b0-0"/>`,
`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(
`<custom v-for="item in items" ref="custom"/>`,
`<custom wx:for="{{a}}" wx:for-item="item" class="r-i-f" u-r="custom" u-i="{{item.b}}"/>`,
`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(
`<custom :ref="custom"/>`,
`<custom class="r" u-r="{{b}}" u-i="2a9ec0b0-0"/>`,
`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(
`<custom v-for="item in items" :ref="custom"/>`,
`<custom wx:for="{{a}}" wx:for-item="item" class="r-i-f" u-r="{{b}}" u-i="{{item.b}}"/>`,
`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 }
......
......@@ -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) {
......
......@@ -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) {
......
......@@ -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) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册