Skip to content

Commit

Permalink
feat(transformer): 使用类函数式组件不再要求以 render 开头命名
Browse files Browse the repository at this point in the history
  • Loading branch information
yuche committed Jul 1, 2019
1 parent 6ac53b2 commit ea1e43e
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 1 deletion.
60 changes: 60 additions & 0 deletions packages/taro-transformer-wx/src/class-method-renamer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Visitor, NodePath } from 'babel-traverse'
import * as t from 'babel-types'
import { isDerivedFromThis } from './utils'

function buildMethodName (n: string) {
return `render${n}`
}

export const buildVistor = () => {
const renameMap = new Map<string, string>()

const classMethodRenamer: () => {
visitor: Visitor
} = () => {
return {
visitor: {
JSXElement (path) {
let methodName = ''
const classMethod = path.findParent(p => p.isClassMethod())
if (classMethod && classMethod.isClassMethod() && t.isIdentifier(classMethod.node.key)) {
if (methodName.startsWith('render')) {
return
}
methodName = classMethod.node.key.name
}

const classProp = path.findParent(p => p.isClassProperty())
if (classProp && classProp.isClassProperty()) {
methodName = classProp.node.key.name
}

if (methodName.length > 0 && !methodName.startsWith('render')) {
renameMap.set(methodName, buildMethodName(methodName))
}
},
Identifier (path: NodePath<t.Identifier>) {
const name = path.node.name
if (renameMap.has(name)) {
const memberExpr = path.parentPath
if (memberExpr.isMemberExpression() && memberExpr.parentPath.isCallExpression()) {
const object = memberExpr.get('object')
if (object.isThisExpression()) {
path.replaceWith(t.identifier(buildMethodName(name)))
} else if (object.isIdentifier() && isDerivedFromThis(path.scope, object.node.name)) {
memberExpr.replaceWith(t.memberExpression(
t.thisExpression(),
t.identifier(buildMethodName(name))
))
}
} else if (memberExpr.isCallExpression() && isDerivedFromThis(path.scope, name)) {
path.scope.rename(name, buildMethodName(name))
}
}
}
}
}
}

return classMethodRenamer
}
3 changes: 2 additions & 1 deletion packages/taro-transformer-wx/src/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ class Transformer {
self.methods.set(methodName, classMethodPath)
if (methodName.startsWith('render')) {
if (!isContainJSXElement(classMethodPath)) {
throw codeFrameError(classMethodPath.node, '以 render 开头的类函数必须返回 JSX,否则会导致渲染失败。如果是为了渲染字符串,建议更名。')
throw codeFrameError(classMethodPath.node, '以 render 开头的类函数必须返回 JSX,否则会导致渲染失败。如果是为了渲染字符串,建议更名。\n' +
'以 VSCode 为例:右键点击选择方法名,点击 rename symbol(重命名符号),输入新方法名。')
}
hasRender = true
self.renderJSX.set(methodName, classMethodPath)
Expand Down
2 changes: 2 additions & 0 deletions packages/taro-transformer-wx/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { eslintValidation } from './eslint'
import { TransformOptions } from 'babel-core'
import { functionalComponent, Status } from './functional'
import { isTestEnv } from './env'
import { buildVistor } from './class-method-renamer'

export interface Options {
isRoot?: boolean,
Expand Down Expand Up @@ -54,6 +55,7 @@ export const buildBabelTransformOptions: () => TransformOptions = () => {
require('babel-plugin-transform-do-expressions'),
require('babel-plugin-transform-export-extensions'),
require('babel-plugin-transform-flow-strip-types'),
buildVistor(),
functionalComponent,
[require('babel-plugin-transform-define').default, transformOptions.env]
].concat(process.env.ESLINT === 'false' || transformOptions.isNormal || transformOptions.isTyped ? [] : eslintValidation)
Expand Down
11 changes: 11 additions & 0 deletions packages/taro-transformer-wx/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ export function isDerivedFromProps (scope: Scope, bindingName: string) {
return false
}

export function isDerivedFromThis (scope: Scope, bindingName: string) {
const binding = scope.getBinding(bindingName)
if (binding && binding.path.isVariableDeclarator()) {
const init = binding.path.get('init')
if (init.isThisExpression()) {
return true
}
}
return false
}

export const incrementId = () => {
let id = 0
return () => id++
Expand Down

0 comments on commit ea1e43e

Please sign in to comment.