diff --git a/config/babel-plugin/oakI18n.js b/config/babel-plugin/oakI18n.js index 839e96d..01cea0d 100644 --- a/config/babel-plugin/oakI18n.js +++ b/config/babel-plugin/oakI18n.js @@ -9,16 +9,37 @@ const Regex = const ModuleDict = {}; +const ReactNativeProjectDict = {}; function parseFileModuleAndNs(cwd, filename) { - const relativePath = relative(cwd, filename); + let cwd2 = cwd; + if (cwd.endsWith('native')) { + // react-native环境,需要重新定位一下项目根目录 + if (ReactNativeProjectDict.hasOwnProperty(cwd)) { + if (ReactNativeProjectDict[cwd]) { + cwd2 = join(cwd, '..'); + } + } + else { + const nodeModulePath = join(cwd, '..', 'node_modules'); + const packageJsonPath = join(cwd, '..', 'package.json'); + if (fs.existsSync(packageJsonPath) && fs.existsSync(nodeModulePath)) { + ReactNativeProjectDict[cwd] = true; + cwd2 = join(cwd, '..'); + } + else { + ReactNativeProjectDict[cwd] = false; + } + } + } + const relativePath = relative(cwd2, filename); if (relativePath.startsWith('node_modules') || relativePath.startsWith('..')) { // 在测试环境下是相对路径 const moduleRelativePath = relativePath .replace(/\\/g, '/') .split('/') .slice(0, 2); - const modulePath = join(cwd, ...moduleRelativePath); + const modulePath = join(cwd2, ...moduleRelativePath); const moduleDir = moduleRelativePath[1]; let moduleName = ModuleDict[moduleDir]; @@ -52,12 +73,12 @@ function parseFileModuleAndNs(cwd, filename) { else { let moduleName = ModuleDict['./']; if (!moduleName) { - const { name } = require(join(cwd, 'package.json')); + const { name } = require(join(cwd2, 'package.json')); ModuleDict['./'] = name; moduleName = name; } - const rel2paths = relative(cwd, filename) + const rel2paths = relative(cwd2, filename) .replace(/\\/g, '/') .split('/'); @@ -123,55 +144,58 @@ module.exports = (babel) => { ) { const { moduleName, ns } = parseFileModuleAndNs(cwd, filename); const arguments = node.arguments; - const [arg0, arg1] = arguments; - assert(arg0); - - if (arg1) { - // 一般是对象,也可能是变量,表达式不予考虑 - if (t.isObjectExpression(arg1)) { - const { properties } = arg1; - const oakNsProp = properties.find( - ele => t.isStringLiteral(ele.key) && ele.key.value === oakNsPropName - ); - if (!oakNsProp) { - properties.push( - t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)), - t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName)) + if (arguments.length < 2) { + // react-native会调用两次,这里要保护一下 + const [arg0, arg1] = arguments; + assert(arg0); + + if (arg1) { + // 一般是对象,也可能是变量,表达式不予考虑 + if (t.isObjectExpression(arg1)) { + const { properties } = arg1; + const oakNsProp = properties.find( + ele => t.isStringLiteral(ele.key) && ele.key.value === oakNsPropName ); + if (!oakNsProp) { + properties.push( + t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)), + t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName)) + ); + } + } + else if (t.isIdentifier(arg1)) { + arguments.splice(1, 1, t.callExpression( + t.memberExpression( + t.identifier('Object'), + t.identifier('assign') + ), + [ + arg1, + t.objectExpression( + [ + t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)), + t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName)) + ] + ) + ] + )); + } + else { + // 不处理,这里似乎会反复调用,不知道为什么 } } - else if (t.isIdentifier(arg1)) { - arguments.splice(1, 1, t.callExpression( - t.memberExpression( - t.identifier('Object'), - t.identifier('assign') - ), - [ - arg1, - t.objectExpression( - [ - t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)), - t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName)) - ] - ) - ] - )); - } else { - // 不处理,这里似乎会反复调用,不知道为什么 + // 如果无参数就构造一个对象传入 + arguments.push( + t.objectExpression( + [ + t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)), + t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName)) + ] + ) + ) } } - else { - // 如果无参数就构造一个对象传入 - arguments.push( - t.objectExpression( - [ - t.objectProperty(t.stringLiteral(oakNsPropName), t.stringLiteral(ns)), - t.objectProperty(t.stringLiteral(oakModulePropName), t.stringLiteral(moduleName)) - ] - ) - ) - } } } }, diff --git a/config/babel-plugin/oakPath.js b/config/babel-plugin/oakPath.js index f0ed5cc..31a3252 100644 --- a/config/babel-plugin/oakPath.js +++ b/config/babel-plugin/oakPath.js @@ -31,12 +31,14 @@ module.exports = (babel) => { const pathProperty = properties.find( ele => t.isObjectProperty(ele) && t.isIdentifier(ele.key) && ele.key.name === 'path' ); + // console.log(filename, 'oakPath'); if (pathProperty) { - console.warn(`${resolvePath}页面的OakPage中还是定义了path,可以删除掉了`); + // react-native的编译器会走两次,这里会被命中 + // console.warn(`${resolvePath}页面的OakPage中还是定义了path,可以删除掉了`); pathProperty.value = t.stringLiteral(relativePath); } else { - properties.push( + properties.unshift( t.objectProperty(t.identifier('path'), t.stringLiteral(relativePath)) ); } diff --git a/config/babel-plugin/oakRenderNative.js b/config/babel-plugin/oakRenderNative.js new file mode 100644 index 0000000..976d11d --- /dev/null +++ b/config/babel-plugin/oakRenderNative.js @@ -0,0 +1,18 @@ +const t = require('@babel/types'); +const { parse } = require('path'); +const { injectGetRender } = require('../utils/injectGetRender'); + +module.exports = (babel) => { + return { + visitor: { + CallExpression(path, state) { + const { cwd, filename } = state; + const { base } = parse(filename); + const node = path.node; + if (['index.ts', 'index.js'].includes(base) && t.isCallExpression(node) && t.isIdentifier(node.callee) && node.callee.name === 'OakComponent') { + injectGetRender(node, cwd, filename, 'native'); + } + }, + }, + }; +}; diff --git a/config/native/transformer.js b/config/native/transformer.js index dc265ce..7d4b647 100644 --- a/config/native/transformer.js +++ b/config/native/transformer.js @@ -22,6 +22,8 @@ const replaceEnvExpressionPlugin = require('./babelEnvPlugin'); const { injectGetRender } = require('../utils/injectGetRender'); const oakPathTsxPlugin = require('../babel-plugin/oakPath'); +const oakRenderNativePlugin = require('../babel-plugin/oakRenderNative'); +const oakI18nPlugin = require('../babel-plugin/oakI18n'); async function renderToCSS({ src, filename, options = {} }) { const { lessOptions = {} } = options; @@ -51,7 +53,7 @@ function transform({ filename, options, plugins, src }) { cwd: options.projectRoot, highlightCode: true, filename, - plugins: plugins.concat([replaceEnvExpressionPlugin, oakPathTsxPlugin]), + plugins: plugins.concat([replaceEnvExpressionPlugin, oakPathTsxPlugin, oakRenderNativePlugin, oakI18nPlugin]), sourceType: "module", // NOTE(EvanBacon): We split the parse/transform steps up to accommodate // Hermes parsing, but this defaults to cloning the AST which increases @@ -71,18 +73,19 @@ function transform({ filename, options, plugins, src }) { const transformResult = transformFromAstSync(sourceAst, src, babelConfig); // 为page和componet下的OakComponent注入getRender函数,去取得同目录下的render.native.tsx - const resultAst = transformResult.ast; - const { base } = path.parse(filename); - if (['index.ts', 'index.js'].includes(base)) { - traverse(resultAst, { - CallExpression(path) { - const node = path.node; - if (t.isIdentifier(node.callee) && node.callee.name === 'OakComponent') { - injectGetRender(node, options.projectRoot, filename, 'native'); - } - } - }) - } + // 改成plugin注入 + // const resultAst = transformResult.ast; + // const { base } = path.parse(filename); + // if (['index.ts', 'index.js'].includes(base)) { + // traverse(resultAst, { + // CallExpression(path) { + // const node = path.node; + // if (t.isIdentifier(node.callee) && node.callee.name === 'OakComponent') { + // injectGetRender(node, options.projectRoot, filename, 'native'); + // } + // } + // }) + // } return { ast: nullthrows(transformResult.ast), diff --git a/config/utils/injectGetRender.js b/config/utils/injectGetRender.js index 97fe130..feb7a71 100644 --- a/config/utils/injectGetRender.js +++ b/config/utils/injectGetRender.js @@ -161,31 +161,36 @@ function injectGetRender(node, projectRoot, filename, env) { */ const arg = node.arguments[0]; assert(t.isObjectExpression(arg)); - const propertyRender = t.objectProperty( - t.identifier('getRender'), - t.functionExpression(null, [], t.blockStatement( - [ - t.variableDeclaration('var', [ - t.variableDeclarator( - t.identifier('oakRenderFn'), - t.memberExpression( - t.callExpression( - t.identifier('require'), - [ - t.stringLiteral('./render') - ] + // react-native的编译器会命中两次 + if (!arg.properties.find( + (ele) => t.isObjectProperty(ele) && t.isIdentifier(ele.key) && ele.key.name === 'getRender' + )) { + const propertyRender = t.objectProperty( + t.identifier('getRender'), + t.functionExpression(null, [], t.blockStatement( + [ + t.variableDeclaration('var', [ + t.variableDeclarator( + t.identifier('oakRenderFn'), + t.memberExpression( + t.callExpression( + t.identifier('require'), + [ + t.stringLiteral('./render') + ] + ), + t.identifier('default') ), - t.identifier('default') - ), + ) + ]), + t.returnStatement( + t.identifier('oakRenderFn') ) - ]), - t.returnStatement( - t.identifier('oakRenderFn') - ) - ] - )) - ); - arg.properties.unshift(propertyRender); + ] + )) + ); + arg.properties.unshift(propertyRender); + } } } diff --git a/template/native/android/build.gradle b/template/native/android/build.gradle index 34ea718..daef6d8 100644 --- a/template/native/android/build.gradle +++ b/template/native/android/build.gradle @@ -11,6 +11,8 @@ buildscript { ndkVersion = "23.1.7779620" } repositories { + maven { url 'https://maven.aliyun.com/repository/google' } + maven { url 'https://maven.aliyun.com/repository/jcenter' } google() mavenCentral() }