重点区分:webpack和webpack的配置文件时运行在node环境下的,所以能访问process,而打包后的文件是运行在用户浏览器中的浏览器下是没有process进程对象的。
模式(mode)
- 日常的前端开发工作中,一般都会有两套构建环境
- 一套开发时使用,构建结果用于本地开发调试,不进行代码压缩,打印 debug 信息,包含 sourcemap 文件
- 一套构建后的结果是直接应用于线上的,即代码都是压缩后,运行时不打印 debug 信息,静态文件不包括 sourcemap
- webpack 4.x 版本引入了 mode 的概念
- 当你指定使用 production mode 时,默认会启用各种性能优化的功能,包括构建结果优化以及 webpack 运行性能优化
- 而如果是 development mode 的话,则会开启 debug 工具,运行时打印详细的错误信息,以及更加快速的增量编译构建
| 选项 | 描述 |
|---|---|
| development | 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin |
| production | 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin |
当我们将webpack配置文件中的mode模式设置为development或者production时,我们可以在项目的源代码文件中通过process.env.NODE_ENV 来获取对应的值,其中值在开发环境下为development(字符串), 在生产环境下为production(字符串),然后了就可以动态的决定项目在浏览器中运行时走不同的逻辑判断语句。比如访问的是开发后台地址还是生产后台地址。
index.js:
mode:'production'
mode:'development'
你可以看出,就相当于在webpack 编译阶段,将我们项目源码文件中的process.env.NODE_ENV这个变量替换为对应的
development或者production字符串。
当我们的项目上线后,源码中的process.env.NODE_ENV 就已经配替换完成,在执行过程中我们可以根据这个字段的实际值进行条件判断,从而走不同的逻辑。
但是这里有一点需要注意:
- 就是当我们在webpack的配置文件中想通过**
process.env.NODE_ENV** 来在配置文件中就实现走不同的逻辑的话,是无法获取的。 来看下面的情况:
所以mode设置production或者development是用于在项目的源码中进行使用的,而webpack配置文件中并不能读取到。
那如果我们想通过在webpack的配置文件中访问process.env.NODE_ENV,从而实现webpack配置文件在被webpack工具所读取的阶段就走不同的逻辑。那就需要另作处理。
上面说的这些就是为了引出下面的内容。 之前的并没有意识到环境变量的不同层次导致自己始终不能十拿九稳。
下面就是介绍webpack的环境区分
区分环境
首先明确: 读取变量的两个地方:
- webpack配置文件所在的node环境
- 项目的源码文件中
--mode用来设置模块内的process.env.NODE_ENV
- 可以在模块内(项目源文件代码中)通过
process.env.NODE_ENV获取当前的环境变量对应的字符串值(production或者production)进行替换,在编译阶段做的,无法在webpack配置文件中通过process.env.NODE_ENV获取此变量
"script":{
"build":"webpack --mode=development"
}
webpack --mode=development => 设置webpack.config.js文件中mode的值为development => mode为开发模式(development )下时,webpack内部通过webpack.definePlugin插件设置字符串process.env.NODE_ENV在项目源码中的代表的实际值为development, 在编译阶段,当解析到项目源码中有用到 process.env.NODE_ENV 时,直接将它替换为 字符串(development) 。 webpack --mode=production也是一样的原理。
其中通过命令行的--mode和配置文件中的mode取指定环境,都是一个原理,如果两者同时存在,则命令行--mode的优先级更高。
--env用来设置webpack配置文件的函数参数
- 无法在模块内通过
process.env.NODE_ENV访问 - 可以在webpack 配置文件中通过函数获取当前环境变量
"script":{
"build":"webpack --env=development"
}
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
console.log(process.env.NODE_ENV) // 值为undefined
module.exports = function (env, argv) {
console.log(env) // development:true
console.log(argv)
return {
mode: 'production',
entry:'./src/index.js'
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
}),
new webpack.DefinePlugin({
FIRTS_VAR: "'wuyibo'"
})
]
};
};
cross-env用来设置node环境的process.env.NODE_ENV
--env=development 只是在执行脚本时,给函数类型的 webpack 配置传入参数。如果在 webpack 配置文件中访问 process.env.NODE_ENV 的话,是没有值的,为 undefined。如果想修改 webpack 配置文件中访问的变量的值,可以在命令行中设置 webpack 配置文件运行的环境的环境变量。
"scripts": {
"build": "set NODE_ENV=development webpack ", // windows下的写法。webpack 配置文件中访问 process.env.NODE_ENV ,则它的值就为development
"build": "cross-env NODE_ENV=development webpack " // 解决操作系统层面的命令兼容性包
}
webpack配置文件中读取的是node的配置的环境变量,可以通过cross-env key=value来设置。 然后在webpack配置文件中可以访问到设置的环境变量,然后再用这个环境变量作为webpack配置的项中的值,从而来改变项目模块内的变量的值或者打包方式。
cross-env这是的环境变量在项目的模块文件中是无法访问到的。
例子:
"scripts": {
"build": "cross-env NODE_ENV=production FIRST_ENV=one webpack"
}
在webpack配置文件中可以访问到:
console.log(process.env.NODE_ENV); // production
console.log(process.env.FIRST_ENV); // one
在项目中的文件index.js:
console.log(process.env.NODE_ENV); // production ,是由mode为production模式下的DefinePlugin插件设置的
console.log(process.env.FIRST_ENV); // process.env.FIRST_ENV则直接在打包后文件中存在,运行时报错
DefinePlugin用来设置模块内的全局变量
- 设置全局变量(全局变量不是
window),所有模块都能读取到该变量的值 - 可以在任意模块(项目的源文件)内通过
process.env.NODE_ENV获取当前的环境变量 - 但无法在
node环境(webpack 配置文件中)下获取当前的环境变量 - 注意在值为字符串是需要用引号包裹代引号的字符串
plugins:[
new webpack.DefinePlugin({
'process.env.NODE_ENV':JSON.stringify(process.env.NODE_ENV),
'back_end_url':'"http://xxxx.xxx/xxx"'
})
]
通过插件DefinePlugin设置的变量可以直接在整个项目的源码中直访问。比如:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = function (env, argv) {
return {
mode: 'production',
// entry:'./src/index.js'
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
}),
new webpack.DefinePlugin({
FIRTS_VAR: "'wuyibo'"
})
]
};
};
源码index.js中:
console.log(FIRTS_VAR); // 在打包编译后的文件中直接就用 wuyibo 字符串进行的替换
--mode 用来设置模块内的process.env.NODE_ENV(优先级更高),等价于设置webpack配置文件中mode 的值。
webpack的mode默认为production, webpack serve的mode默认为development
- 可以在模块内通过
process.env.NODE_ENV获取当前的环境变量,无法在webpack配置文件中获取此变量
如果通过 webpack 的配置文件中的 mode 设置打包模式,那么在项目的各个模块文件中的 process.env.NODE_ENV 字段在打包后生成的文件中都将被替换为字符串:'development 或者 production'。比如在项目的 index.js 入口文件中写代码:
console.log(process.env.NODE_ENV, '----------------');
在 mode 为 development 模式下,编译后文件的中的代码是:
console.log('development', '----------------');
在 script 脚本中使用 --mode=development 的效果和在 webpack 配置文件的 mode 字段中设置值是一样的。
--env 用来设置webpack配置文件的函数参数,并不直接在项目的模块文件中生效
webpack 的配置文件的模块导出可以是一个函数,也可以是一个配置对象。其中函数可以接受命令行传递的参数。
在 script 脚本中使用 --env=development 的效果是为 webpack 配置文件默认导出的是函数时,可以在函数的参数中获取到该命令行中设置的参数。例如 script 脚本中:"build": "webpack --env=development" 那么下面代码中的 env 就是:{ WEBPACK_BUNDLE: true, WEBPACK_BUILD: true, development: true }。argv 的结构则是:{ env: { WEBPACK_BUNDLE: true, WEBPACK_BUILD: true, development: true } },但是因为 mode 默认没有设置时使用的是 production 模式,所以打包出来代码中的 process.env.NODE_ENV 变量的取值仍旧是 production 字符串。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = function (env, argv) {
console.log(env);
console.log(argv);
return {
// mode: 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'main.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
})
]
}
}
在 webpack 项目中读取变量有两种环境:一个是 webpack 配置文件所运行的 node 环境,一个是项目源码模块中的运行的环境。配置文件和--mode 都是设置项目源码模块中的运行的环境配置和变量。
vue中可以通过.env格式的文件向node环境中设置变量。借助的是一个第三方库:dotenv-expand。