Vue CLI中模式与环境变量的深入详解


Posted in Vue.js onMay 30, 2021

前言

在实际项目的开发中,我们一般会经历项目的开发阶段、测试阶段和最终上线阶段,每一个阶段对于项目代码的要求可能都不尽相同,那么我们如何能够游刃有余的在不同阶段下使我们的项目呈现不同的效果,使用不同的功能呢?
这里就需要引入环境的概念。官方文档中模式和环境变量说明

一般一个项目都会有以下 3 种环境:

  • 开发环境(开发阶段,本地开发版本,一般会使用一些调试工具或额外的辅助功能);
  • 测试环境(测试阶段,上线前版本,除了一些 bug 的修复,基本不会和上线版本有很大差别);
  • 生产环境(上线阶段,正式对外发布的版本,一般会进行优化,关掉错误报告);

作为一名开发人员,我们可能需要针对每一种环境编写一些不同的代码并且保证这些代码运行在正确的环境中,那么我们应该如何在代码中判断项目所处的环境同时执行不同的代码呢?这就需要我们进行正确的环境配置和管理。

1. 配置文件

正确的配置环境首先需要我们认识不同环境配置之间的关系,如图所示:

Vue CLI中模式与环境变量的深入详解

我们从上图中可以了解到每一个环境其实有其不同的配置,同时它们也存在着交集部分,交集便是它们都共有的配置项,那么在 Vue 中我们应该如何处理呢?

我们可以在根目录下创建以下形式的文件进行不同环境下变量的配置:

.env                # 在所有的环境中被载入
.env.local          # 在所有的环境中被载入,但会被 git 忽略
.env.[mode]         # 只在指定的模式中被载入, 如:.env.development,.env.production 
.env.[mode].local   # 只在指定的模式中被载入,但会被 git 忽略

Vue CLI中模式与环境变量的深入详解

Vue CLI中模式与环境变量的深入详解

如:创建一个名为 .env.development 的文件,该文件表明其只在 development 环境下被加载。

在这个文件中,我们可以配置如下键值对的变量:

# 开发环境配置
NODE_ENV=development
VUE_APP_API_BASE_URL=https://www.baidu.com/

这时怎么在 vue.config.js 中访问这些变量呢?使用 process.env.[name] 进行访问就可以了。

// vue.config.js
console.log(process.env.NODE_ENV); // development(在终端输出)

当运行 npm run serve 命令后会发现输出的是 development,因为 vue-cli-service serve 命令 默认设置的环境就是 development。

如果我们需要修改,可将 package.json 中的 serve 脚本的命令为:

// package.json
"scripts": {
  "serve": "vue-cli-service serve --mode stage",
},

?mode stage 其实就是修改了 webpack 4 中的 mode 配置项为 stage,同时其会读取对应 .env.[model] 文件下的配置。
如果没找到对应配置文件,其会使用默认环境 development,同样 vue-cli-service build 会使用默认环境 production。

如果再创建一个 .env 的文件,再次配置重复的变量,但是值不同。

# 环境配置
NODE_ENV=ENV
VUE_APP_API_BASE_URL=http://www.soso.com/

因为 .env 文件会被所有环境加载,即公共配置,那么最终运行 vue-cli-service serve 打印出来的是哪个呢?

答案是 development。

但是如果是 .env.development.local 文件中配置成上方这样,答案便是 ENV。

所以 .env.[mode].local 会覆盖 .env.[mode] 下的相同配置。

同理 .env.local 会覆盖 .env 下的相同配置。

由此可以得出结论,相同配置项的权重:.env.[mode].local > .env.[mode] > .env.local > .env
注意: 除了相同配置项权重大的覆盖小的,不同配置项它们会进行合并操作,类似于 Javascript 中的 Object.assign 的用法。

2. 环境注入

通过上述配置文件的创建,我们成功地使用命令行的形式对项目环境进行了设置并可以自由切换,但是注意:在 Vue 的前端代码中打印出的 process.env 与 vue.config.js 中输出的可能是不一样的,这需要普及一个知识点:webpack 通过 DefinePlugin 内置插件将 process.env 注入到客户端代码中。

// webpack 配置
{
    ...
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify(process.env.NODE_ENV)
            }
        }),
    ], 
    ...
}

