Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(taro-plugin-vue3): sfc template conditional compilation #11482

Open
wants to merge 1 commit into
base: 3.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions packages/taro-plugin-vue3/src/transforms.ts
Original file line number Diff line number Diff line change
@@ -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:
* `<view taro-env="weapp">weapp specific node</view>`
* is basically equal to
* `<view v-if="process.env.TARO_ENV === 'weapp'">weapp specific node</view>`
*/
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<string, any>): 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 */
}
}
}
17 changes: 5 additions & 12 deletions packages/taro-plugin-vue3/src/webpack.h5.ts
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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
]
}
}

Expand Down
45 changes: 3 additions & 42 deletions packages/taro-plugin-vue3/src/webpack.mini.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down Expand Up @@ -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')
Expand Down