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

fix(taro-webpack5-runner): 修复webpack5中vue通过render函数渲染组件,无法在微信小程序中渲染问题 #13749

Merged
merged 8 commits into from
Jun 8, 2023
21 changes: 18 additions & 3 deletions packages/taro-mini-runner/src/plugins/TaroNormalModulesPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ const walk = require('acorn-walk')

const PLUGIN_NAME = 'TaroNormalModulesPlugin'


function isRenderNode (node, ancestors): boolean {
let renderFn
const hasRenderMethod = ancestors.some((ancestor) => {
if (ancestor.type === 'FunctionExpression' && ancestor?.id?.name === 'render') {
renderFn = ancestor.params[0]?.name
return true
} else {
return false
}
})
return hasRenderMethod && node.callee.name === renderFn
}

export default class TaroNormalModulesPlugin {
onParseCreateElement: Func | undefined

Expand All @@ -29,8 +43,8 @@ export default class TaroNormalModulesPlugin {
// react 的第三方组件支持
normalModuleFactory.hooks.parser.for('javascript/auto').tap(PLUGIN_NAME, (parser) => {
parser.hooks.program.tap(PLUGIN_NAME, (ast) => {
walk.simple(ast, {
CallExpression: node => {
walk.ancestor(ast, {
CallExpression: (node, ancestors) => {
const callee = node.callee
if (callee.type === 'MemberExpression') {
if (callee.property.name !== 'createElement') {
Expand All @@ -46,7 +60,8 @@ export default class TaroNormalModulesPlugin {
!(nameOfCallee && nameOfCallee.includes('createBlock')) &&
!(nameOfCallee && nameOfCallee.includes('createElementVNode')) &&
!(nameOfCallee && nameOfCallee.includes('createElementBlock')) &&
!(nameOfCallee && nameOfCallee.includes('resolveComponent')) // 收集使用解析函数的组件名称
!(nameOfCallee && nameOfCallee.includes('resolveComponent')) && // 收集使用解析函数的组件名称
!isRenderNode(node, ancestors)
// TODO: 兼容 vue 2.0 渲染函数及 JSX,函数名 h 与 _c 在压缩后太常见,需要做更多限制后才能兼容
// nameOfCallee !== 'h' && nameOfCallee !== '_c'
) {
Expand Down
13 changes: 13 additions & 0 deletions packages/taro-plugin-vue2/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ import { mergeWith } from 'lodash'
import { getLoaderMeta } from './loader-meta'

import type { IPluginContext } from '@tarojs/service'
import type { IComponentConfig } from '@tarojs/taro/types/compile/hooks'

export const CUSTOM_WRAPPER = 'custom-wrapper'


interface OnParseCreateElementArgs {
nodeName: string
componentConfig: IComponentConfig
}

export default (ctx: IPluginContext) => {
const { framework } = ctx.initialConfig
if (framework !== 'vue') return
Expand Down Expand Up @@ -51,6 +58,12 @@ export default (ctx: IPluginContext) => {
prebundleOptions.exclude ||= []
}
})

ctx.onParseCreateElement(({ nodeName, componentConfig }: OnParseCreateElementArgs) => {
if (capitalize(toCamelCase(nodeName)) in internalComponents) {
componentConfig.includes.add(nodeName)
}
})
}

function getVueLoaderPath (): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ const walk = require('acorn-walk')

const PLUGIN_NAME = 'TaroNormalModulesPlugin'

function isRenderNode (node, ancestors): boolean {
let renderFn
const hasRenderMethod = ancestors.some((ancestor) => {
if (ancestor.type === 'FunctionExpression' && ancestor?.id?.name === 'render') {
Chen-jj marked this conversation as resolved.
Show resolved Hide resolved
renderFn = ancestor.params[0]?.name
return true
} else {
return false
}
})
return hasRenderMethod && node.callee.name === renderFn
}

export default class TaroNormalModulesPlugin {
onParseCreateElement: Func | undefined

Expand All @@ -31,8 +44,8 @@ export default class TaroNormalModulesPlugin {
// react 的第三方组件支持
normalModuleFactory.hooks.parser.for('javascript/auto').tap(PLUGIN_NAME, (parser) => {
parser.hooks.program.tap(PLUGIN_NAME, (ast) => {
walk.simple(ast, {
CallExpression: node => {
walk.ancestor(ast, {
CallExpression: (node, ancestors) => {
const callee = node.callee
if (callee.type === 'MemberExpression') {
if (callee.property.name !== 'createElement') {
Expand All @@ -48,7 +61,8 @@ export default class TaroNormalModulesPlugin {
!(nameOfCallee && nameOfCallee.includes('createBlock')) &&
!(nameOfCallee && nameOfCallee.includes('createElementVNode')) &&
!(nameOfCallee && nameOfCallee.includes('createElementBlock')) &&
!(nameOfCallee && nameOfCallee.includes('resolveComponent')) // 收集使用解析函数的组件名称
!(nameOfCallee && nameOfCallee.includes('resolveComponent')) && // 收集使用解析函数的组件名称
!isRenderNode(node, ancestors)
// TODO: 兼容 vue 2.0 渲染函数及 JSX,函数名 h 与 _c 在压缩后太常见,需要做更多限制后才能兼容
// nameOfCallee !== 'h' && nameOfCallee !== '_c'
) {
Expand Down Expand Up @@ -76,7 +90,7 @@ export default class TaroNormalModulesPlugin {
prop.properties
.filter(p => p.type === 'Property' && p.key.type === 'Identifier' && p.key.name !== 'children' && p.key.name !== 'id')
.forEach(p => attrs.add(p.key.name))
}
},
})
})
})
Expand Down