由于 vue-cli 3.x 封装的 webpack 配置中已经帮我们完成了这个功能,所以可以直接在客户端代码中打印出 process.env 的值,该对象可以包含多个键值对,也就是说可以注入多个值,但是 经过 vue-cli 封装后仅支持注入环境配置文件中以 VUE_APP_ 开头的变量,而 NODE_ENV 和 BASE_URL 这两个特殊变量除外。

比如:在权重最高的 .env.development.local 文件中写入:

# 开发环境配置
NODE_ENV=developmentLocal
VUE_APP_API_BASE_URL=https://www.baidu.com/
NAME=javaScript

然后我们尝试在 vue.config.js 中打印 process.env,终端输出:

{
    ...
    npm_config_ignore_scripts: '',
    npm_config_version_git_sign: '',
    npm_config_ignore_optional: '',
    npm_config_init_version: '1.0.0',
    npm_package_dependencies_vue_router: '^3.0.1',
    npm_config_version_tag_prefix: 'v',
    npm_node_execpath: '/usr/local/bin/node',
    NODE_ENV: 'developmentLocal',
    VUE_APP_API_BASE_URL: 'https://www.baidu.com/',
    NAME: 'javaScript',
    BABEL_ENV: 'development',
    ...
}

可以看到输出内容除了环境配置中的变量外还包含了很多 npm 的信息,但在入口文件 main.js 中打印会发现输出:

{
  BASE_URL: "/",
  NODE_ENV: "developmentLocal",
  VUE_APP_API_BASE_URL: "https://www.baidu.com/",
}

可见注入时过滤调了非 VUE_APP_ 开头的变量,其中多出的 BASE_URL 为你在 vue.config.js 设置的值,默认为 /,其在环境配置文件中设置无效。

Vue CLI中模式与环境变量的深入详解

3. 额外配置

以上我们通过新建配置文件的方式为项目不同环境配置不同的变量值,能够实现项目基本的环境管理,但是 .env 这样的配置文件中的参数目前只支持静态值,无法使用动态参数,在某些情况下无法实现特定需求。

这时候可以在根目录下新建 config 文件夹用于存放一些额外的配置文件。

/* 配置文件 index.js */
 
// 公共变量
const com = {
  IP: JSON.stringify('xxx')
};

module.exports = {
  // 开发环境变量
  dev: {
    env: {
      TYPE: JSON.stringify('dev'),
      ...com
    }
  },
  // 生产环境变量
  build: {
    env: {
      TYPE: JSON.stringify('prod'),
      ...com
    }
  }
}

以上代码把环境变量分为了公共变量、开发环境变量和生产环境变量,当然这些变量可能是动态的,比如用户的 ip 等。
现在我们要在 vue.config.js 里注入这些变量,可以使用 chainWebpack 修改 DefinePlugin 中的值:

/* vue.config.js */
const configs = require('./config');
 
// 用于做相应的 merge 处理
const merge = require('webpack-merge');
 
// 根据环境判断使用哪份配置
const cfg = process.env.NODE_ENV === 'production' ? configs.build.env : configs.dev.env;
module.exports = {
  chainWebpack: config => {
    config.plugin('define').tap(args => {
      let name = 'process.env';
      // 使用 merge 保证原始值不变
      args[0][name] = merge(args[0][name], cfg);
      return args
    })
  },	
}

最后可以在客户端成功打印出包含动态配置的对象:

{
  BASE_URL: "/",
  IP: "xxx",
  NODE_ENV: "developmentLocal",
  TYPE: "dev",
  VUE_APP_API_BASE_URL: "https://www.baidu.com/",
}

4. 实际场景

使用 process.env.xxx 来访问属性

<script>
export default {
  data() { 
    return {
      BASEURL:process.env,
    } 
  },  
  mounted(){
 	console.log(this.BASEURL.VUE_APP_API_BASE_URL) // https://www.baidu.com/
  }
}
</script>
// 创建 axios 实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  timeout: 5000
})

结语

环境的配置和管理对于项目的构建起到了至关重要的作用,通过给项目配置不同的环境不仅可以增加开发的灵活性、提高程序的拓展性,同时也有助于帮助我们去了解并分析项目在不同环境下的运行机制,建立全局观念。

