背景
因为公司的同一个项目要投放不同的市场,不同的市场有不同的需求,所以这就导致从最开始的一份代码衍生出不同的版本,其中有欧洲版、中东版、非洲版等,但是这些代码最初都是从同一份代码里衍生出来的,有同样的部分,也有差异化定制的部分但差异并不大,所以就导致维护起来十分费劲,第一个问题是维护时需频繁切换不同区域分支进行维护,操作流程繁琐;,第二个问题是,当修改或者优化这些代码的相同部分时,其他版本也需要同步。
所以提出了这个"一套代码维护多个版本的整合方案"
分解需求
- 一套代码仓库同时维护多个版本
- 把差异部分提出来,对应着版本。进行维护
- 根据不同的指令自动编译打包不同的版本
- 把功能页面进行模块化切割,方便进行功能模块的快速迁移
- 不同版本需要定制不同的主题色
分析需求提出对应的解决方案
首先是需求一和二,一套代码同时维护多个有差异的版本
这个需求相对好解决,既然我们想要频繁的切换分支,来进行维护,那我们就把代码和合一份来进行维护,相同的功能部分进行共用,而不同的部分在同一级目录下拆分成多个版本文件夹来进行维护
类似于
js
├─common //相同的功能页面
├─Diff // 差异化功能页面
| ├─China //标识不同的地区版本的差异部分
| | ├─diffPage
| ├─America
| | ├─diffPage
如何根据不同的指令自动编译打包不同的版本
既然是要根据编译指令来打包不同版本的包,那我们就得从编译指令下手,我们每次运行或者编译代码时都需要运行我们的编译指令,我们可以在运行脚本时注入一个(版本)变量来告诉我们的编译器,我们需要编译打包的是那个版本的代码
例如这样
在 package.json
中配置脚本:
vite
js
"scripts": {
"dev:china": "vite --mode china" // Vite 项目
"dev:America": "vite --mode America"
"build:china": "vite build --mode china"
"build:America": "vite build --mode America"
}
webpack
js
"dev:china": "webpack serve --env china", // Webpack 项目
"dev:America": "webpack serve --env America",
"build:china": "webpack --mode production --env china",
"build:america":"webpack --mode production --env America"
-
--env <value>
参数Webpack CLI 的
--env
选项可以传递任意环境变量给配置文件,值会被映射到配置函数的env
对象里。例如--env china
会让env === 'china'
-
--mode <development|production>
参数明确指定模式可以自动开启相应的优化:
development
:启用 source map、快速重编译等开发友好功能;production
:开启 Tree Shaking、Terser 压缩等生产优化 citeturn0search1。
注意:如果你的项目需要款平台(Windows 和 Unix)系统,可以使用cross-env
跨平台环境变量设置工具
运行的是时候我们只需要输入我们对应的脚本命名即可,npm run dev:china
,npm run build:America
在代码中获获取变量
vite
--mode china
会让 Vite:
- 将
import.meta.env.MODE === 'china'
js
console.log(import.meta.env.MODE); // 'china'
console.log(import.meta.env.VITE_API); // 来自 .env.china 中的 VITE_API=...
webpack
-
--env china
会让配置函数收到 { china: true };同理 --env america 会变成 { america: true } -
要使用 env,必须将 webpack.config.js 导出改为 函数,而非直接对象:
js
// webpack.config.js
module.exports = (env, argv) => {
// 当执行 `--env china` 时: env = { china: true }
// 当执行 `--env america` 时: env = { america: true }
console.log('env:', env);
// 根据 env 对象的键来确定区域
const region = env.china
? 'china'
: env.america
? 'america'
: 'default';
return {
// 例如,将 region 注入到输出文件名
output: {
filename: `bundle.${region}.js`
},
// 也可将 region 注入到应用代码
plugins: [
new (require('webpack')).DefinePlugin({
'process.env.REGION': JSON.stringify(region)
})
]
// ...其它配置
};
};
同时我们还需要一个路由文件,来告诉我们编译器,该有哪些路由
文件内容用json格式
js
"/login": {
"module": "login",
"name": "login"
},
"/main": {
module: "main",
name: "个人信息"
},
然后我们需要读取这个路由配置文件,用循环遍历的方式来实现我们前端路由所需要的树形结构
js
[
{
path: "/login",
module: "login",
children: []
},
{
path: "/main",
module: "main",
children: []
}
]
然后我们再动态的给路由添加组件
核心映射关系
建立菜单项与路由配置的对应规则:
lua
| 菜单属性 | 路由配置项 | 说明 |
| -------- | ------------ | --------- |
| path | path | 完全匹配 |
| module | component 路径 | 决定加载的视图组件 |
| name | name | 路由命名 |
| children | children | 嵌套路由配置 |
组件加载策略
根据菜单项类型动态导入组件:
**普通模块**:import(../views/Diff/${import.meta.env.MODE}/diffPage.vue)
这样就可以实现我们的一套代码维护多个版本了。
把功能页面进行模块化切割,方便进行功能模块的快速迁移
这里我们需要使用到fs
这个Node.js 的内置模块,我们需要在我们的项目最外出新建一个view文件夹,把我们的模块独立出来,然后再项目的vite.config.js进行代码配置,我们需要把我们项目外面view文件夹里的功能模块映射到我们项目里的对应的view文件夹,外层的view文件里的每个页面模块,里需要一个路由文件,文件内容是我们的路由模块信息包括页面模块下的子路由信息。在读取后结合最外层的路由信息进行路由生成,以及把我们外层的view链接到项目里的vue里进行一一对应,但是要以外层的路由信息为准
md
├─menu.js
├─项目文件
| ├─src
| | ├─view
├─view
| ├─login
| | ├─menu
| | ├─index
| ├─main
| | ├─menu
| | ├─index
不同版本需要定制不同的主题色
我们需要使用CSS自定义属性(变量),动态导入功能,只加载当前需要的厂商主题
定义多个基础样式文件带里面定义不同的颜色变量
css
:root {
/* 默认变量,会被特定主题覆盖 */
--color-primary: #1890ff;
--color-secondary: #52c41a;
--color-background: #ffffff;
--color-text: #333333;
/* 其他变量... */
}
在main.js动态的导入我们的主题色定义文件
js
// 在入口文件如 App.js 中
import './styles/${import.meta.env.MODE}/variables.css';
在功能页面使用颜色主题变量
js
<div style={{ color: 'var(--color-primary)' }}>
总结代码管理方案优势
- 单仓库维护多版本代码
- 95% 以上代码复用率
- 新增版本开发成本降低 70%