项目环境一般分为开发环境、测试环境、生产环境,每个环境的接口域名和其他配置、webpack配置可能都是不同的配置,每次打包构建不能总是手动去更改这些配置,我们应当根据打包的环境去动态判断不同环境自动切换配置,尤其是自动化构建部署如jenkins
。
使用node的fs模块实现vue-cli2中根据打包环境动态切换配置
- 配置文件
src/common/config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 部署不同的环境时 需要修改 DBS_ENV 的值
// 0 开发环境 1为测试环境1 2为测试环境2 3为正式环境
var DBS_ENV = 1
var baseUrl = ''
var clientId = ''
swicth (DBS_ENV){
case 0:
baseUrl = 'http://192.168.5.6'
clientId = '90'
break
case 1:
baseUrl = 'http://22.11.33.44'
clientId = '91'
break
case 2:
baseUrl = 'http://22.55.33.99'
clientId = '92'
break
case 3:
baseUrl = 'https://xxx.cn'
clientId = '93'
break
}
export default {baseUrl, clientId}
修改package.json中的npm scripts的打包命令
1
2
3
4
5
6scripts: {
"dev": "node build/dev-server.js", // 开发环境
"build-T1": "node build/build.js", // T1测试环境1
"build-T2": "node build/build.js", // T2测试环境2
"build-pro": "node build/build.js" // pro生产环境
}在build.js中通过打包参数修改src/common/config.js文件中DBS_ENV值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32// 读取配置文件
const fs = require('fs')
let fileContent = ''
const envPath = path.resolve(__dirname, '../src/common/config.js')
try {
fileContent = fs.readFileSync(envPath, 'utf-8')
} catch(error){
console.log(chalk.red(error + '/n'))
process.exit(1)
}
// 获取打包命令判断打包环境参数
const event = process.env.npm_lifecycle_event
let env = 1
switch(event){
case 'build-T1':
env = 1
break
case 'build-T2':
env = 2
break
case 'build-pro':
env = 3
break
}
// 根据打包参数修改配置文件并写入
const text = fileContent.replace(/(var DBS_ENV = \d;)/, `var DBS_ENV = ${env};`)
try {
fs.writeFileSync(envPath, text, 'utf-8')
} catch(error){
console.log(chalk.red(error + '/n'))
process.exit(1)
}打包完成放弃src/common.config.js修改
1
2
3
4
5
6
7
8
9
10let childProcess = require('child_process')
// 在build.js中的打包完成回调中 webpack(webpackconfig, function(){xxx})
// svn 版本管理回退
// childProcess.execSync('svn revert src/common/config.js', function(err, stdout, stdin){
// console.log(chalk.red(err))
// })
// git 版本管理回退
childProcess.execSync('git checkout -- src/common/config.js', function(err, stdout, stdin){
console.log(chalk.red(err))
})
使用cross-env和webpack.DefinePlugin()实现vue-cli2中根据打包环境动态切换配置
cross-env:可以跨平台设置和使用环境变量(process.env)的node模块包
webpack.DefinePlugin(): webpack通过DefinePlugin内置插件将process.env注入到客户端代码中,定义的变量可以在webpack打包范围内任意javascript环境内访问
修改package.json中的npm scripts的打包命令
1
2
3
4
5
6scripts: {
"dev": "node build/dev-server.js", // 开发环境
"build-T1": "cross-env MODE=T1 node build/build.js", // T1测试环境1
"build-T2": "cross-env MODE=T2 node build/build.js", // T2测试环境2
"build-pro": "cross-env MODE=pro node build/build.js" // pro生产环境
}修改config/dev.env.js和config/prod.env.js
1
2
3
4
5
6
7
8
9
10
11// config/dev.env.js
module.export = {
NODE_ENV: '"development"',
MODE: '"dev"' // 全局变量
})
// config/prod.env.js
module.export = {
NODE_ENV: '"production"',
// process.env.MODE 是通过 cross-env 设置的环境变量 即T1或T2或pro
MODE: JSON.stringify(process.env.MODE) // 全局变量字符串需要使用JSON.stringify()
})在webpack.dev.conf.js和webpack.prod.conf.js
通过new webpack.DefinePlugin()
注入到执行环境中使用1
2
3
4
5
6
7
8
9
10
11
12// webpack.dev.conf.js
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
})
]
// webpack.prod.conf.js
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/prod.env')
})
]配置文件动态赋值
src/common/config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 通过cross-env 和 webpack.DefinePlugin() 将process.env注入到执行环境(客户端代码)中使用
// 设置DBS_ENV 的值 0 开发环境 1为测试环境1 2为测试环境2 3为正式环境
var DBS_ENV = ''
var baseUrl = ''
var clientId = ''
const envArr = ['dev', 'T1', 'T2', 'pro']
if (envArr.indexOf(process.env.MODE) > -1) {
DBS_ENV = envArr.indexOf(process.env.MODE)
}
swicth (DBS_ENV){
case 0:
baseUrl = 'http://192.168.5.6'
clientId = '90'
break
case 1:
baseUrl = 'http://22.11.33.44'
clientId = '91'
break
case 2:
baseUrl = 'http://22.55.33.99'
clientId = '92'
break
case 3:
baseUrl = 'https://xxx.cn'
clientId = '93'
break
}
export default {baseUrl, clientId}其他用处
可以通过process.env.MODE设置sourceMap
1
2
3
4
5// config/indx.js
build: {
// 生产环境关闭sourcemap(避免暴露源码) 开发环境和测试环境开启sourcemap便于调试和定位错误
productionSourceMap: process.env.MODE === 'pro' ? false : true
}可以通过process.env.MODE设置仅在开发环境和测试环境引入vconsole
1
2
3
4
5
6
7// main.js 仅在开发环境和测试环境引入vconsole
if (process.env.MODE!=='pro') {
// 不能使用 import vConsole from 'vconsole' 或 import('vconsole') 静态引入 不能放在if里面会报错
// SyntaxError: xxx/main.js 'import' and 'export' may only appear at the top level
let vConsole = require('vconsole') // 使用require引入 可放在if里动态引入
new vConsole()
}
使用process.env.npm_config_arg|process.argv和webpack.DefinePlugin()实现vue-cli2中配置切换
process.env.npm_config_argv或process.argv可以获取npm命令行的参数,动态设置MODE,然后通过DefinePlugin注入
修改package.json中的npm scripts的打包命令
1
2
3
4
5
6
7
8
9scripts: {
"dev": "node build/dev-server.js", // 开发环境
"build": "node build/build.js"
}
// 打包构建 在执行 npm run build 时多加入一个命令行参数
/* npm run build T1 // T1测试环境1
* npm run build T2 // T2测试环境2
* npm run build pro // pro生产环境
*/修改config/dev.env.js和config/prod.env.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// config/dev.env.js
module.export = {
NODE_ENV: '"development"',
MODE: '"dev"' // 全局变量
})
// config/prod.env.js
module.export = {
NODE_ENV: '"production"',
// 方式1
// process.env.npm_config_argv->JSON字符串 获取npm命令行的参数,动态设置MODE
// npm run build pro -> process.env.npm_config_argv -> '{"remain":["pro"], "cooked":["run", "build", "pro"],...}'
// 全局变量字符串需要使用JSON.stringify()
MODE: JSON.stringify(JSON.parse(process.env.npm_config_argv).remain[0])
// 方式2
// npm run build pro -> 使用 process.argv -> ["c:\\xxx\node.exe", "D:\\project\xx\build.js", "pro"]
// MODE: JSON.stringify(process.argv[2])
})其他步骤和上个方法一致
使用自定义loader实现配置环境的切换
package.json中的npm scripts的打包命令
1
2
3
4
5
6scripts: {
"dev": "node build/dev-server.js", // 开发环境
"build-T1": "node build/build.js", // T1测试环境1
"build-T2": "node build/build.js", // T2测试环境2
"build-pro": "node build/build.js" // pro生产环境
}配置文件
src/common/config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var DBS_ENV = 0
var baseUrl = ''
var clientId = ''
swicth (DBS_ENV){
case 0:
baseUrl = 'http://192.168.5.6'
clientId = '90'
break
case 1:
baseUrl = 'http://22.11.33.44'
clientId = '91'
break
case 2:
baseUrl = 'http://22.55.33.99'
clientId = '92'
break
case 3:
baseUrl = 'https://xxx.cn'
clientId = '93'
break
}
export default {baseUrl, clientId}自定义loader替换环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14// loaders/config-loader.js
modules.exports = function (content) {
this.cacheable()
if (process.env.npm_lifesycle_event === 'build-T1') {
content = content.replace(/(var DBS_ENV = \d)/, `var DBS_ENV = 1`)
} else if (process.env.npm_lifesycle_event === 'build-T2'){
content = content.replace(/(var DBS_ENV = \d)/, `var DBS_ENV = 2`)
} else if (process.env.npm_lifesycle_event === 'build-pro'){
content = content.replace(/(var DBS_ENV = \d)/, `var DBS_ENV = 3`)
} else {
content = content.replace(/(var DBS_ENV = \d)/, `var DBS_ENV = 0`)
}
return content
}使用loader
webpack.base.conf.js
1
2
3
4
5
6
7
8module: {
rules: [
{
test: /config\.js$/,
loader: path.resolve('loaders') + '/config-loader'
}
]
}
vue-cli3及以上使用不同的.env文件设置不同的环境配置
vue-cli3.x封装了webpack配置,.env文件中的变量都会被放入当process.env中,我们可以直接在客户端代码中使用process.env的值,该对象可以包含多个键值对,仅支持注入环境配置文件中以VUE_APP_开头的变量,也是通过webpack.DefinePlugin()实现
在根目录下设置不同环境的配置文件
1
2
3
4
5
6
7
8
9// .env.T1 测试环境1配置
VUE_APP_baseUrl = 'http://22.11.33.44'
VUE_APP_clientId = 91
// .env.T2 测试环境2配置
VUE_APP_baseUrl = 'http://22.55.33.99'
VUE_APP_clientId = 92
// .env.prod 生产环境
VUE_APP_baseUrl = 'http://xxx.cn'
VUE_APP_clientId = 93修改package.json中的npm-script脚本的命令
1
2
3
4
5
6
7
8
9"scripts": {
// vue-cli-service build --mode=xxx webpack会去找对应的配置文件 .env.xxx
// 测试环境1 会读取对应配置文件 .env.T1
"build-T1": "vue-cli-service build --mode=T1",
// 测试环境2 会读取对应配置文件 .env.T2
"build-T2": "vue-cli-service build --mode=T2",
// 生产环境 会读取对应配置文件 .env.prod
"build": "vue-cli-service build --mode=prod"
}配置变量的使用
1
2
3
4
5// 客户端代码中 或 vue.config.js 中
// 仅支持注入环境配置文件中以 VUE_APP_ 开头的变量 客户端代码中使用时,都是字符串形式
// VUE_APP_XXX = xxx 都会被webpack.DefinePlugin()设置为 process.env = {VUE_APP_XXX: "xxx" ,...}
config.baseUrl = process.env.VUE_APP_baseUrl
headers.clientId = process.env.VUE_APP_clientId // process.env.VUE_APP_clientId => "93"如果需要在客户端代码中根据打包环境区分某些配置或功能如vconsole
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 方法一
// 可以在 .env.T1 .env.T2 .env.prod 配置文件中 加VUE_APP_MODE = T1或T2或pro
// .env.T1 测试环境1配置
VUE_APP_MODE = T1
VUE_APP_baseUrl = 'http://22.11.33.44'
// .env.T2 测试环境2配置
VUE_APP_MODE = T2
VUE_APP_baseUrl = 'http://22.55.33.99'
// .env.prod 生产环境
VUE_APP_MODE = pro
VUE_APP_baseUrl = 'http://xxx.cn'
// 方法二 不在 .env.xxx 配置文件中写死 可以通过配置 DefinePlugin 注入 MODE
// vue.config.js
moudles.export = {
chainWebpack: config => {
config.plugin('define').tap(args => {
//args => [{'process.env': { NODE_ENV: 'developMent', VUE_APP_base_url: 'xx'}}]
// 通过 process.env.npm_lifecycle_script 去获取 => vue-cli-service build --mode=T1
args[0]['process.env'].VUE_APP_MODE = JSON.stringify(process.env.npm_lifecycle_script.match(/--mode=(.+)(?=\s)/)[1])
return args
})
}
}
// 使用 main.js 仅在开发环境和测试环境引入vconsole
if (process.env.VUE_APP_MODE!=='pro') {
let vConsole = require('vconsole') // 使用require引入 可放在if里动态引入
new vConsole()
}