前端工程化-基于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架构改造的主要内容,如果未能解决你的问题,请参考以下文章

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

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

前端工程化- ReactNative整合Taro工程可行性实践方案

前端工程化- ReactNative整合Taro工程可行性实践方案

前端工程化- ReactNative整合Taro工程可行性实践方案

前端工程化-Genebox App 整合 Taro 工程可行性实践方案