背景:之前在cli编译方式下,一直使用.env的方式进行环境变量的加载,非常的方便,而且在部署上也是把环境文件与开发人员分离开的。但是在使用HBuilderX的方式部署时,.env文件是加载不到的,需要重新思考和处理这个环境变量的问题。刚开始,我尝试使用了js做判断,在我看来,不算是个好方法,因为要在main.js中调用,在我看来在编译时使用最佳。所以,自己尝试了一下,也希望能分享和交流。
一、环境变量与编译方式
1.CLI编译
也就是:vue-cli-service的打包方式
我的理解:内核还是webpack,但是额外增加了一些处理,尤其是环境变量的处理。
注意:vue-cli-service只有三种环境,我之前以为可以自定义,其实不可以。
参考官方文档:https://cli.vuejs.org/zh/guide/mode-and-env.html#环境变量
这里明确说了:
想要了解解析环境文件规则的细节,请参考 dotenv。
vue-cli-service使用dotenv解析.env文件之后,使用@vue/cli-service/lib/util/resolveClientEnv.js
const prefixRE = /^VUE_APP_/
module.exports = function resolveClientEnv (options, raw) {
const env = {}
Object.keys(process.env).forEach(key => {
if (prefixRE.test(key) || key === 'NODE_ENV') {
env[key] = process.env[key]
}
})
env.BASE_URL = options.publicPath
if (raw) {
return env
}
for (const key in env) {
env[key] = JSON.stringify(env[key])
}
return {
'process.env': env
}
}
过滤了一部分key,不是APP_VUE*这个开头的全局变量就会被过滤掉,此外还保留了NODE_ENV
通常来说,我们都是在项目的根目录下面执行vue-cli-service,所以默认的环境变量文件.env也是在根目录下面。
2.HBuilderX编译
HBuilderX的编译时,也是使用的webpack。但是HBuilderX的编译,是没有处理根目录下的.env文件的。
二、解决方案
1.使HBuilderX也能自动加载.env文件
在根目录下的vue.config.js(如果没有就创建一个)
const webpack = require('webpack')
const dotenv = require('dotenv')
module.exports = {
chainWebpack: config => {
config
.plugin('define')
.tap(args => {
//console.log(args)
const config = getEnvsByDot()
//console.log(config)
// 将自定义的环境变量塞入配置中
//这里有个格式转化时的字符串的坑
//'"http://127.0.0.1:8088/"' //这种没问题
//'http://127.0.0.1:8088/' //这种就报错了!
Object.keys(config).forEach(key => {
if(typeof config[key] == "string"){
config[key] = '"'+config[key]+'"'
}
args[0]['process.env'][key] = config[key]
})
//args[0]['process.env'] = Object.assign(args[0]['process.env'],config)
console.log(args)
return args
})
}
}
/**
* 从.env中获取
* 使用了dotenv依赖
* 模仿vue-cli-service,不是APP_VUE*这个开头的全局变量就会被过滤掉
*/
function getEnvsByDot(){
const prefixRE = /^VUE_APP_/
let dotEnvs = {}
//1.先加载通用环境变量
const envPath0 = __dirname+'/.env'
const dotEnvsConfig0 = dotenv.config({path:envPath0})
console.log(dotEnvsConfig0)
if(!dotEnvsConfig0.error){
Object.keys(dotEnvsConfig0.parsed).forEach(key => {
if (prefixRE.test(key) ) {
dotEnvs[key] = dotEnvsConfig0.parsed[key]
}
})
}
//2.再加载专属环境变量
let env='local'
if (process.env.NODE_ENV === 'development') {
env='dev'
} else if (process.env.NODE_ENV === 'production') {
env='prod'
}else{
env=process.env.NODE_ENV
}
const envPath = __dirname+'/.env.'+env
const dotEnvsConfig = dotenv.config({path:envPath})
console.log(dotEnvsConfig)
if(!dotEnvsConfig.error){
Object.keys(dotEnvsConfig.parsed).forEach(key => {
if (prefixRE.test(key) ) {
dotEnvs[key] = dotEnvsConfig.parsed[key]
}
})
}
return dotEnvs
}
当然,你也可以不过滤VUE_APP_前缀,自由的使用环境变量,自己注意不要产生与系统自带变量名的冲突就好了。
这个方法,应该足够让.env文件在HBuilderX下的使用与cli一样舒服了。但也带来一个问题,如果你这个项目同时使用cli编译的话,可能会导致.env被加载两次。当然了一般来说,由于两种方式创建的项目的文件夹结构不一样,所以可能你不会遇到既是用cli又是用HBuilderX编译的情况。
2.用yaml文件编译
其实yaml文件类型这几年在配置文件上用得挺多的,好读好写。
同样是在根目录下的vue.config.js(如果没有就创建一个)
const webpack = require('webpack')
const YAML = require('yaml')
const fs = require('fs')
module.exports = {
chainWebpack: config => {
config
.plugin('define')
.tap(args => {
console.log(args)
const config = getEnvsByYaml()
console.log(config)
// 将自定义的环境变量塞入配置中
args[0]['process.env'] = Object.assign(args[0]['process.env'],config)
console.log(args)
return args
})
}
}
/**
* 从env文件中读取配置:
* 1.要获取文件绝对路径,因为相对路径是相对于编译器的,而不是项目的根目录。使用了__dirname。
* 2.使用了yaml格式。
*/
function getEnvsByYaml(){
//1.先加载通用环境变量
const prefixRE = /^VUE_APP_/
let yamlEnvs = {}
let config0 = {}
try{
const envYaml0 = fs.readFileSync(__dirname+'/.env.yaml','utf8')
config0 = YAML.parse(envYaml0)
}catch(e){
console.log(e)
}
// console.log(config0)
Object.keys(config0).forEach(key => {
if (prefixRE.test(key) ) {
yamlEnvs[key] = config0[key]
}
})
//2.再加载专属环境变量
let env='local'
if (process.env.NODE_ENV === 'development') {
env='dev'
} else if (process.env.NODE_ENV === 'production') {
env='prod'
}else{
env=process.env.NODE_ENV
}
let config = {}
try{
const envYaml = fs.readFileSync(__dirname+'/.env.'+env+'.yaml','utf8')
config = YAML.parse(envYaml)
}catch(e){
console.log(e)
}
// console.log(config)
Object.keys(config).forEach(key => {
if (prefixRE.test(key) ) {
yamlEnvs[key] = config[key]
}
})
return yamlEnvs
}
3.同时使用.env和yaml
配置好,爱用哪个就用哪个,也可以同时用,但要确定好优先级。我个人会把yaml的优先级放高一点,因为它更结构化。
方法就是把上面两个的代码一次执行,先下载.env,再加载yaml
6 个评论
要回复文章请先登录或注册
w***@163.com
2***@qq.com
Leo星星 (作者)
2***@qq.com
1***@qq.com
1***@qq.com