From a0b5bd4603fd83032cf7204a590fa30619af8aeb Mon Sep 17 00:00:00 2001 From: Ken Ho Date: Thu, 17 Mar 2022 12:09:03 +0800 Subject: [PATCH] feat(taro-plugin-vue3): sfc template conditional compilation --- packages/taro-plugin-vue3/src/transforms.ts | 104 ++++++++++++++++++ packages/taro-plugin-vue3/src/webpack.h5.ts | 17 +-- packages/taro-plugin-vue3/src/webpack.mini.ts | 45 +------- 3 files changed, 112 insertions(+), 54 deletions(-) create mode 100644 packages/taro-plugin-vue3/src/transforms.ts diff --git a/packages/taro-plugin-vue3/src/transforms.ts b/packages/taro-plugin-vue3/src/transforms.ts new file mode 100644 index 000000000000..29925f79160a --- /dev/null +++ b/packages/taro-plugin-vue3/src/transforms.ts @@ -0,0 +1,104 @@ +import { internalComponents, toCamelCase, capitalize } from '@tarojs/shared/dist/template' +import { DEFAULT_Components } from '@tarojs/runner-utils' + +import type { RootNode, TemplateChildNode, TransformContext, ElementNode, AttributeNode, DirectiveNode, SimpleExpressionNode, NodeTransform } from '@vue/compiler-core' + +function findEnv (source: string) { + const envREG = /(?<=(taro-env|taroEnv)=("|'))([a-z0-9]+)(?=("|'))/g + const found = source.match(envREG) + return found !== null ? found[0] : found +} + +function isTaroEnv (propName: string) { + return propName === 'taro-env' || propName === 'taroEnv' +} + +/** + * Transform elements with `taro-env` or `taroEnv` attribute. + * The value of `taro-env` or `taroEnv` must be the same as `process.env.TARO_ENV`. + * For example: + * `weapp specific node` + * is basically equal to + * `weapp specific node` + */ +export function transformTaroEnv (node: RootNode | TemplateChildNode, ctx: TransformContext) { + if (node.type >= 9 && node.type <= 11) { + const source = node.type === 11 + ? node.codegenNode?.loc.source || '' + : node.loc.source + + const targetEnv = findEnv(source) + + if (Boolean(targetEnv) && targetEnv !== process.env.TARO_ENV) { + ctx.removeNode(node as TemplateChildNode) + } + } else if (node.type === 1) { + node.props.forEach((prop, index) => { + if (prop.type === 6 && isTaroEnv(prop.name)) { + process.env.TARO_ENV !== prop.value?.content + ? ctx.removeNode(node) + : node.props.splice(index, 1) + } + }) + } +} + +const CUSTOM_WRAPPER = 'custom-wrapper' + +/** + * Transform and collect native tags and components. + */ +export function transformMiniNativeTags (data: Record): NodeTransform { + return (node) => { + if (node.type === 1 /* ELEMENT */) { + node = node as ElementNode + const nodeName = node.tag + + if (capitalize(toCamelCase(nodeName)) in internalComponents) { + // change only ElementTypes.COMPONENT to ElementTypes.ELEMENT + // and leave ElementTypes.SLOT untouched + if (node.tagType === 1 /* COMPONENT */) { + node.tagType = 0 /* ELEMENT */ + } + data.componentConfig.includes.add(nodeName) + } + + if (nodeName === CUSTOM_WRAPPER) { + node.tagType = 0 /* ELEMENT */ + data.componentConfig.thirdPartyComponents.set(CUSTOM_WRAPPER, new Set()) + } + + const usingComponent = data.componentConfig.thirdPartyComponents.get(nodeName) + if (usingComponent != null) { + node.props.forEach(prop => { + if (prop.type === 6 /* ATTRIBUTE */) { + usingComponent.add((prop as AttributeNode).name) + } else if ((prop as any).type === 7 /* DIRECTIVE */) { + prop = prop as DirectiveNode + if (prop.arg?.type === 4 /* SimpleExpression */) { + let value = (prop.arg as SimpleExpressionNode).content + if (prop.name === 'on') { + value = `on${value}` + } + usingComponent.add(value) + } + } + }) + } + } + } +} + +/** + * Transform h5 tags by adding a `taro-` prefix. + */ +export function trnasformH5Tags (node: RootNode | TemplateChildNode) { + if (node.type === 1 /* ELEMENT */) { + node = node as ElementNode + const nodeName = node.tag + if (DEFAULT_Components.has(nodeName)) { + node.tag = `taro-${nodeName}` + node.tagType = 1 /* 0: ELEMENT, 1: COMPONENT */ + } + } +} diff --git a/packages/taro-plugin-vue3/src/webpack.h5.ts b/packages/taro-plugin-vue3/src/webpack.h5.ts index 791b8254761d..6aa9c2a7dbc0 100644 --- a/packages/taro-plugin-vue3/src/webpack.h5.ts +++ b/packages/taro-plugin-vue3/src/webpack.h5.ts @@ -1,10 +1,9 @@ import { REG_VUE } from '@tarojs/helper' -import { DEFAULT_Components } from '@tarojs/runner-utils' import { getLoaderMeta } from './loader-meta' import { getVueLoaderPath } from './index' +import { transformTaroEnv, trnasformH5Tags } from './transforms' import type { IPluginContext } from '@tarojs/service' -import type { RootNode, TemplateChildNode, ElementNode } from '@vue/compiler-core' export function modifyH5WebpackChain (ctx: IPluginContext, chain) { setStyleLoader(ctx, chain) @@ -54,16 +53,10 @@ function setVueLoader (chain) { }, compilerOptions: { // https://github.com/vuejs/vue-next/blob/master/packages/compiler-core/src/options.ts - nodeTransforms: [(node: RootNode | TemplateChildNode) => { - if (node.type === 1 /* ELEMENT */) { - node = node as ElementNode - const nodeName = node.tag - if (DEFAULT_Components.has(nodeName)) { - node.tag = `taro-${nodeName}` - node.tagType = 1 /* 0: ELEMENT, 1: COMPONENT */ - } - } - }] + nodeTransforms: [ + transformTaroEnv, + trnasformH5Tags + ] } } diff --git a/packages/taro-plugin-vue3/src/webpack.mini.ts b/packages/taro-plugin-vue3/src/webpack.mini.ts index a21a3dfdfe22..edfe3429f7ad 100644 --- a/packages/taro-plugin-vue3/src/webpack.mini.ts +++ b/packages/taro-plugin-vue3/src/webpack.mini.ts @@ -1,14 +1,11 @@ import { REG_VUE } from '@tarojs/helper' -import { internalComponents, toCamelCase, capitalize } from '@tarojs/shared/dist/template' import { getLoaderMeta } from './loader-meta' import { getVueLoaderPath } from './index' +import { transformMiniNativeTags, transformTaroEnv } from './transforms' import type { IPluginContext } from '@tarojs/service' -import type { RootNode, TemplateChildNode, ElementNode, AttributeNode, DirectiveNode, SimpleExpressionNode } from '@vue/compiler-core' import type { IConfig } from './index' -const CUSTOM_WRAPPER = 'custom-wrapper' - type MiniConfig = IConfig['mini'] export function modifyMiniWebpackChain (_ctx: IPluginContext, chain, data, config: MiniConfig) { @@ -45,44 +42,8 @@ function setVueLoader (chain, data, config: MiniConfig) { } vueLoaderOption.compilerOptions.nodeTransforms ||= [] - vueLoaderOption.compilerOptions.nodeTransforms.unshift((node: RootNode | TemplateChildNode) => { - if (node.type === 1 /* ELEMENT */) { - node = node as ElementNode - const nodeName = node.tag - - if (capitalize(toCamelCase(nodeName)) in internalComponents) { - // change only ElementTypes.COMPONENT to ElementTypes.ELEMENT - // and leave ElementTypes.SLOT untouched - if (node.tagType === 1 /* COMPONENT */) { - node.tagType = 0 /* ELEMENT */ - } - data.componentConfig.includes.add(nodeName) - } - - if (nodeName === CUSTOM_WRAPPER) { - node.tagType = 0 /* ELEMENT */ - data.componentConfig.thirdPartyComponents.set(CUSTOM_WRAPPER, new Set()) - } - - const usingComponent = data.componentConfig.thirdPartyComponents.get(nodeName) - if (usingComponent != null) { - node.props.forEach(prop => { - if (prop.type === 6 /* ATTRIBUTE */) { - usingComponent.add((prop as AttributeNode).name) - } else if ((prop as any).type === 7 /* DIRECTIVE */) { - prop = prop as DirectiveNode - if (prop.arg?.type === 4 /* SimpleExpression */) { - let value = (prop.arg as SimpleExpressionNode).content - if (prop.name === 'on') { - value = `on${value}` - } - usingComponent.add(value) - } - } - }) - } - } - }) + vueLoaderOption.compilerOptions.nodeTransforms.unshift(transformMiniNativeTags(data)) + vueLoaderOption.compilerOptions.nodeTransforms.unshift(transformTaroEnv) chain.module .rule('vue')