vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue env文件作用和配置

Vue项目中env文件的作用和配置详解

作者:Nejosi_念旧

Vue项目中,.env文件是运行项目时的环境配置文件,但是在实际开发过程中,有本地开发环境、测试环境、生产环境等,不同环境对应的配置会不一样,本文给大家介绍了Vue项目中env文件的作用和配置,需要的朋友可以参考下

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

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

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

1. 配置文件

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

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

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

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

比如我们创建一个名为 .env.stage 的文件,该文件表明其只在 stage 环境下被加载,在这个文件中,我们可以配置如下键值对的变量:

NODE_ENV=stage
VUE_APP_TITLE=stage mode

注意:环境变量的名称必须以 VUE_APP_ 开头

这时候我们怎么在 vue.config.js 中访问这些变量呢?很简单,使用 process.env.[name] 进行访问就可以了,比如:

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

当你运行 yarn serve 命令后会发现输出的是 development,因为 vue-cli-service serve 命令默认设置的环境是 development,你需要修改 package.json 中的 serve 脚本的命令为:

"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=staging
 VUE_APP_TITLE=staging mode
 VUE_APP_NAME=project

因为 .env 文件会被所有环境加载,即公共配置,那么最终我们运行 vue-cli-service serve 打印出来的是哪个呢?答案是 stage,但是如果是 .env.stage.local 文件中配置成上方这样,答案便是 staging,所以 .env.[mode].local 会覆盖 .env.[mode] 下的相同配置。同理 .env.local 会覆盖 .env 下的相同配置。

由此可以得出结论,相同配置项的权重:

 .env.[mode].local > .env.[mode] > .env.local > .env 

如果看完上例还未理解优先级和覆盖规则的关系的话,这里有一个更容易理解的例子:

当你运行 vue-cli-service serve 命令时,Vue CLI 会根据你指定的模式(如 --mode stage)加载不同的环境变量文件。以下是常见的环境变量文件及其优先级:

  1. .env.local: 该文件用于本地环境的配置,优先级最高,适用于所有模式。如果在该文件中定义了环境变量,它们将覆盖其他文件中的同名变量。

  2. .env.[mode].local: 这是特定于某个模式的本地配置文件,如 .env.stage.local。它的优先级仅次于 .env.local,并且可以覆盖 .env.[mode] 中的相同变量。

  3. .env.[mode]: 这是特定于某个模式的环境变量文件,例如 .env.stage。它包含该模式下的公共配置。

  4. .env: 这是一个通用的环境变量文件,适用于所有模式。它的优先级最低。

实际效果

示例

假设你的文件结构如下:

project-root/
│
├── .env
│   VUE_APP_TITLE=My Vue App
│
├── .env.stage
│   VUE_APP_TITLE=Stage App
│
├── .env.stage.local
│   VUE_APP_TITLE=Staging

执行命令

当你运行以下命令时:

npm run serve -- --mode stage

最终结果

需要注意的是,除了相同配置项权重大的覆盖小的,不同配置项它们会进行合并操作,类似于 Javascript 中的 Object.assign 的用法。

拓展1

1.为什么使用 VUE_APP_ 前缀?

在 Vue.js 中,环境变量以 VUE_APP_ 前缀开头是特别重要的。这是因为 Vue CLI 仅会将以 VUE_APP_ 开头的环境变量暴露给客户端的 JavaScript 代码。它的主要目的是为了区分环境变量,使得这些变量能够被 Vue 应用程序访问,同时避免与其他环境变量的冲突

1. 明确标识

2. 隔离命名空间

3. 安全性

4. 一致性

5. 便于配置

这里用一个例子说明:

在一个 Vue 应用中,你可能会看到以下环境变量的定义:

# .env.development
VUE_APP_TITLE=My Development App
VUE_APP_API_URL=https://dev.api.example.com
 
# .env.production
VUE_APP_TITLE=My Production App
VUE_APP_API_URL=https://api.example.com

这些变量在 Vue 组件中可以直接使用,比如:

console.log(process.env.VUE_APP_TITLE); // 输出 "My Development App" 或 "My Production App"
console.log(process.env.VUE_APP_API_URL); // 输出相应环境下的 API URL

2.APP 后缀的作用

1. 明确变量的作用

2. 减少命名冲突

3. 提高可维护性

4. 便于环境切换

5. 文档化和标准化

6. 版本控制和部署

示例:

假设你正在开发一个 Vue 应用,其中需要配置多个环境变量,可以使用 APP 后缀来组织它们:

# 应用基本设置
VUE_APP_TITLE=My Awesome App
VUE_APP_VERSION=1.0.0
 
# API 配置
VUE_APP_API_URL=https://api.example.com
VUE_APP_API_TIMEOUT=5000
 
