写在前面

  1. 最近在忙一个新web平台的技术调研工作, 昨天在项目站会汇报时,同事说已完成项目多环境切换, 有点困惑就去看了下git提交记录, 发现有提交.env/.env.test/.env.development等文件, 不太懂什么意思,故有了此文章。

vue-cli脚手架搭建的

在项目启动时,vue-cli会将以VUE_APP开头的变量读取至环境变量,这是vue-cli强制要求的=.=

.env是什么?

.env不管生产or开发环境都会加载的文件; .env.production是生产环境配置文件; .env.development是开发环境配置文件。

我们先看下常规的package.json文件一般是如下这么配置的

  1. {
  2. "scripts": {
  3. "dev": "vue-cli-service serve", // npm run dev本地开发运行,会把process.env.NODE_ENV设置为'development'
  4. "build": "vue-cli-service build", // npm run build默认打包模式, 会把process.env.NODE_ENV设置为'production'
  5. }
  6. }

如何使用.env实现多环境切换?

为便于描述,这里先展示2个环境: production生产环境&&development开发环境。

  • 项目根目录下新建.env.production && .env.development文件
  • 分别配置2个文件的环境属性(Tips:必须与VUEAPP开头且属性命名必须全部大写) ``` // .env.production VUE_APP_BASE_URL=”http://vtodo-list.com

// .env.development VUE_APP_BASE_URL=”http://localhost:3000

  1. - 在需要的使用, 通过如下命令去获取

console.log(‘当前环境baseurl:’, process.env.VUE_APP_BASE_URL)

  1. <a name="Kh5Lm"></a>
  2. ### 如何新增自定义环境?
  3. 若想追加自定义环境的话eg:测试环境test, 可按照下面的配置:
  4. - 根目录下新建.env.test文件
  5. - 配置该文件的环境属性

// .env.test VUE_APP_BASE_URL=”http://vtodo-test-list.com

  1. - package.json中新增环境变量命令

// 添加自定义环境, —mode后面的参数对应.env.xx文件后缀 { “scripts”: { “dev:test”: “vue-cli-service serve —mode test” } }

  1. - 测试配置是否生效

npm run dev:test

// 需要使用的文件处 console.log(‘当前环境baseurl:’, process.env.VUE_APP_BASE_URL)

  1. <a name="Xd1hf"></a>
  2. ### vue.config.js中代理配置如何跟.env联系起来?
  3. > 现状: 在本地开发时,通过localhost访问接口会跨域,此方案是通过本起一个devServer服务, 反向代理的方式处理此问题,若需要切换环境时需要每次手动改代码。
  4. > 考虑:既然.env能实现多环境的切换, 那么该文件的代理配置能否跟.env联系起来呢?

// vue.config.js文件 module.exports = { devServer: { port: 9999, proxy: { ‘/*’: { target: “https://www.xxx-test.com“, //dev环境 // target: ‘https://www.xxx.com‘, //prd环境 target: process.env.VUE_APP_BASE_URL, // 关键代码通过.env联系起来 changOrigin: true, }, }, } }

  1. <a name="X7YrJ"></a>
  2. ##
  3. <a name="L0cbA"></a>
  4. ## 剖析process.env环境
  5. <a name="T8TBQ"></a>
  6. ### dotenv
  7. > 零依赖模块, 将环境变量从.env文件读取至process.env环境变量中.
  8. 下面我们研究下使用教程:
  9. - 初始化package.json文件

npm init -y

  1. - 安装dotenv

npm i dotenv -D

  1. 笔者在安装过程中遇到报错了Error: Refusing to install package with name 'dotenv' under a package.<br />![](https://cdn.nlark.com/yuque/0/2022/png/1607809/1655812039230-e7b031cf-256b-49d8-8c72-d365ee350ff2.png#clientId=u5fd2eedb-9042-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=uf8c95df7&margin=%5Bobject%20Object%5D&originHeight=731&originWidth=1229&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u51b96bc3-5f5a-41a5-a200-29817981057&title=)<br />该问题出现的原因是:安装的依赖名跟项目名重复了,这里修改下package.json中的name即可正确安装。<br />![](https://cdn.nlark.com/yuque/0/2022/png/1607809/1655812101897-b27bf64b-bcca-43ef-aa65-d9c261df5b43.png#clientId=u5fd2eedb-9042-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u23ff1541&margin=%5Bobject%20Object%5D&originHeight=676&originWidth=1182&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=ubb2995aa-b672-4f86-ab61-6dd8718937a&title=)
  2. - 项目根目录下新建.env文件

// 内容可自定义,符合key=value即可

以#开头的会被注释, 不会被读取到

BASE_URL=’http://192.168.103.88

  1. - 新建src/main.js文件

const dotenv = require(‘dotenv’) dotenv.config({}) console.log(name=> ${process.env.BASE_URL})

  1. - 本地运行该文件

node src/mian.js

  1. 我们看下终端输出情况:是能正确拿到.env文件配置的。这里需要注意的是: 若你先进入src目录然后再执行node命令,你会发现输出是undefined
  2. > **这是因为dotenv默认是去加载当前路径下的.env文件, 故会出现此差异。**
  3. ![IMG_6011.JPG](https://cdn.nlark.com/yuque/0/2022/jpeg/1607809/1655786717057-4740646f-26b3-4824-a72c-4e3947c23ec5.jpeg#crop=0&crop=0&crop=1&crop=1&from=url&id=l8RiM&margin=%5Bobject%20Object%5D&name=IMG_6011.JPG&originHeight=546&originWidth=1516&originalType=binary&ratio=1&rotation=0&showTitle=false&size=59924&status=done&style=none&title=)<br />相信你看到这里也是有个疑问的:这是运行在node环境,而我们的项目是运行在浏览器环境的,这倆是怎么关联起来的呢?请往下看?
  4. <a name="F3FsS"></a>
  5. ### 结合webpack使用
  6. - 安装webpack webpack-cli, 为方便管理HTML还安装html-webpack-plugin

npm i webpack webpack-cli html-webpack-plugin -D

  1. - 根目录下新建webpack.config.json文件

const {resolve} = require(‘path’) const HtmlWebpackPlugin = require(‘html-webpack-plugin’)

module.exports = { mode: ‘development’, entry: ‘./src/main.js’, output: { filename: ‘[name].js’, path: resolve(__dirname, ‘dist’), clean: true, }, plugins: [ new HtmlWebpackPlugin({ title: ‘自定义加载env文件’ }) ] }

  1. - 新建index.html,引入main.js文件

<!DOCTYPE html>

  1. - 修改src/main.js文件,如下

const process = {} console.log(document, ‘document’) process.env = document.title console.log(‘process相关参数’, process.env)

  1. - 执行打包命令

npx webpack ./src/main.js

  1. - 打包成功后,浏览器访问dist/index.html文件: 你会发现该终端有如下输出:<br />其实这里的主要目标是: webpackHtmlWebpackPlugin插件配置的网页标题,在js文件中通过process.env去获取.
  2. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/1607809/1655811137788-799b13a9-3894-40b2-85bb-bbda39c8c85c.png#clientId=u5fd2eedb-9042-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=161&id=u8d63004a&margin=%5Bobject%20Object%5D&name=image.png&originHeight=201&originWidth=794&originalType=binary&ratio=1&rotation=0&showTitle=false&size=14325&status=done&style=none&taskId=ud7799237-f532-49ae-924e-38d78a892ae&title=&width=635.2)
  3. > **该做法的缺陷: 所有需要使用到该网页标题的,需要单独引入该变量,不知道有没更好的办法注入该代码呢?**
  4. <br />
  5. <a name="bm5g8"></a>
  6. ### 引入 DefinePlugin内置插件
  7. > DefinePlugin 允许在 编译时 将你代码中的变量替换为其他值或表达式。简单来说,它的作用就是文本替换,将值或表达式硬编码到代码中。
  8. 其实我们思考下, 我们的webpack是运行在node环境的,而我们的项目是运行在浏览器的,2者是怎么联系起来的?
  9. - 使用dotenv加载.env中的环境变量
  10. - 在打包阶段读取环境变量
  11. - 以某种方式将环境变量合并到打包结果中
  12. 下面我们演示下要怎么做替换✅
  13. - 修改webpack.config.js文件如下

const { resolve } = require(‘path’) const { DefinePlugin } = require(‘webpack’)

const BASE_URL = “‘http://192.168.0.0.1‘“

module.exports = { mode: ‘development’, entry: ‘./src/main.js’, output: { filename: ‘[name].js’, path: resolve(__dirname, ‘dist’), clean: true, }, plugins: [ new DefinePlugin({ ‘process.env’: BASE_URL }) ] }

  1. - 修改main.js如下

console.log(name=> ${process.env.BASE_URL})

  1. - 执行如下命令进行打包

npx webpack ./src/main.js ``` 我们看下终端运行效果: 打包是成功的,也有在本地生成dist文件夹
Vue .env有什么用? - 图1

  • 本地打开dist/index.html文件,你会发现终端能正常输出env的配置

    不过这里需要注意的是:若是number类型可直接替换, But进行文本替换的时候, 必须使用”‘xxx’”, 直接’xxx’会报错, 请看下图.

Vue .env有什么用? - 图2

写在最后

webpack + dotenv + webpack DefinePlugin相互作用的成果,这也是前端工程化的表现。