diff --git a/packages/taro-transformer-wx/src/index.ts b/packages/taro-transformer-wx/src/index.ts index 7d130c335afa..c350a4729479 100644 --- a/packages/taro-transformer-wx/src/index.ts +++ b/packages/taro-transformer-wx/src/index.ts @@ -1,17 +1,15 @@ import traverse, { Binding, NodePath } from 'babel-traverse' import generate from 'babel-generator' -import * as fs from 'fs' import { prettyPrint } from 'html' import { transform as parse } from 'babel-core' import * as ts from 'typescript' import { Transformer } from './class' -import { setting, findFirstIdentifierFromMemberExpression, isContainJSXElement, codeFrameError, isArrayMapCallExpression, pathResolver } from './utils' +import { setting, findFirstIdentifierFromMemberExpression, isContainJSXElement, codeFrameError, isArrayMapCallExpression, getSuperClassCode } from './utils' import * as t from 'babel-types' import { DEFAULT_Component_SET, INTERNAL_SAFE_GET, TARO_PACKAGE_NAME, REDUX_PACKAGE_NAME, MOBX_PACKAGE_NAME, IMAGE_COMPONENTS, INTERNAL_INLINE_STYLE, THIRD_PARTY_COMPONENTS, INTERNAL_GET_ORIGNAL, setLoopOriginal, GEL_ELEMENT_BY_ID } from './constant' import { Adapters, setAdapter, Adapter } from './adapter' -import { Options, setTransformOptions } from './options' +import { Options, setTransformOptions, babelTransformOptions } from './options' import { get as safeGet } from 'lodash' -import { eslintValidation } from './eslint' const template = require('babel-template') @@ -163,29 +161,7 @@ export default function transform (options: Options): TransformResult { // 导致 Path#getSource|buildCodeFrameError 都无法直接使用 // 原因大概是 babylon.parse 没有生成 File 实例导致 scope 和 path 原型上都没有 `file` // 将来升级到 babel@7 可以直接用 parse 而不是 transform - const ast = parse(code, { - parserOpts: { - sourceType: 'module', - plugins: [ - 'classProperties', - 'jsx', - 'flow', - 'flowComment', - 'trailingFunctionCommas', - 'asyncFunctions', - 'exponentiationOperator', - 'asyncGenerators', - 'objectRestSpread', - 'decorators', - 'dynamicImport' - ] as any[] - }, - plugins: [ - require('babel-plugin-transform-flow-strip-types'), - [require('babel-plugin-transform-define').default, options.env] - ].concat(process.env.ESLINT === 'false' || options.isNormal || options.isTyped ? [] : eslintValidation) - .concat((process.env.NODE_ENV === 'test') ? [] : require('babel-plugin-minify-dead-code')) - }).ast as t.File + const ast = parse(code, babelTransformOptions).ast as t.File if (options.isNormal) { return { ast } as any } @@ -233,28 +209,19 @@ export default function transform (options: Options): TransformResult { }, ClassDeclaration (path) { mainClass = path - const superClass = path.node.superClass - if (t.isIdentifier(superClass)) { - const binding = path.scope.getBinding(superClass.name) - if (binding && binding.kind === 'module') { - const bindingPath = binding.path.parentPath - if (bindingPath.isImportDeclaration()) { - const source = bindingPath.node.source - try { - const p = pathResolver(source.value, options.sourcePath) + (options.isTyped ? '.js' : '.js') - const code = fs.readFileSync(p, 'utf8') - componentProperies = transform({ - isRoot: false, - isApp: false, - code, - isTyped: true, - sourcePath: source.value, - outputPath: source.value - }).componentProperies - } catch (error) { - // - } - } + const superClass = getSuperClassCode(path) + if (superClass) { + try { + componentProperies = transform({ + isRoot: false, + isApp: false, + code: superClass.code, + isTyped: true, + sourcePath: superClass.sourcePath, + outputPath: superClass.sourcePath + }).componentProperies + } catch (error) { + // } } }, diff --git a/packages/taro-transformer-wx/src/options.ts b/packages/taro-transformer-wx/src/options.ts index b4f87fa0e6e4..c26546183a16 100644 --- a/packages/taro-transformer-wx/src/options.ts +++ b/packages/taro-transformer-wx/src/options.ts @@ -1,4 +1,6 @@ import { Adapters } from './adapter' +import { eslintValidation } from './eslint' +import { TransformOptions } from 'babel-core' export interface Options { isRoot?: boolean, @@ -21,3 +23,27 @@ export const setTransformOptions = (options: Options) => { } } } + +export const babelTransformOptions: TransformOptions = { + parserOpts: { + sourceType: 'module', + plugins: [ + 'classProperties', + 'jsx', + 'flow', + 'flowComment', + 'trailingFunctionCommas', + 'asyncFunctions', + 'exponentiationOperator', + 'asyncGenerators', + 'objectRestSpread', + 'decorators', + 'dynamicImport' + ] as any[] + }, + plugins: [ + require('babel-plugin-transform-flow-strip-types'), + [require('babel-plugin-transform-define').default, transformOptions.env] + ].concat(process.env.ESLINT === 'false' || transformOptions.isNormal || transformOptions.isTyped ? [] : eslintValidation) + .concat((process.env.NODE_ENV === 'test') ? [] : require('babel-plugin-minify-dead-code')) +} diff --git a/packages/taro-transformer-wx/src/render.ts b/packages/taro-transformer-wx/src/render.ts index 361c78fb01ee..a817b97d7468 100644 --- a/packages/taro-transformer-wx/src/render.ts +++ b/packages/taro-transformer-wx/src/render.ts @@ -1,5 +1,6 @@ -import { NodePath, Scope, Visitor } from 'babel-traverse' +import traverse, { NodePath, Scope, Visitor } from 'babel-traverse' import * as t from 'babel-types' +import { transform as parse } from 'babel-core' import { newJSXIfAttr, reverseBoolean, @@ -20,7 +21,8 @@ import { isVarName, setParentCondition, isContainJSXElement, - getSlotName + getSlotName, + getSuperClassCode } from './utils' import { difference, get as safeGet, cloneDeep } from 'lodash' import { @@ -40,7 +42,7 @@ import { ALIPAY_BUBBLE_EVENTS } from './constant' import { Adapter, Adapters } from './adapter' -import { transformOptions } from './options' +import { transformOptions, babelTransformOptions } from './options' import generate from 'babel-generator' import { LoopRef } from './interface' const template = require('babel-template') @@ -785,6 +787,7 @@ export class RenderParser { const methodName = findMethodName(value.expression) methodName && this.usedEvents.add(methodName) const method = this.methods.get(methodName) + const classDecl = path.findParent(p => p.isClassDeclaration()) const componentName = jsxElementPath.node.openingElement.name // if (method && t.isIdentifier(method.node.key)) { // this.usedEvents.add(methodName) @@ -797,6 +800,30 @@ export class RenderParser { if (this.methods.has(methodName)) { eventShouldBeCatched = isContainStopPropagation(method) } + if (classDecl && classDecl.isClassDeclaration()) { + const superClass = getSuperClassCode(classDecl) + if (superClass) { + try { + const ast = parse(superClass.code, babelTransformOptions).ast as t.File + traverse(ast, { + ClassMethod (p) { + if (!p.get('key').isIdentifier({ name: methodName })) { + return + } + eventShouldBeCatched = isContainStopPropagation(method) + }, + ClassProperty (p) { + if (!p.get('key').isIdentifier({ name: methodName })) { + return + } + eventShouldBeCatched = isContainStopPropagation(method) + } + }) + } catch (error) { + // + } + } + } if (t.isJSXIdentifier(componentName) && !DEFAULT_Component_SET.has(componentName.name)) { const element = path.parent as t.JSXOpeningElement if (process.env.NODE_ENV !== 'test' && Adapter.type !== Adapters.alipay) { diff --git a/packages/taro-transformer-wx/src/utils.ts b/packages/taro-transformer-wx/src/utils.ts index 819842f6e6f5..f614427af54a 100644 --- a/packages/taro-transformer-wx/src/utils.ts +++ b/packages/taro-transformer-wx/src/utils.ts @@ -2,12 +2,13 @@ import * as t from 'babel-types' import generate from 'babel-generator' import { codeFrameColumns } from '@babel/code-frame' import { NodePath, Scope } from 'babel-traverse' -import { LOOP_STATE } from './constant' +import { LOOP_STATE, TARO_PACKAGE_NAME } from './constant' import { cloneDeep } from 'lodash' import * as fs from 'fs' import * as path from 'path' import { buildBlockElement } from './jsx' import { Adapter } from './adapter' +import { transformOptions } from './options' const template = require('babel-template') export const incrementId = () => { @@ -15,6 +16,32 @@ export const incrementId = () => { return () => id++ } +export function getSuperClassCode (path: NodePath) { + const superClass = path.node.superClass + if (t.isIdentifier(superClass)) { + const binding = path.scope.getBinding(superClass.name) + if (binding && binding.kind === 'module') { + const bindingPath = binding.path.parentPath + if (bindingPath.isImportDeclaration()) { + const source = bindingPath.node.source + if (source.value === TARO_PACKAGE_NAME) { + return + } + try { + const p = pathResolver(source.value, transformOptions.sourcePath) + (transformOptions.isTyped ? '.tsx' : '.js') + const code = fs.readFileSync(p, 'utf8') + return { + code, + sourcePath: source.value + } + } catch (error) { + return + } + } + } + } +} + export function decodeUnicode (s: string) { return unescape(s.replace(/\\(u[0-9a-fA-F]{4})/gm, '%$1')) }