Webpack 设置环境变量的误区

1、前言

  • 平常的前端开发工做中,至少会有两套构建环境
    • 一套开发时使用,构建结果用于本地开发调试,不进行代码压缩、打印 debug 信息、包含 sourcemap 文件等
    • 一套发布时使用,构建结果用于线上,即代码都是压缩过的、运行时不打印 debug 信息、静态文件不包括 sourcemap 等
  • webpack 4.0 版本开始引入了 mode 的概念
选项 描述
development 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPluginNamedModulesPlugin
production 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin

2、区分开发环境/生产环境的多种方式

2.1 使用命令行

2.1.1 写法一

"scripts": {
    // 默认 mode 为 development
    "dev1": "webpack-dev-server",
    // 默认 mode 为 production,不过这样写,打包的时候会有警告
    "build1": "webpack",
}
复制代码
  • 以上 script 脚本,能够在任意模块内经过 process.env.NODE_ENV 获取当前的环境变量
  • 但没法在 node 环境(webpack 配置文件中)下获取当前的环境变量
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development | production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
复制代码

2.1.2 写法二

"scripts": {
   "dev2": "webpack --mode=development",
   "build2": "webpack --mode=production",
}
复制代码
  • 写法一, 是同样的结果

2.1.3 写法三

"scripts": {
   "dev3": "webpack-dev-server --env=development",
   "build3": "webpack --env=production",
}
复制代码
  • 以上 script 脚本,没法在任意模块内经过 process.env.NODE_ENV 获取当前的环境变量
  • 但能够在 node 环境(webpack 配置文件中)下,经过函数获取当前环境变量
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// undefined
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

// 经过函数获取当前环境变量
module.exports = (env,argv) => {
  console.log('env',env);// development | production
  return {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
  }
};
复制代码

2.2 使用 mode

// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development | production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

module.exports =  {
  	mode:'development',// development | production
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
复制代码
  • 和 2.1 中的写法二,是同样的结果
  • 一个是在命令行中设置,一个是在 webpack 配置文件中设置

2.3 使用 webpack.DefinePlugin

  • 首先得知道这个插件的做用:设置全局变量(并不是挂载到 window 上),全部模块都能读取到该变量的值
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development
   console.log(NODE_ENV);//  production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

// 这里只是凑巧和环境变量同名了,因此才不会报错
console.log('process.env.NODE_ENV',process.env.NODE_ENV);// undefined
console.log('NODE_ENV',NODE_ENV);// error !!!

module.exports =  {
  	mode:'development',// development | production
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
  	plugins:[
            new webpack.DefinePlugin({
           	'process.env.NODE_ENV':JSON.stringify('development'),
                'NODE_ENV':JSON.stringify('production'),
       }),
    ],
    		...
};
复制代码
  • 能够在任意模块内经过 process.env.NODE_ENV 获取当前的环境变量
  • 但没法在 node 环境(webpack 配置文件中)下获取当前的环境变量

2.4 使用 cross-env 插件

  • 原先我一直觉得这个插件,能够用来设置全部环境(浏览器环境、node 环境)下的变量。通过测试发现,只能设置node 环境下的变量 —— NODE_ENV

2.4.1 写法一

"scripts": {
 	"dev1": "cross-env NODE_ENV='production' webpack-dev-server",
        "build1": "cross-env NODE_ENV='development' webpack",
}
复制代码
  • 以上 script 脚本,能够在任意模块内经过 process.env.NODE_ENV 获取当前的环境变量
  • 能够在 node 环境(webpack 配置文件中)下,获取当前环境变量
  • 可是会有一个问题: 浏览器环境和 node 环境下获取到的值是不同的
//  !!!!!!
// npm run build1 
//  !!!!!!

// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
复制代码

2.4.2 写法二

"scripts": {
  "dev2": "cross-env NODE_ENV='development' --mode development",
  "build2": "cross-env NODE_ENV='production' --mode production",
}
复制代码
  • 以上 script 脚本,能够在任意模块内经过 process.env.NODE_ENV 获取当前的环境变量
  • 能够在 node 环境(webpack 配置文件中)下,获取当前环境变量
  • 因此在能浏览器环境下读取到环境变量的值,靠的是 mode ,在 node 环境下读取到环境变量的值,靠的是 cross-env
//  !!!!!!
// npm run build2 
//  !!!!!!

// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// production

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
复制代码

3、误区

  • 常常在一些群里看到这个问题: cross-envwebpack.DefinePlugin 配合使用的时候,没法经过 process.env.xxx 来获取到设置的环境变量,须要经过 webpack.DefinePlugin 里面设置的 key 来获取。
  • 会引起这个问题的可能缘由是:先往 cross-env 里设置了 NODE_ENV 变量,而后又到 DefinePlugin里设置了一遍环境变量
"scripts": {
  "dev": "cross-env NODE_ENV='development' --mode development"
}
复制代码
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
  	plugins:[
           new webpack.DefinePlugin({
             	// 设置环境变量
               	'process.env.NODE_ENV':JSON.stringify('development'),
           }),
        ],
    		...
};
复制代码
  • 此时会发现浏览器环境和 node 环境都能获取到设置的变量了,而后就认为以后再设置其余的全局变量时,也像这样写就好了。javascript

  • 认为 cross-envDefinePlugin 是配套一块儿使用的,这个见解自己就很奇怪,由于二者的做用点不同前端

    • DefinePlugin 的做用:是设置浏览器环境下能读取到的 "全局变量",直接经过 key 读取,在 node 环境下是没法读取到的
    • cross-env 的做用:是经过命令行设置环境变量 NODE_ENV,使 node 环境下能读取到,经过 process.env.NODE_ENV 读取
    • 若是在DefinePlugin 里设置的 keyprocess.env.NODE_ENV ,会覆盖 webpack 经过 mode 模式设置的环境变量的值
"scripts": {
  "dev": "cross-env NODE_ENV='development' --mode development"
}
复制代码
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// 666666
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
  	plugins:[
           new webpack.DefinePlugin({
                // 注意:由于同名的 key,这里的值会覆盖默认的值 !!!!!!
               	'process.env.NODE_ENV':JSON.stringify('666666'),
           }),
        ],
    		...
};
复制代码

4、总结

  • cross-env专门用来设置 node 环境变量
  • webpack.DefinePlugin专门用来设置浏览器环境下的全局变量(不会挂载到 window 上)
  • 本文只是我我的的理解,若有错误还请告知,万分感谢

5、推荐阅读

你真的了解 React 生命周期吗java

React Hooks 详解 【近 1W 字】+ 项目实战node

React SSR 详解【近 1W 字】+ 2个项目实战webpack

从 0 到 1 实现一款简易版 Webpackweb

相关文章
相关标签/搜索