到此这篇关于Vue CLI中模式与环境变量的文章就介绍到这了,更多相关Vue CLI模式与环境变量内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
在Vue中使用Echarts可视化库的完整步骤记录
Nov 18 Vue.js
解决vue页面刷新,数据丢失的问题
Nov 24 Vue.js
如何实现vue的tree组件
Dec 03 Vue.js
详解Vue的异步更新实现原理
Dec 22 Vue.js
vue 动态生成拓扑图的示例
Jan 03 Vue.js
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 Vue.js
vue实现拖拽进度条
Mar 01 Vue.js
vue实现简单数据双向绑定
Apr 28 Vue.js
vue基于Teleport实现Modal组件
May 31 Vue.js
vue @click.native 绑定原生点击事件
Apr 22 Vue.js
详解Vue3使用axios的配置教程
Apr 29 Vue.js
vue @ ~ 相对路径 路径别名设置方式
Jun 05 Vue.js
springboot+VUE实现登录注册
May 27 #Vue.js
vue+springboot实现登录验证码
vue+spring boot实现校验码功能
May 27 #Vue.js
vue-cropper组件实现图片切割上传
May 27 #Vue.js
vue-cropper插件实现图片截取上传组件封装
May 27 #Vue.js
HTML+VUE分页实现炫酷物联网大屏功能
Vue实现动态查询规则生成组件
You might like
一个改进的UBB类
2006/10/09 PHP
用PHP实现ODBC数据分页显示一例
2006/10/09 PHP
PHP内存缓存Memcached类实例
2014/12/08 PHP
深入解析PHP的Laravel框架中的event事件操作
2016/03/21 PHP
jquery清空表单数据示例分享
2014/02/13 Javascript
基于javascript、ajax、memcache和PHP实现的简易在线聊天室
2015/02/03 Javascript
使用jQuery制作遮罩层弹出效果的极简实例分享
2016/05/12 Javascript
JavaScript事件学习小结(三)js事件对象
2016/06/09 Javascript
JavaScript校验Number(4,1)格式的数字实例代码
2017/03/13 Javascript
使用JavaScript实现表格编辑器(实例讲解)
2017/08/02 Javascript
用jquery获取select标签中选中的option值及文本的示例
2018/01/25 jQuery
Vue中使用create-keyframe-animation与动画钩子完成复杂动画
2019/04/09 Javascript
JS实现查找数组中对象的属性值是否存在示例
2019/05/24 Javascript
原生javascript自定义input[type=radio]效果示例
2019/08/27 Javascript
Node Express用法详解【安装、使用、路由、中间件、模板引擎等】
2020/05/13 Javascript
JS获取一个字符串中指定字符串第n次出现的位置
2021/02/10 Javascript
[03:57]2016完美“圣”典风云人物:rOtk专访
2016/12/09 DOTA
python命令行参数解析OptionParser类用法实例
2014/10/09 Python
Python文件的读写和异常代码示例
2017/10/31 Python
在pycharm 中添加运行参数的操作方法
2019/01/19 Python
anaconda如何查看并管理python环境
2019/07/05 Python
利用pyshp包给shapefile文件添加字段的实例
2019/12/06 Python
基于Python+QT的gui程序开发实现
2020/07/03 Python
详解Tensorflow不同版本要求与CUDA及CUDNN版本对应关系
2020/08/04 Python
Python 连接 MySQL 的几种方法
2020/09/09 Python
Python xlwings插入Excel图片的实现方法
2021/02/26 Python
俄罗斯眼镜网: optikaworld
2016/07/31 全球购物
金宝贝童装官网:Gymboree
2016/08/31 全球购物
应用数学专业求职信
2014/03/14 职场文书
房屋租赁协议书
2014/04/10 职场文书
竞选大队长演讲稿
2014/04/29 职场文书
师范毕业生求职信
2014/07/11 职场文书
公司试用期员工自我评价
2014/09/17 职场文书
婚宴祝酒词大全
2015/08/10 职场文书
MySQL 数据丢失排查案例
2021/05/08 MySQL
JavaScript高级程序设计之基本引用类型
2021/11/17 Javascript