# 用户设置
VUE_APP_USER_DEFAULT_LANGUAGE=en
VUE_APP_USER_ENABLE_NOTIFICATIONS=true

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 的值,该对象可以包含多个键值对,也就是说可以注入多个值,但是经过 CLI 封装后仅支持注入环境配置文件中以 VUE_APP_ 开头的变量,而 NODE_ENV 和 BASE_URL 这两个特殊变量除外。比如我们在权重最高的 .env.stage.local 文件中写入:

NODE_ENV=stage2
VUE_APP_TITLE=stage mode2
NAME=vue

然后我们尝试在 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: 'stage2',
    VUE_APP_TITLE: 'stage mode2',
    NAME: 'vue',
    BABEL_ENV: 'development',
    
    ...
}

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

{
    "BASE_URL": "/vue/",
    "NODE_ENV": "stage2",
    "VUE_APP_TITLE": "stage mode2"
}

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

拓展2

DefinePlugin插件

DefinePlugin 是 Webpack 提供的一个插件,用于在编译时创建一个全局常量,并替换代码中的变量。这在处理环境变量和配置时非常有用,因为它允许你在客户端代码中使用不同的值,而这些值在编译时就已经确定了。

主要作用

基本用法

在 Webpack 配置文件中,你可以这样使用 DefinePlugin

const webpack = require('webpack');
 
module.exports = {
    // 其他配置...
    plugins: [
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
            'API_URL': JSON.stringify('https://api.example.com'),
            // 可以定义更多的环境变量
        })
    ]
};

详细说明

  1. 创建全局常量: 你可以通过 DefinePlugin 创建任何你想要的全局常量。例如,在上面的示例中,API_URL 被定义为一个字符串。在代码其他地方,你可以直接使用 API_URL,Webpack 会在编译时将其替换为对应的字符串。

  2. 字符串化: 注意当定义常量时,通常需要使用 JSON.stringify 来确保常量在代码中是一个有效的 JavaScript 字符串。如果直接使用字符串,可能会导致语法错误。

  3. 环境变量: 在许多项目中,process.env.NODE_ENV 是一个常见的用法。在开发环境下,它通常设置为 'development',而在生产环境下则为 'production'。通过这种方式,你可以在代码中进行条件判断,比如:

if (process.env.NODE_ENV === 'production') {
    // 生产环境的代码
} else {
    // 开发环境的代码
}

示例

假设你有以下代码:

if (process.env.NODE_ENV === 'production') {
    console.log('This is production mode');
} else {
    console.log('This is development mode');
}

在 Webpack 配置中使用 DefinePlugin

const webpack = require('webpack');
 
module.exports = {
    plugins: [
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
        })
    ]
};

在构建应用时,如果 NODE_ENV 为 'production',Webpack 会将代码中的 process.env.NODE_ENV 替换为 'production',这样在运行时就只会执行生产环境的代码。

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 */
 
//从 config.js 文件中导入不同环境配置
const configs = require('./config');
 
// 引入 webpack-merge 库,用于合并不同的 Webpack 配置对象。这样可以灵活地组合不同的配置,而不丢失原有的配置。
const merge = require('webpack-merge');
 
// 根据环境判断使用哪份配置
const cfg = process.env.NODE_ENV === 'production' ? configs.build.env : configs.dev.env;
 
module.exports = {
    ...
    
    chainWebpack: config => {
        //plugin('define')访问 Webpack 中 DefinePlugin 插件通过修改这个插件的配置,可以更改全局变量的值
        config.plugin('define')
            .tap(args => {
                let name = 'process.env';
                
                // 使用 merge方法将 原有的process.env 和根据环境选择的 cfg 进行合并这样可以确保    
                 在原有的环境变量基础上添加新的变量,而不覆盖原有的值。
                args[0][name] = merge(args[0][name], cfg);
    
                return args
            })
    },
	
    ...
}

args[0][name] = merge(args[0][name], cfg);

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

{
    "NODE_ENV": "stage2",
    "VUE_APP_TITLE": "stage mode2",
    "BASE_URL": "/vue/",
    "TYPE": "dev",
    "IP": "xxx"
}

4. 实际场景

结合以上环境变量的配置,我们项目中一般会遇到一些实际场景: 比如在非线上环境我们可以给自己的移动端项目开启 vConsole 调试,但是在线上环境肯定不需要开启这一功能,我们可以在入口文件中进行设置,代码如下:

/* main.js */
 
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
 
Vue.config.productionTip = false
 
// 如果是非正式环境,加载 VConsole
if (process.env.NODE_ENV !== 'production') {
    var VConsole = require('vconsole/dist/vconsole.min.js');
    var vConsole = new VConsole();
}
 
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

vConsole 是一款用于移动网页的轻量级,可扩展的前端开发工具,可以看作是移动端浏览器的控制台。

另外我们还可以使用配置中的 BASE_URL 来设置路由的 base 参数:

