应用场景
在 toB 端业务中, 同样的产品, 客户多多少少会要求一些定制化. 从皮肤, 图片, 到一些小的功能的差异.
前端总是冲在最前面需要改的. 如果改动不大的话, 拉个分支有增加了维护的成本, 分支拉多了, 如果主干有一个问题相当于 copy 了 n 份, 那个滋味简直不要太酸爽. 那么, 是否可以一套代码支持多个项目呢?
前段时间, 接了一个需求, 技术选型是 vue, 用 vue-cli 搭建的. 一套代码需要支持 10 几家客户, 每家的皮肤, 功能都有一些小的差异, 主体流程大致是一样的. 在这个场景下研究了一下解决方案.
思路
总体的思路模块化, 然后在编译的时候根据输入命令直接组装不同的模块, 打包出我们需要的页面.
这个地方就有两个问题:
1. 如何划分页面, 控制组件的颗粒度?
2. 如何差异化编译?
项目结构
同样一个页面, 有相同的部分, 也有一些不一样的部分. vue 本身的组件化思想很容易让我们想到把页面拆分成组件, 然后把公共的提取出来, 差异化的分别处理.
项目总体结构
menu.png
build
build 结构中主要是 webpack 的一些脚本配置
config
config 文件主要是项目相关配置, 我们常用的就是当端口冲突时配置监听端口, 打包输出路径及命名等
src
源码文件.
assets: 静态资源, 一般放图片, 样式等
less: 样式文件, 这里分主题处理了
pages: 页面文件
router: 路由
util: 工具类
components
component.png
文件夹中是各个项目的自有的组件. components 目录下的是公共的组件
static
静态资源, 不会被 webpack 编译. 一般放一下外部引用文件.
webpack 打包配置
如何差异化编译?
1.cross-env 使用环境变量. 在编译阶段, 根据编译传入的变量不同, 编译不同的组件.
首先, 要改的是 package.json 的文件
- "scripts": {
- "dev:gx": "cross-env BRANCH_ENV=gx node build/dev-server.js",
- "build:gx": "cross-env BRANCH_ENV=gx node build/build.js"
- },
这个时候我们编译的时候输入对应的命令 就可以传入相应的环境变量.
eg:npm run dev:gx 会传入 BRANCH_ENV=gx.
2. 把 config/prod.env.js 中注入这个环境变量
- module.exports = {
- NODE_ENV: '"production"',
- API_PATH:'""',
- BRANCH_ENV: JSON.stringify(process.env.BRANCH_ENV) || '"base"',
- ignoreCsrfToken:'"false"'
- }
- 3.webpack.base.conf.js
- resolve: {
- extensions: ['','.js','.vue','.json'],
- fallback: [path.join(__dirname, '../node_modules')],
- alias: {
- 'vue$': 'vue/dist/vue.common.js',
- 'src': path.resolve(__dirname, '../src'),
- 'assets': path.resolve(__dirname, '../src/assets/images/'+process.env.BRANCH_ENV),
- 'components': path.resolve(__dirname, '../src/components'),
- 'componentsDif': path.resolve(__dirname, '../src/components/'+process.env.BRANCH_ENV),
- }
- },
可以看的出, 我们把编译命令注入的环境变量在引入别名的时候用上了. 比如说, 假设我输入的编译命令是
npm run build:gx
这个时候
- 'assets': path.resolve(__dirname, '../src/assets/images/'+process.env.BRANCH_ENV)
- // 等同于
- 'assets': path.resolve(__dirname, '../src/assets/images/gx')
页面引用
1. 图片引用
- <img class="icon-arrow" src="~assets/arrow.png">
- // 根据编译命令. 图片引用的是 src/assets/images/gx/arrow.png
- background: url(~assets/btn_1.png) no-repeat;
ps: 用别名的时候记得要加上~ 号
组价引用
- // 公共组件
- import ruleTitle from 'components/RuleTitle'
- // 差异化组件
- import ruleContent from 'componentsDif/RuleContent'
总结
总而言之, 核心思想就是跟进编译命令传入环境变量, 利用环境变量和别名的配置来差异化打包. 比较难的是如何控制组件的颗粒度, 如何拆分组件, 这个需要跟据需求的不同来实际定制.
来源: http://www.jianshu.com/p/c06bda4e9b86