前端工程化-基于Taro的Web端Monorepo架构改造
Posted Songlcy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端工程化-基于Taro的Web端Monorepo架构改造相关的知识,希望对你有一定的参考价值。
前端工程化-Genebox小程序端Monorepo架构改造中介绍了在使用Taro框架下,结合yarn workspace + lerna 来改造Monorepo架构的方式和流程,这篇文章与本篇文章内容有很大关联,未阅读的可以先查看前端工程化-Genebox小程序端Monorepo架构改造。
使用Taro框架来进行小程序开发主要因素为实现多端代码的复用。比如 Web、RN等。如何将当前Monorepo架构下的代码编译到Web端呢?
在Web端的改造中,仍然采用小程序改造下的引用不同lerna模块下的页面路由方式规则
主入口路由命名规则:@pkg/pages/login
分包入口路由命名规则:@pkg/list/index
样式
小程序端采用CSSModule的样式方式编写,为了在原有小程序端基础上支持H5的样式编译,需要在项目的config/index下添加如下代码
h5:
publicPath: '/',
staticDirectory: 'static',
postcss:
autoprefixer:
enable: true,
config:
,
,
// css modules 功能开关与相关配置
cssModules:
enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
config:
namingPattern: 'module', // 转换模式,取值为 global/module,下文详细说明
generateScopedName: '[name]__[local]___[hash:base64:5]',
,
,
,
,
跨平台开发
Taro 在编译时提供了一些内置的环境变量来帮助用户做一些特殊处理。
process.env.TARO_ENV:用于判断当前的编译平台类型。取值:weapp / swan / alipay / tt / qq / jd / h5 / rn
可以通过这个变量来区分不同环境,从而使用不同的逻辑。在编译阶段,会移除不属于当前编译类型的代码,只保留当前编译类型下的代码,例如:
1. 在微信小程序和 H5 端分别引用不同资源:
if (process.env.TARO_ENV === 'h5')
else if (process.env.TARO_ENV === 'weapp')
不要解构 process.env 来获取环境变量,请直接以完整书写的方式(process.env.TARO_ENV)来进行使用。
2. 多端组件
├── test.js Test 组件默认的形式,编译到微信小程序、百度小程序和 H5 之外的端使用的版本
├── test.weapp.js Test 组件的微信小程序版本
├── test.swan.js Test 组件的百度小程序版本
└── test.h5.js Test 组件的 H5 版本
3. 多端脚本逻辑
原则就是多端文件对外的接口保持一致。例如微信小程序上使用 Taro.setNavigationBarTitle 来设置页面标题,H5 则是使用 document.title。那么我们可以封装一个 setTitle 方法来抹平两个平台的差异。
set_title.weapp.js
import Taro from '@tarojs/taro'
export default function setTitle (title)
Taro.setNavigationBarTitle(
title
)
set_title.h5.js
export default function setTitle (title)
document.title = title
import setTitle from '../utils/set_title'
setTitle('页面标题')
webpack-runner
在小程序端下,我们通过修改@tarojs/mini-runner目录中的 MiniPlugin.js 源码支持了Monorepo架构下的小程序端代码编译。
为支持在Taro编译到Web端时支持 Lerna 不同模块的引入,同样我们需要通过修改@tarojs/webpack-runner目录中的 MainPlugin.js 源码支持了Monorepo架构下的Web端代码编译。
diff --git a/node_modules/@tarojs/webpack-runner/dist/plugins/MainPlugin.js b/node_modules/@tarojs/webpack-runner/dist/plugins/MainPlugin.js
index ca6f4c5..28f7e72 100644
--- a/node_modules/@tarojs/webpack-runner/dist/plugins/MainPlugin.js
+++ b/node_modules/@tarojs/webpack-runner/dist/plugins/MainPlugin.js
@@ -95,10 +95,15 @@ class MainPlugin
const framework = this.options;
this.pages = new Set([
- ...appPages.map(item => (
- name: item,
- path: helper_1.resolveMainFilePath(path.join(this.options.sourceDir, item), helper_1.FRAMEWORK_EXT_MAP[framework])
- ))
+ ...appPages.map(item =>
+ const pagePath = helper_1.resolveMainFilePath(path.join(this.options.sourceDir, item), helper_1.FRAMEWORK_EXT_MAP[framework]);
+ return
+ name: item.replace('@pkg/', ''),
+ path: pagePath.includes('@pkg')
+ ? pagePath.replace(/projects\\/.*\\/src\\/@pkg\\/pages/, 'packages/pages/src')
+ : pagePath, // 兼容从packages中引用的页面文件
+ ;
+ )
]);
this.getSubPackages();
@@ -123,8 +128,10 @@ class MainPlugin
if (!hasPageIn)
const pagePath = helper_1.resolveMainFilePath(path.join(this.options.sourceDir, pageItem), helper_1.FRAMEWORK_EXT_MAP[framework]);
this.pages.add(
- name: pageItem,
- path: pagePath
+ name: pageItem.replace('@pkg/', ''),
+ path: pagePath.includes('@pkg')
+ ? pagePath.replace(/projects\\/.*\\/src\\/.*\\/@pkg/, `packages/pages/src/$root`) // 分包包名作为寻找路径
+ : pagePath, // 兼容从packages中引用的页面文件
);
// eslint-disable-next-line no-unused-expressions
(_a = this.appConfig.pages) === null || _a === void 0 ? void 0 : _a.push(pageItem);
与小程序端的修改思路大致一样,在解析app.config下的pages时,对命名到文件的路径进行映射。
taro-lodaer
taro-loader中的h5.js文件下主要负责了Web端路由的初始化创建配置和文件之间的引入。同样需要对pages的解析做映射调整,使其能够正确解析Monorepo对应目录下的文件。
diff --git a/node_modules/@tarojs/taro-loader/lib/h5.js b/node_modules/@tarojs/taro-loader/lib/h5.js
index 193413e..e9f6ba5 100644
--- a/node_modules/@tarojs/taro-loader/lib/h5.js
+++ b/node_modules/@tarojs/taro-loader/lib/h5.js
@@ -5,13 +5,30 @@ const path_1 = require("path");
const utils_1 = require("./utils");
function genResource(path, pages, loaderContext)
const stringify = (s) => loader_utils_1.stringifyRequest(loaderContext, s);
+ // 兼容从packages中引用的页面文件
+ let tempPath = path.replace(/@pkg\\//g, ''); // 用于router映射
+ let loadPath = undefined; // 真实文件路径
+ // 此处需要分别处理主包和分包情况
+ const externalModuleTag = path.indexOf("@pkg");
+ if(externalModuleTag > 0)
+ // 分包模块
+ // report/@pkg => pages/src/report
+ loadPath = path_1.join('', ('pages/src/' + path).replace(/@pkg\\//g, ''));
+ else if (externalModuleTag === 0)
+ // 主包模块
+ loadPath = path_1.join('', path.replace(/@pkg\\/pages/g, 'pages/src'));
+ else
+ // 内部工程模块
+ tempPath = path;
+ loadPath = path_1.join(loaderContext.context, tempPath);
+
return `
Object.assign(
- path: '$path',
+ path: '$tempPath',
load: function()
- return import($stringify(path_1.join(loaderContext.context, path)))
+ return import($stringify(loadPath))
- , require($stringify(pages.get(path))).default || ),
+ , require($stringify(pages.get(path.replace(/@pkg\\//g, '')))).default || ),
`;
function default_1()
以上是关于前端工程化-基于Taro的Web端Monorepo架构改造的主要内容,如果未能解决你的问题,请参考以下文章
前端工程化- ReactNative整合Taro工程可行性实践方案
前端工程化- ReactNative整合Taro工程可行性实践方案