小程序跨端框架实践之Remax篇( 四 )

4.3工程化
考虑到我们的小程序是多部门多团队共同合作的项目,不可能让整个公司同时都使用Remax重写原来的业务,那样会有极大不可控风险 。所以Remax只能是在部分业务试用,并且能渐进的切换原有的业务,这就要求我们必须有工程化的方案 。
我们期望的小程序产物的结构如下:

小程序跨端框架实践之Remax篇

文章插图
 
而 Web 端的产物结构如下:
小程序跨端框架实践之Remax篇

文章插图
 
这表示小程序端是依赖原有小程序的,Web端是可以单个业务单独发布的,于是我们在编译过程中给小程序和Web生成两套不同的壳工程 。
编译小程序的过程中拉取壳工程,壳工程的目录结构大致如下:
小程序跨端框架实践之Remax篇

文章插图
 
其中remaxA和remaxB的页面代码是在拉取壳工程的时候动态生成的,我们在壳工程里放入一个配置文件bundle.js,用来描述该壳工程有哪些Remax业务代码:
module.exports= {remaxA: {git:"git@remaxA.git"},remaxB: {gitL "git@remaxB.git"}}在拉取壳工程的同时clonebundle.js所配置的仓库到临时目录packages,此时packages目录如下:
小程序跨端框架实践之Remax篇

文章插图
 
然后根据Remax业务代码里的app.config.js,重新在壳工程生成新的页面和页面配置,其核心逻辑如下:
const template = (projectName, path) => {return`import ${projectName} from'~packages/${projectName}/src/pages${path ?`/${path}`:''}';${projectName}.prototype.onShareAppMessage;${projectName}.prototype.onPageScroll;${projectName}.prototype.onShareTimeline;exportdefault ${projectName};`;}const pageHandler = (projectName) => {const projectPath =`${rootDir}/packages/${projectName}`;shell.cd(projectPath);let conf =require(`${projectPath}/src/app.config.js`);let platConf = conf[platform] || conf;const projectAllPages = [];...// 遍历 pages 和subPackages配置并替换路径pagePath.replace('pages/',`pages/${projectName}/`);...subPackage.root= subPackage.root.replace('pages/',`pages/${projectName}/`);...// 将pages subPackages里所有的页面路径合并到一起let allPages = [...platConf.pages]allPages.push(path.join(subPackage.root, page));// 遍历页面配置生成新的页面allPages.forEach((mapPath) => {const pagePath = path.resolve(rootDir,'src','pages', projectName,`${mapPath}.js`);fse.ensureFileSync(pagePath);const data =https://www.isolves.com/it/cxkf/ydd/xcx/2021-11-05/template(projectName, mapPath);fs.writeFileSync(pagePath, data);});};const complier = () => {...//获取子项目git地址,下载至packages目录下const packagesPath = path.resolve(rootDir,'packages');const subDirs = fs.readdirSync(packagesPath);// 遍历packages根据packages里的app.config.js重新生成合并路径后的页面subDirs.forEach((name) => {let file = fs.statSync(`${packagesPath}/${name}`);if (file.isDirectory()) {pageHandler(name);}});...};module.exports= complier生成的页面代码如下:
import remaxA from'~packages/remaxA/src/pages/index/index';remaxA.prototype.onShareAppMessage;remaxA.prototype.onPageScroll;remaxA.prototype.onShareTimeline;exportdefault remaxA;这个可以修改上面代码中template按需求修改, 这段代码中之所以有类似
remaxA.prototype.onShareAppMessage; 这样的无用代码是因为Remax在编译过程中会收集页面代码里的生命周期函数的关键字,非必需的生命周期在页面代码没有出现的时候,编译产物里也不会有 。
生成的页面路径如下:
小程序跨端框架实践之Remax篇

文章插图
 
同样的,在Web端也会有相似的操作 。我们Web是使用node容器发布的,所以壳工程就弄成了node工程了 。如果使用静态发布那就不需要壳工程了,直接build发布产物就可以了 。
此外,由于小程序的单包size限制的原因,在小程序webpack配置方面需要做一些额外的配置,避免多个Remax业务不共同依赖的代码也打到主包去,导致主包的单包size超出限制,这里给一个例子,仅供参考:
configWebpack:function (options) {let config = options.config;let subpackageGroups = {};Object.keys(projects).forEach((key) => {let packagePages = projectsPages[key];let allPages = packagePages.allPages.map((page) =>`pages/${key}/${page}`);let pages = packagePages.pages;subpackageGroups[`${key}Common`] = {name:`package-${key}-common`,test: (module) =>newRegExp(`[\/]packages[\/]${key}[\/]src[\/]`).test(module.userRequest),chunks:'all',minChunks:2,minSize:0,priority:91,filename:`pages/${key}/package-${key}-common.js`,};});config.optimization.merge({splitChunks: {maxAsyncRequests:100,maxInitialRequests:100,automaticNameDelimiter:'-',enforceSizeThreshold:50000,cacheGroups: {...,...subpackageGroups},},});},


推荐阅读