在实际项目开发中,须要基于多种环境去设置不一样的环境变量以便于在构建阶段或是运行阶段去使用,例如常见的经过process.env.NODE_ENV
在构建时去判断当前的构建环境是development
仍是production
,例如须要在开发环境
、测试环境
和生产环境
去访问不一样的接口服务器。html
为了模拟真实的项目,使用webpack搭建了一个最小化的项目结构:前端
├─package.json ├─src | └index.jsx ├─public | └index.html ├─config | └webpack.config.js
Node环境变量就是指process.env
这个属性node
它是 Nodejs 应用程序中,process.env
属性,返回包含用户环境的对象,因此它不能够在客户端侧代码中使用,也就不能在浏览器环境上使用。webpack
// process.env(官方示例) { TERM: 'xterm-256color', SHELL: '/usr/local/bin/bash', USER: 'nodejscn', PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin', PWD: '/Users/nodejscn', EDITOR: 'vim', SHLVL: '1', HOME: '/Users/nodejscn', LOGNAME: 'nodejscn', _: '/usr/local/bin/node' }
使用 cross-env
依赖包,支持跨平台配置环境变量。git
// package.json { ..., "scripts": { "start": "npm run dev", "dev": "cross-env NODE_ENV=development AAA=123 webpack serve --config ./config/webpack.config.js", "build:test": "cross-env NODE_ENV=test webpack --config ./config/webpack.config.js", "build:pro": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js" }, ... }
经过在package.json
脚本中设置变量的方式来注入环境变量,同时cross-env
还支持去设置多个环境变量,只须要经过空格区分,例如在dev
脚本中设置的NODE_ENV=development
和AAA=123
。github
这样在执行npm start
就可以经过process.env
获取到对应的环境变量。web
// webpack.config.js console.log("【process.env】", process.env.AAA);
可以在构建时的终端中打印出npm
可是在index.jsx
中也就是浏览器环境下的文件中打印process.env
就会报错json
缘由就是前文提到的peocess.env
是Node环境的属性,浏览器环境不可以获取到。让浏览器环境获取到所需变量咱们后文再说。vim
直接经过在script脚本中注入环境变量的方式不利于集中管理环境变量,并且在环境变量较多时这种方式也十分不友好,因此须要一种方式来集中管理这些环境变量。
使用dotenv
依赖包可将环境变量从 .env
文件加载到 process.env
。
dotenv
会默认加载根目录的.env
文件去注入环境变量,经过require('dotenv').config()
便可完成注入。
//webpack.config.js dotenv.config(); //.env文件 AAA=123
一样也可以在终端中看到
在多环境配置时须要经过规定不一样环境对应的.env
文件,例如如今规定.env.test
是测试环境对应的环境变量,.env.production
是生产环境,.env
是开发环境。而后经过dotenv.config({ path: })
去加载对应文件的环境变量。
//webpack.config.js const PROJECT_PATH = resolve(__dirname, "../"); const dotenvFile = resolve(PROJECT_PATH, `./.env.${process.env.NODE_ENV}`); // 加载.env*文件 默认加载.env文件 dotenv.config({ path: fs.existsSync(dotenvFile) ? dotenvFile : resolve(PROJECT_PATH, `./.env`), }); console.log("【process.env】", process.env.ENV);
这里process.env.NODE_ENV
是为了判断当前的运行环境来去加载对应的.env
文件。
// package.json "scripts": { "start": "npm run dev", "dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js", "build:test": "cross-env NODE_ENV=test webpack --config ./config/webpack.config.js", "build:pro": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js" } //.env.production ENV=pro //.env ENV=dev
执行npm start
执行npm run build:pro
能够看到不一样环境的变量确实已经注入成功。
浏览器环境下也须要根据不一样的环境变量来处理一些逻辑,可是它不能获取到process.env
因此不能像注入Node环境变量的方式来实现。浏览器环境变量是基于webpack.DefinePlugin
这个插件在项目构建时引入的,引入以后能够在前端代码中全局获取到对应的变量。
基础使用方式是将所需的变量按键值对的方式传入DefinePlugin
中,须要注意的是变量值须要经过JSON.stringify
进行包裹。
module.exports = { plugins: [ new DefinePlugin({ aaa: JSON.stringify("!!!!") }) ] }
执行脚本后能够在index.jsx
中获得对应的结果
//index.jsx console.log("【app】", aaa); const App = () => { return <div>app</div>; };
浏览器环境中也须要根据项目环境来引入不一样的变量,以前在Node
环境中已经获取到不一样的环境变量,咱们能够创建一个基于此的映射表在项目构建时根据拿到的Node
环境变量来引入对应的浏览器环境变量。
// webpack.config.js // 浏览器环境注入的变量 const define = { dev: { baseURL: "/api/dev", }, test: { baseURL: "/api/test", }, pro: { baseURL: "/api/pro", }, }; module.exports = { new DefinePlugin({ "process.env": Object.keys(define[process.env.ENV]).reduce((env, key) => { env[key] = JSON.stringify(define[process.env.ENV][key]); return env; }, {}), }), }
执行npm start
,能够在浏览器控制台看到结果
执行npm run build:pro
,在dist目录开启一个服务器,能够在浏览器控制台看到结果
在实际项目中根据不一样环境切换接口服务器地址的场景中,就能经过这样的方式来获取到不一样环境中的接口地址。
在平时开发中较常使用umi
做为项目框架,umi
经过环境变量UMI_ENV
区分不一样环境来指定不一样配置。
具体来讲是经过脚本中注入的UMI_ENV=xxx
去匹配对应的config.xxx.js
配置文件,而后在define
属性中去配置须要引入浏览器环境的变量。
// webpack.config.js module.exports = { ..., "scripts": { "start": "cross-env UMI_ENV=dev umi dev", "build:test": "cross-env UMI_ENV=test umi build", "build:pre": "cross-env UMI_ENV=pre umi build", "build:pro": "cross-env UMI_ENV=pro umi build", } ..., } //config.dev.js import { defineConfig } from 'umi'; export default defineConfig({ define: { 'process.env': { BASE_API: '/api/dev', }, }, });