/* router.js */
 
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
 
Vue.use(Router)
 
let base = `${process.env.BASE_URL}`; // 获取二级目录
 
export default new Router({
    mode: 'history',
    base: base, // 设置 base 值
    routes: [
        {
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/about',
            name: 'about',
            component: About
        }
    ]
})

每一个环境变量你都可以用于项目的一些地方,它提供给了我们一种全局的可访问形式,也是基于 Node 开发的特性所在。

拓展3

1.webpack 通过 DefinePlugin 内置插件将 process.env 注入到客户端代码中时,`process.env.NODE_ENV` 为什么要进行 JSON.stringify 处理?

原因分析

  1. JavaScript 语法: 当你在 JavaScript 代码中使用字符串时,这些字符串必须被正确地包裹在引号中。例如,"production" 或者 "development" 必须是字符串类型。而 DefinePlugin 允许我们在编译时定义全局常量,如果不使用 JSON.stringify,将会导致生成的代码不符合 JavaScript 语法。

// 如果没有 JSON.stringify,可能会变成这样
process.env.NODE_ENV === production // 这里的 production 会被认为是一个变量
 
// 正确的写法应该是
process.env.NODE_ENV === 'production' // 这里的 'production' 是一个字符串
  1. 确保类型一致性: JSON.stringify 可以确保传递给 DefinePlugin 的值在任何情况下都是字符串。即使 process.env.NODE_ENV 的值为 undefined 或者其他类型(如数字),JSON.stringify 也会将其转换为字符串格式,并避免潜在的类型错误。

  2. 防止意外的值: 如果你直接将某个变量(例如 process.env.NODE_ENV)传递给 DefinePlugin,而这个变量在某些情况下可能是未定义的或不符合预期的类型,直接使用可能导致运行时错误或逻辑错误。通过 JSON.stringify,你可以确保一切都是严格的字符串,从而避免这些问题。

示例

下面是一个简单的示例来展示没有 JSON.stringify 的可能后果:

const webpack = require('webpack');
 
module.exports = {
    plugins: [
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': process.env.NODE_ENV || 'development' // 没有字符串化
        })
    ]
};
 
// 结果可能是:
if (process.env.NODE_ENV === production) {
    // 这里会报错,因为 production 没有被定义为字符串
}

而使用 JSON.stringify 的情况下:

const webpack = require('webpack');
 
module.exports = {
    plugins: [
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development') // 使用字符串化
        })
    ]
};
 
// 结果是:
if (process.env.NODE_ENV === 'production') {
    // 这里是正确的,逻辑不会出错
}

总结

使用 JSON.stringify 在 DefinePlugin 中确保 process.env.NODE_ENV 被定义为一个合法的字符串,从而避免了潜在的语法错误和运行时错误。这是一个好的实践,确保你在客户端代码中处理常量时的安全性和一致性。

2.如何在 package.json 中的 scripts 字段中定义一些自定义脚本来切换不同的环境?

假设你有一个 Node.js 项目,并且希望根据不同的环境(如开发、测试和生产)来执行不同的脚本。你可以在 package.json 中定义如下脚本:

{
  "name": "your-project",
  "version": "1.0.0",
  "scripts": {
    "start": "NODE_ENV=production node server.js",
    "dev": "NODE_ENV=development nodemon server.js",
    "test": "NODE_ENV=test mocha",
    "build": "webpack --mode production",
    "build:dev": "webpack --mode development"
  }
}
  1. start: 用于生产环境启动应用,将 NODE_ENV 设置为 production。在 Unix 系统中,环境变量可以通过 KEY=value command 的方式设置。

  2. dev: 用于开发环境启动应用,将 NODE_ENV 设置为 development。这里使用了 nodemon,它会自动重启 Node.js 应用程序。

  3. test: 用于测试环境,运行测试框架(如 Mocha),将 NODE_ENV 设置为 test

  4. build 和 build:dev: 分别用于构建生产和开发版本,使用 Webpack 进行打包。

Windows 兼容性

在 Windows 上,设置环境变量的方式与 Unix 系统不同。为了确保你的脚本在不同操作系统上都能正常工作,你可以使用 cross-env 包。首先,你需要安装 cross-env

npm install --save-dev cross-env

然后修改 package.json 中的脚本如下:

{
  "name": "your-project",
  "version": "1.0.0",
  "scripts": {
    "start": "cross-env NODE_ENV=production node server.js",
    "dev": "cross-env NODE_ENV=development nodemon server.js",
    "test": "cross-env NODE_ENV=test mocha",
    "build": "webpack --mode production",
    "build:dev": "webpack --mode development"
  }
}

运行脚本

可以使用以下命令来运行不同的脚本:

以上就是Vue项目中env文件的作用和配置详解的详细内容,更多关于Vue env文件作用和配置的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文