一、背景
我们美家移动端业务使用uni-app
实现一码多端,目前上线了APP(包括Android和ios),微信小程序、百度小程序和H5。
从去年6月份以来,随着业务的快速发展,从最初单一产品线,不断孵化出包括逛逛美家、美家工作台APP、美家旺铺、美家直播Live、智能名片多个比较庞大的产品体系。之间存在大量可复用的模块、组件和页面,于是搭建npm
私有仓库,目前接近50
个包,接近400
个版本,周下载量接近140
次,接下来会加快节奏,将更多公共资源整合进来。
uni-app项目引入npm包(即使是分包页面引入),打包微信小程序后,都会统一编译到小程序根目录的 node-modules
文件夹。其中,我们有个自主开发的直播模块,打包后,接近1M
大小,多个项目引入后,导致主包过大,如果粗暴将node-modules设为分包,会影响主包的其他页面。咨询uni-app相关开发人员,得到的回复是:确实不支持npm分包,处理起来会比较复杂,暂时也没有支持计划。为了满足业务需要,只能自力更生!
二、思路
将需要分包的npm包复制一份到分包目录,改成相对路径引入,这样打包之后,引入的npm包就会在分包里面。很明显,这种事情不能靠手工去处理。uni-app底层是通过webpack
打包,可以通过开发插件解决问题。想到两种方案:
-
添加JSON配置文件,手动维护
需要分包的npm包和引用文件路径
的映射关系,分包页面通过相对路径引入npm包,在webpack
解析模块前,比如beforeRun
阶段,根据配置,将npm包自动copy到引用文件所在的目录。 -
DSL阶段
:约定一种引入分包的import
语法。AST
阶段:添加Babel模块解析器解析分包语法,再将解析的npm包copy到引用文件所在目录,同时模块路径改成相对路径。
三、对比
- 方案1,配置繁琐,而且引用和配置存在松散耦合关系,随着项目的不断迭代,容易导致JSON配置文件越来越臃肿和冗余,不好维护。
- 方案2,语法层控制,不存在松散耦合,是否需要分包,切换语法就好,添加删除引入,不需要修改配置,不会出现历史包袱问题。
四、实现
本着约定大于配置
的原则,最终我们采用方案2。
约定
分包import
语法:
import module from "subpack:module"
模块解析器
基于babel-plugin-module-resolver模块解析插件进行扩展。
1.安装依赖
npm install babel-plugin-module-resolver --save-dev
2.配置babel.config.js
1、通过cli构建的项目:在项目根目录下。
2、通过HBuilderX创建的项目:安装目录下HBuilderX/plugins/uniapp-cli/babel.config.js
const fs = require('fs-extra');
const path = require("path");
const plugins = [
["module-resolver", {
"root": ["./"],
resolvePath(sourcePath, currentFile, opts) {
// 解析模块路径
const [scope,pakageName] = sourcePath.split(":");
// 判断是否为分包模块
if(scope == "subpack"){
// 如果是,将npm包copy到当前引入文件所在目录
fs.copySync(`./node_modules/${pakageName}/`, `${path.dirname(currentFile)}/${pakageName}`);
// 改成相对路径引用
sourcePath = `./${pakageName}`
}
return sourcePath;
}
}]
]
...
五、写在最后
通过上述方案,暂时可以满足我们目前的业务需求。还存在两个问题:
- 通过HBuilderX创建的项目,根目录配置
babel.config.js
无效,需要去安装目录下手动配置,版本升级,会被覆盖。 - 约定分包引入的npm包,其引入的npm包,是否需要一起做分包处理,目前我们是没做的,还在权衡。
如果大家有其他思路,欢迎一起沟通讨论。最后感谢一下优秀的Dcloud团队
!
2 个评论
要回复文章请先登录或注册
梨涡浅笑
9***@qq.com