Leo星星
Leo星星
  • 发布:2022-06-21 13:38
  • 更新:2024-08-27 18:53
  • 阅读:14022

uniapp的环境变量.env

分类:uni-app

背景:之前在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

7 关注 分享
BoredApe 1***@qq.com 老醒 野猪佩奇_ 4***@qq.com HRK_01 w***@163.com

要回复文章请先登录注册

w***@163.com

w***@163.com

这个问题看来是普遍存在啊
2024-08-27 18:53
2***@qq.com

2***@qq.com

ERROR Error loading vue.config.js:
ERROR Error: Cannot find module 'webpack'
Require stack:


报错找不到webpack
2024-03-01 15:17
Leo星星

Leo星星 (作者)

回复 2***@qq.com :
我也是最近用了一个nvue,同样发现了这个问题,然后暂时单独处理了。
2022-11-30 09:02
2***@qq.com

2***@qq.com

遇到一个问题, 在 uvue 文件中读不到 process.env
2022-11-29 21:34
1***@qq.com

1***@qq.com

回复 1***@qq.com :
vue2用的是webpack打包工具,vue3用的是 vite打包工具,需要添加vite.config.js 参考文档:https://vitejs.cn/config/#conditional-config
2022-07-30 09:52
1***@qq.com

1***@qq.com

请教一下,我使用vite+vue3加载不到.env,按教程设置的--mode development没用啊
2022-07-29 18:18