前端工程化-基于Taro的Web端Monorepo架构改造

本文介绍了如何在使用Taro开发框架的同时,对Monorepo架构进行改造,以便于在Web端支持多端代码复用,包括路由规则、CSSModule样式迁移、环境变量判断、组件和脚本的多端部署,以及Webpack Runner的定制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前端工程化-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() {

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Songlcy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值