diff --git a/packages/uni-cli-shared/__tests__/transformImports.spec.ts b/packages/uni-cli-shared/__tests__/transformImports.spec.ts index 9fabf9cd5e0ec0e1da04d42586fb0d17fe40162a..e712e2e9a44109a6c865f2873fe4ea3e19c795c2 100644 --- a/packages/uni-cli-shared/__tests__/transformImports.spec.ts +++ b/packages/uni-cli-shared/__tests__/transformImports.spec.ts @@ -2,7 +2,7 @@ import path from 'path' import { ResolvedId } from 'rollup' import { transformVueComponentImports } from '../src/mp/transformImports' const root = '/usr/xxx/projects/test/src' -const importer = '/usr/xxx/projects/test/src/pages/index/index.vue' + async function resolve(id: string, importer?: string) { return { id: importer ? path.resolve(path.dirname(importer), id) : id, @@ -14,181 +14,222 @@ function dynamicImport(name: string, source: string) { } describe('transformVueComponentImports', () => { - test(`basic`, async () => { - const source = `import test1 from "${root}/components/test1.vue"; - const _sfc_main = { - components: { - test1 - } - }; - const __BINDING_COMPONENTS__ = '{"test1":{"name":"_component_test1","type":"unknown"}}'; - function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { - return {}; - } - import "${importer}?vue&type=style&index=0&lang.css"; - import _export_sfc from "plugin-vue:export-helper"; - export default /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); + describe('global', () => { + const importer = '/usr/xxx/projects/test/src/main.js' + test(`basic`, async () => { + const source = ` +import { createSSRApp } from 'vue' +import ComponentA from './components/component-a.vue' +import ComponentB from './components/component-b.vue' +export function createApp() { + const app = createSSRApp(App) + app.component('component-a',ComponentA) + app.component('component-b',ComponentB) + return { + app + } +} ` - const { code, usingComponents } = await transformVueComponentImports( - source, - importer, - { - root, - resolve, - dynamicImport, - } - ) - expect(code).toContain( - `const test1 = ()=>import('${root}/components/test1.vue')` - ) - expect(usingComponents).toMatchObject({ test1: '/components/test1' }) + const { code, usingComponents } = await transformVueComponentImports( + source, + importer, + { + root, + global: true, + resolve, + dynamicImport, + } + ) + expect(code).toContain( + `const ComponentA = ()=>import('${root}/components/component-a.vue')` + ) + expect(code).toContain( + `const ComponentB = ()=>import('${root}/components/component-b.vue')` + ) + expect(usingComponents).toMatchObject({ + 'component-a': '/components/component-a', + 'component-b': '/components/component-b', + }) + }) }) - - test(`easycom`, async () => { - const source = `import test1 from "../../components/test1.vue"; - import MyComponentName from "../../components/test1.vue"; - const _sfc_main = { - components: { - test1, - MyComponentName - } - }; - const __BINDING_COMPONENTS__ = '{"test":{"name":"_easycom_test","type":"unknown"},"test1":{"name":"_component_test1","type":"unknown"},"MyComponentName":{"name":"_component_MyComponentName","type":"unknown"},"my-component-name":{"name":"_component_my_component_name","type":"unknown"}}'; - import _easycom_test from "${root}/components/test/test.vue"; - if (!Math) { - Math.max.call(Max, _easycom_test); - } - function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { - return {}; - } - import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; - 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, + describe('local', () => { + const importer = '/usr/xxx/projects/test/src/pages/index/index.vue' + test(`basic`, async () => { + const source = `import test1 from "${root}/components/test1.vue"; + const _sfc_main = { + components: { + test1 + } + }; + const __BINDING_COMPONENTS__ = '{"test1":{"name":"_component_test1","type":"unknown"}}'; + function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return {}; } - ) - expect(code).toContain( - `const _easycom_test = ()=>import('${root}/components/test/test.vue')` - ) - expect(usingComponents).toMatchObject({ - test: '/components/test/test', - test1: '/components/test1', - 'my-component-name': '/components/test1', + import "${importer}?vue&type=style&index=0&lang.css"; + 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 test1 = ()=>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"; - const _sfc_main = { - components: { - test1, - MyComponentName + test(`easycom`, async () => { + const source = `import test1 from "../../components/test1.vue"; + import MyComponentName from "../../components/test1.vue"; + const _sfc_main = { + components: { + test1, + MyComponentName + } + }; + const __BINDING_COMPONENTS__ = '{"test":{"name":"_easycom_test","type":"unknown"},"test1":{"name":"_component_test1","type":"unknown"},"MyComponentName":{"name":"_component_MyComponentName","type":"unknown"},"my-component-name":{"name":"_component_my_component_name","type":"unknown"}}'; + import _easycom_test from "${root}/components/test/test.vue"; + if (!Math) { + Math.max.call(Max, _easycom_test); } - }; - const __BINDING_COMPONENTS__ = '{"test1":{"name":"_component_test1","type":"unknown"},"MyComponentName":{"name":"_component_MyComponentName","type":"unknown"},"my-component-name":{"name":"_component_my_component_name","type":"unknown"}}'; - function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { - return {}; - } - import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; - 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, + function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return {}; } - ) - expect(code).toContain( - `const MyComponentName = ()=>import('${root}/components/test1.vue')` - ) - expect(usingComponents).toMatchObject({ - test1: '/components/test1', - 'my-component-name': '/components/test1', + import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; + 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 _easycom_test = ()=>import('${root}/components/test/test.vue')` + ) + expect(usingComponents).toMatchObject({ + test: '/components/test/test', + test1: '/components/test1', + 'my-component-name': '/components/test1', + }) }) - }) - test(`setup`, async () => { - const source = `import { defineComponent as _defineComponent } from "vue"; - const __BINDING_COMPONENTS__ = '{"test1":{"name":"test1","type":"setup"},"MyComponentName":{"name":"MyComponentName","type":"setup"},"my-component-name":{"name":"MyComponentName","type":"setup"}}'; - if (!Math) { - Math.max.call(Max, test1, MyComponentName, MyComponentName); - } - import test1 from "../../components/test1.vue"; - import MyComponentName from "../../components/test1.vue"; - const _sfc_main = /* @__PURE__ */ _defineComponent({ - setup(__props) { - return (_ctx, _cache) => { - return {}; - }; - } - }); - import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; - export default _sfc_main; -` - const { code, usingComponents } = await transformVueComponentImports( - source, - importer, - { - root, - resolve, - dynamicImport, + test(`PascalCase`, async () => { + const source = `import test1 from "../../components/test1.vue"; + import MyComponentName from "../../components/test1.vue"; + const _sfc_main = { + components: { + test1, + MyComponentName + } + }; + const __BINDING_COMPONENTS__ = '{"test1":{"name":"_component_test1","type":"unknown"},"MyComponentName":{"name":"_component_MyComponentName","type":"unknown"},"my-component-name":{"name":"_component_my_component_name","type":"unknown"}}'; + function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return {}; } - ) - expect(code).toContain( - `const MyComponentName = ()=>import('${root}/components/test1.vue')` - ) - expect(usingComponents).toMatchObject({ - test1: '/components/test1', - 'my-component-name': '/components/test1', + import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; + 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 MyComponentName = ()=>import('${root}/components/test1.vue')` + ) + expect(usingComponents).toMatchObject({ + test1: '/components/test1', + 'my-component-name': '/components/test1', + }) }) - }) - test(`setup with easycom`, async () => { - const source = `import { defineComponent as _defineComponent } from "vue"; - const __BINDING_COMPONENTS__ = '{"test":{"name":"_easycom_test","type":"unknown"},"test1":{"name":"test1","type":"setup"},"MyComponentName":{"name":"MyComponentName","type":"setup"},"my-component-name":{"name":"MyComponentName","type":"setup"}}'; - import _easycom_test from "${root}/components/test/test.vue"; - if (!Math) { - Math.max.call(Max, _easycom_test, test1, MyComponentName, MyComponentName); - } - import test1 from "../../components/test1.vue"; - import MyComponentName from "../../components/test1.vue"; - const _sfc_main = /* @__PURE__ */ _defineComponent({ - setup(__props) { - return (_ctx, _cache) => { - return {}; - }; + + test(`setup`, async () => { + const source = `import { defineComponent as _defineComponent } from "vue"; + const __BINDING_COMPONENTS__ = '{"test1":{"name":"test1","type":"setup"},"MyComponentName":{"name":"MyComponentName","type":"setup"},"my-component-name":{"name":"MyComponentName","type":"setup"}}'; + if (!Math) { + Math.max.call(Max, test1, MyComponentName, MyComponentName); } - }); - import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; - export default _sfc_main; -` - const { code, usingComponents } = await transformVueComponentImports( - source, - importer, - { - root, - resolve, - dynamicImport, + import test1 from "../../components/test1.vue"; + import MyComponentName from "../../components/test1.vue"; + const _sfc_main = /* @__PURE__ */ _defineComponent({ + setup(__props) { + return (_ctx, _cache) => { + return {}; + }; + } + }); + import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; + export default _sfc_main; + ` + const { code, usingComponents } = await transformVueComponentImports( + source, + importer, + { + root, + resolve, + dynamicImport, + } + ) + expect(code).toContain( + `const MyComponentName = ()=>import('${root}/components/test1.vue')` + ) + expect(usingComponents).toMatchObject({ + test1: '/components/test1', + 'my-component-name': '/components/test1', + }) + }) + test(`setup with easycom`, async () => { + const source = `import { defineComponent as _defineComponent } from "vue"; + const __BINDING_COMPONENTS__ = '{"test":{"name":"_easycom_test","type":"unknown"},"test1":{"name":"test1","type":"setup"},"MyComponentName":{"name":"MyComponentName","type":"setup"},"my-component-name":{"name":"MyComponentName","type":"setup"}}'; + import _easycom_test from "${root}/components/test/test.vue"; + if (!Math) { + Math.max.call(Max, _easycom_test, test1, MyComponentName, MyComponentName); } - ) - expect(code).toContain( - `const _easycom_test = ()=>import('${root}/components/test/test.vue')` - ) - expect(usingComponents).toMatchObject({ - test: '/components/test/test', - test1: '/components/test1', - 'my-component-name': '/components/test1', + import test1 from "../../components/test1.vue"; + import MyComponentName from "../../components/test1.vue"; + const _sfc_main = /* @__PURE__ */ _defineComponent({ + setup(__props) { + return (_ctx, _cache) => { + return {}; + }; + } + }); + import "${root}/pages/index/index.vue?vue&type=style&index=0&lang.css"; + export default _sfc_main; + ` + const { code, usingComponents } = await transformVueComponentImports( + source, + importer, + { + root, + resolve, + dynamicImport, + } + ) + expect(code).toContain( + `const _easycom_test = ()=>import('${root}/components/test/test.vue')` + ) + expect(usingComponents).toMatchObject({ + test: '/components/test/test', + test1: '/components/test1', + 'my-component-name': '/components/test1', + }) }) }) }) diff --git a/packages/uni-cli-shared/src/messages/index.ts b/packages/uni-cli-shared/src/messages/index.ts index 50c5111bfb554479fd7d3104475cb73b08abbfbc..ffc07b776b6609144582fc1cedb2ca0e7e93ce0e 100644 --- a/packages/uni-cli-shared/src/messages/index.ts +++ b/packages/uni-cli-shared/src/messages/index.ts @@ -18,4 +18,6 @@ export const M = { 'i18n.fallbackLocale.missing': '当前应用配置的 fallbackLocale 或 locale 为:{locale},但 locale 目录缺少该语言文件', 'easycom.conflict': 'easycom组件冲突:', + 'mp.component.args[0]': '{0}的第一个参数必须为静态字符串', + 'mp.component.args[1]': '{0}需要两个参数', } diff --git a/packages/uni-cli-shared/src/mp/transformImports.ts b/packages/uni-cli-shared/src/mp/transformImports.ts index 42ced9a5ba8185822bd6685f7349b1aed6b4627a..7754f5b35ef116809dfe948e0960a4066bb0e443 100644 --- a/packages/uni-cli-shared/src/mp/transformImports.ts +++ b/packages/uni-cli-shared/src/mp/transformImports.ts @@ -1,8 +1,10 @@ import { parse, ParserPlugin } from '@babel/parser' import { ImportDeclaration, + isCallExpression, isIdentifier, isImportDeclaration, + isMemberExpression, isObjectExpression, isObjectProperty, isStringLiteral, @@ -16,11 +18,13 @@ import { camelize, capitalize, hyphenate } from '@vue/shared' import { walk } from 'estree-walker' import MagicString from 'magic-string' import { PluginContext } from 'rollup' +import { M } from '../messages' import { BINDING_COMPONENTS } from '../constants' import { normalizeMiniProgramFilename, removeExt } from '../utils' interface TransformVueComponentImportsOptions { root: string + global?: boolean resolve: PluginContext['resolve'] dynamicImport: (name: string, source: string) => string babelParserPlugins?: ParserPlugin[] @@ -31,6 +35,7 @@ export async function transformVueComponentImports( { root, resolve, + global, dynamicImport, babelParserPlugins, }: TransformVueComponentImportsOptions @@ -38,7 +43,7 @@ export async function transformVueComponentImports( code: string usingComponents: Record }> { - if (!code.includes(BINDING_COMPONENTS)) { + if (!global && !code.includes(BINDING_COMPONENTS)) { return { code, usingComponents: {} } } const s = new MagicString(code) @@ -49,7 +54,9 @@ export async function transformVueComponentImports( const imports = findVueComponentImports( scriptAst.body, - parseComponents(scriptAst, findBindingComponents(scriptAst.body)) + global + ? parseGlobalComponents(scriptAst) + : parseComponents(scriptAst, findBindingComponents(scriptAst.body)) ) const usingComponents: Record = {} for (let i = 0; i < imports.length; i++) { @@ -116,6 +123,47 @@ function findBindingComponents(ast: Statement[]): BindingComponents { } return {} } +/** + * 查找全局组件定义:app.component('component-a',{}) + * @param ast + * @returns + */ +function parseGlobalComponents(ast: Program) { + const bindingComponents: BindingComponents = {} + ;(walk as any)(ast, { + enter(child: Node) { + if (!isCallExpression(child)) { + return + } + const { callee } = child + // .component + if ( + !isMemberExpression(callee) || + !isIdentifier(callee.property) || + callee.property.name !== 'component' + ) { + return + } + // .component('component-a',{}) + const args = child.arguments + if (args.length !== 2) { + return + } + const [name, value] = args + if (!isStringLiteral(name)) { + return console.warn(M['mp.component.args[0]']) + } + if (!isIdentifier(value)) { + return console.warn(M['mp.component.args[1]']) + } + bindingComponents[value.name] = { + tag: name.value, + type: 'unknown', + } + }, + }) + return bindingComponents +} /** * 从 components 中查找定义的组件,修改 bindingComponents * @param ast diff --git a/packages/uni-mp-compiler/__tests__/test.spec.ts b/packages/uni-mp-compiler/__tests__/test.spec.ts index e828805598f724e62932844754258f542061296c..2fd372cf5f9396374b0fb232c5f1d76ba4ec0cba 100644 --- a/packages/uni-mp-compiler/__tests__/test.spec.ts +++ b/packages/uni-mp-compiler/__tests__/test.spec.ts @@ -13,6 +13,9 @@ function assert( filename: 'foo.vue', prefixIdentifiers: true, inline: true, + generatorOpts: { + concise: true, + }, miniProgram: { slot: { fallback: false, diff --git a/packages/uni-mp-compiler/__tests__/testUtils.ts b/packages/uni-mp-compiler/__tests__/testUtils.ts index 5e4ab47b15fce4ce3bad3b31f9709c9efa9644da..3c54eee509db1b27cb80b63cfc37dae1ffce1525 100644 --- a/packages/uni-mp-compiler/__tests__/testUtils.ts +++ b/packages/uni-mp-compiler/__tests__/testUtils.ts @@ -26,6 +26,9 @@ export function assert( inline: true, isNativeTag, isCustomElement, + generatorOpts: { + concise: true, + }, miniProgram: { slot: { fallback: false, diff --git a/packages/uni-mp-compiler/__tests__/transformElement.spec.ts b/packages/uni-mp-compiler/__tests__/transformElement.spec.ts index 2bce9b15ceb22333c5bf0b4e4536cc44dba26522..778fb4bda0a02ee8b29046a60268d9e7761f827d 100644 --- a/packages/uni-mp-compiler/__tests__/transformElement.spec.ts +++ b/packages/uni-mp-compiler/__tests__/transformElement.spec.ts @@ -16,7 +16,12 @@ function parseWithElementTransform( root: RootNode node: ElementNode } { - const { ast, code, preamble } = compile(`
${template}
`, options) + const { ast, code, preamble } = compile(`
${template}
`, { + generatorOpts: { + concise: true, + }, + ...options, + }) const node = (ast as any).children[0].children[0] return { code, @@ -32,10 +37,14 @@ describe('compiler: element transform', () => { source: ``, filename: 'foo.vue', id: 'foo', + compiler: MPCompiler as unknown as TemplateCompiler, compilerOptions: { mode: 'module', - }, + generatorOpts: { + concise: true, + }, + } as any, transformAssetUrls: { includeAbsolute: true, ...(createUniVueTransformAssetUrls('/') as Record), diff --git a/packages/uni-mp-compiler/__tests__/vBind.spec.ts b/packages/uni-mp-compiler/__tests__/vBind.spec.ts index bb6aa6d666c8062b860a726a5a1df68a24adc7ba..f084dda811aab96535b14aa6596b13dc973df39d 100644 --- a/packages/uni-mp-compiler/__tests__/vBind.spec.ts +++ b/packages/uni-mp-compiler/__tests__/vBind.spec.ts @@ -5,7 +5,12 @@ import { CompilerOptions } from '../src/options' import { assert, miniProgram } from './testUtils' function parseWithVBind(template: string, options: CompilerOptions = {}) { - const { ast, code } = compile(template, options) + const { ast, code } = compile(template, { + generatorOpts: { + concise: true, + }, + ...options, + }) return { code, node: ast.children[0] as ElementNode, diff --git a/packages/uni-mp-compiler/__tests__/vFor.spec.ts b/packages/uni-mp-compiler/__tests__/vFor.spec.ts index 1a4f5b2c4a65e4b3cb7b30ea1ae3ab2fd058d8c3..f71dc2fa67b1e8caedc6b39195f864b61ffd0888 100644 --- a/packages/uni-mp-compiler/__tests__/vFor.spec.ts +++ b/packages/uni-mp-compiler/__tests__/vFor.spec.ts @@ -14,7 +14,12 @@ function parseWithForTransform( template: string, options: CompilerOptions = {} ) { - const { ast } = compile(template, options) + const { ast } = compile(template, { + generatorOpts: { + concise: true, + }, + ...options, + }) return { root: ast, diff --git a/packages/uni-mp-compiler/__tests__/vIf.spec.ts b/packages/uni-mp-compiler/__tests__/vIf.spec.ts index f24fb839674fbc1c3c5be734833f768f416e27af..a65cecd083d69dd91916286d4c928ed12f461932 100644 --- a/packages/uni-mp-compiler/__tests__/vIf.spec.ts +++ b/packages/uni-mp-compiler/__tests__/vIf.spec.ts @@ -9,7 +9,12 @@ function compileWithIfTransform( returnIndex: number = 0, childrenLen: number = 1 ) { - const { ast } = compile(template, options) + const { ast } = compile(template, { + generatorOpts: { + concise: true, + }, + ...options, + }) if (!options.onError) { expect(ast.children.length).toBe(childrenLen) for (let i = 0; i < childrenLen; i++) { diff --git a/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts b/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts index 1a96247cb53c598a0558ac812260fcc664930f66..fa45c33c0f2fdaa6a0cd273a4c5b6352287d309a 100644 --- a/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts +++ b/packages/uni-mp-compiler/__tests__/vOn.mp.spec.ts @@ -5,7 +5,12 @@ import { CompilerOptions } from '../src/options' import { assert } from './testUtils' function parseWithVOn(template: string, options: CompilerOptions = {}) { - const { ast } = compile(template, options) + const { ast } = compile(template, { + generatorOpts: { + concise: true, + }, + ...options, + }) return { root: ast, node: ast.children[0] as ElementNode, diff --git a/packages/uni-mp-compiler/__tests__/vOn.spec.ts b/packages/uni-mp-compiler/__tests__/vOn.spec.ts index 888c762824506090057bca82306aad5ca3143c36..570b2c5b639269c7b6c81c16f6791dcb1ec5d3fe 100644 --- a/packages/uni-mp-compiler/__tests__/vOn.spec.ts +++ b/packages/uni-mp-compiler/__tests__/vOn.spec.ts @@ -4,7 +4,12 @@ import { CompilerOptions } from '../src/options' import { assert } from './testUtils' function parseWithVOn(template: string, options: CompilerOptions = {}) { - const { ast } = compile(template, options) + const { ast } = compile(template, { + generatorOpts: { + concise: true, + }, + ...options, + }) return { root: ast, node: ast.children[0] as ElementNode, diff --git a/packages/uni-mp-compiler/src/ast.ts b/packages/uni-mp-compiler/src/ast.ts index 65ea0e357c74ffffa94eb60e1c0849517a1865c5..24e593e8d599d0e2704090854c10abbbc58ebe47 100644 --- a/packages/uni-mp-compiler/src/ast.ts +++ b/packages/uni-mp-compiler/src/ast.ts @@ -94,7 +94,9 @@ export function parseExpr( code = genExpr(code) } try { - return parseExpression(code) + return parseExpression(code, { + plugins: context.expressionPlugins, + }) } catch (e: any) { context.onError( createCompilerError( diff --git a/packages/uni-mp-compiler/src/codegen.ts b/packages/uni-mp-compiler/src/codegen.ts index 7f63f41c40d1803f9052d4e6333ecc6074ffbdc1..0d3bf5b3bcb9493b44569fdc0b1a7d71ebfdd14f 100644 --- a/packages/uni-mp-compiler/src/codegen.ts +++ b/packages/uni-mp-compiler/src/codegen.ts @@ -1,4 +1,4 @@ -import { isString, isSymbol } from '@vue/shared' +import { isString, isSymbol, hasOwn } from '@vue/shared' import { CodegenResult, CompoundExpressionNode, @@ -11,7 +11,7 @@ import { TO_DISPLAY_STRING, } from '@vue/compiler-core' import { Expression } from '@babel/types' -import { default as babelGenerate } from '@babel/generator' +import { default as babelGenerate, GeneratorOptions } from '@babel/generator' import { addImportDeclaration, matchEasycom } from '@dcloudio/uni-cli-shared' import { CodegenOptions, CodegenRootNode } from './options' @@ -88,7 +88,7 @@ export function generate( } push(`return `) - push(genBabelExpr(ast.renderData)) + push(genBabelExpr(ast.renderData, options.generatorOpts)) if (useWithBlock) { deindent() push(`}`) @@ -283,13 +283,12 @@ function createGenNodeContext() { return context } -export function genBabelExpr(expr: Expression) { - return babelGenerate(expr, { - concise: true, - jsescOption: { - quotes: 'single', - }, - }).code +export function genBabelExpr(expr: Expression, opts: GeneratorOptions = {}) { + if (!hasOwn(opts, 'jsescOption')) { + opts.jsescOption = {} + } + opts.jsescOption!.quotes = 'single' + return babelGenerate(expr, opts).code } export function genExpr( diff --git a/packages/uni-mp-compiler/src/options.ts b/packages/uni-mp-compiler/src/options.ts index e2290a40a30e531a4645b17a6de546938fa4d906..315042ccbc5b49ddad146c30f6fcb6731e2c5a80 100644 --- a/packages/uni-mp-compiler/src/options.ts +++ b/packages/uni-mp-compiler/src/options.ts @@ -1,4 +1,5 @@ import { ParserPlugin } from '@babel/parser' +import { GeneratorOptions } from '@babel/generator' import { CallExpression, Expression, @@ -90,6 +91,7 @@ export interface CodegenOptions extends SharedTransformCodegenOptions { scopeId?: string | null runtimeModuleName?: string runtimeGlobalName?: string + generatorOpts?: GeneratorOptions miniProgram?: MiniProgramCompilerOptions } diff --git a/packages/uni-mp-vite/src/index.ts b/packages/uni-mp-vite/src/index.ts index f152283ca4cb8dda46f324231c027b8a084bb5ba..5143c65cd2ffc287efc07add337e9d68abe3b498 100644 --- a/packages/uni-mp-vite/src/index.ts +++ b/packages/uni-mp-vite/src/index.ts @@ -12,7 +12,11 @@ import { uniRenderjsPlugin } from './plugins/renderjs' export { UniMiniProgramPluginOptions } from './plugin' export default (options: UniMiniProgramPluginOptions) => { return [ - uniMainJsPlugin(options), + (options: { + vueOptions?: { script?: Partial } + }) => { + return uniMainJsPlugin(options.vueOptions?.script) + }, uniManifestJsonPlugin(options), uniPagesJsonPlugin(options), uniEntryPlugin(options), diff --git a/packages/uni-mp-vite/src/plugins/mainJs.ts b/packages/uni-mp-vite/src/plugins/mainJs.ts index e7834e98ed74e389debb1a10ed76cdb40c0b3257..3a5e180d963c2c9b9b7b3d20729513be7eadd8c4 100644 --- a/packages/uni-mp-vite/src/plugins/mainJs.ts +++ b/packages/uni-mp-vite/src/plugins/mainJs.ts @@ -1,16 +1,37 @@ -import { defineUniMainJsPlugin } from '@dcloudio/uni-cli-shared' -import { UniMiniProgramPluginOptions } from '../plugin' +import { + addMiniProgramUsingComponents, + defineUniMainJsPlugin, + transformVueComponentImports, +} from '@dcloudio/uni-cli-shared' +import { SFCScriptCompileOptions } from '@vue/compiler-sfc' +import { dynamicImport } from './usingComponents' -export function uniMainJsPlugin(options: UniMiniProgramPluginOptions) { +export function uniMainJsPlugin( + options: Partial = {} +) { return defineUniMainJsPlugin((opts) => { return { name: 'vite:uni-mp-main-js', enforce: 'pre', - transform(code, id) { + async transform(source, id) { if (opts.filter(id)) { - code = code.includes('createSSRApp') - ? createApp(code) - : createLegacyApp(code) + source = source.includes('createSSRApp') + ? createApp(source) + : createLegacyApp(source) + + const inputDir = process.env.UNI_INPUT_DIR + const { code, usingComponents } = await transformVueComponentImports( + source, + id, + { + root: inputDir, + global: true, + resolve: this.resolve, + dynamicImport, + babelParserPlugins: options.babelParserPlugins, + } + ) + addMiniProgramUsingComponents('app', usingComponents) return { code: `import 'plugin-vue:export-helper';import 'uni-mp-runtime';import './pages.json.js';` + diff --git a/packages/uni-mp-vite/src/plugins/usingComponents.ts b/packages/uni-mp-vite/src/plugins/usingComponents.ts index c8e5af33380cd931b2cccfd1cbb4b8aa88d15150..7597812863a3e47495e6bf1c0e84110d6b410eba 100644 --- a/packages/uni-mp-vite/src/plugins/usingComponents.ts +++ b/packages/uni-mp-vite/src/plugins/usingComponents.ts @@ -49,6 +49,6 @@ export function uniUsingComponentsPlugin( } } -function dynamicImport(name: string, value: string) { +export function dynamicImport(name: string, value: string) { return `const ${name} = ()=>import('${virtualComponentPath(value)}')` }