携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
简介
虽然开发、测试、生产的代码都是使用webpack
构建工具来构建,但是对于不同的环境对构建后代码的要求肯定是不一样的。
比如,我们肯定想本地开发的时候需要构建的快、能快速定位到源码错误位置。对于生产环境我们肯定希望构建后的代码体积要足够小,图片能压缩、代码能分割等等。
对于这些要求,肯定就会涉及到不同的环境的配置。今天我们就来说说webpack
的环境配置。
mode
mode
配置选项,告知 webpack
使用相应模式的内置优化。
mode
的值有none | development | production
三个
对于不同的mode
值,webpack
有不同的优化策略。
引用官网的一张图:
mode默认值
mode
默认值是production
。
配置方式
配置方式主要有两种
- 直接定义
module.exports = {
mode: 'development',
};
复制代码
- 从
CLI
参数中传递:
$ webpack --mode=development
复制代码
可以看到第一种方式不够灵活,不能根据不同环境自动变更。第二种方式通过命令行参数进行传递,相对更灵活,但是由于mode
只有development
和production
两个值,不太能满足我们日常开发的需要,所以我们需要另外再改造下。
一般我们的环境会有本地开发环境、测试环境、生产环境。所以我们就需要定义三种环境,不同的环境使用不同的配置。
获取mode值
对于第二种通过命令行参数传递mode
值,我们怎么才能在webpack.config.js
中获取到该值呢?
其实我们只要把文件形式改写下就可以了,由导出对象形式改为导出函数就能获取到了。
// webpack.config.js
const config = {
entry: './app.js',
mode: 'production'
//...
};
module.exports = (env, argv) => {
console.log(argv.mode) // development、none、production
return config;
};
复制代码
前面说了,仅仅两个模式不能满足日常开发需求,所以我们需要再定义其它的参数来进行更细化的区分。
自定义多种环境
这里我们需要使用到cross-env
,它的作用就是能跨环境传递环境参数,也就是能同时兼容mac、windows、linux
。
我们先安装下
npm i cross-env
复制代码
然后我们在package.json
里面配置构建命令
{
"scripts": {
"dev": "cross-env MODE=development webpack",
"staging": "cross-env MODE=staging webpack",
"build": "cross-env MODE=production webpack",
}
}
复制代码
dev
构建开发环境,staging
构建测试环境,build
构建生产环境。
三个环境传递三个不同的MODE
值,我们可以在webpack.config.js
中通过process.env.MODE
获取,然后进行不同的配置啦。
// webpack.config.js
console.log("process.env.MODE=", process.env.MODE);
module.exports = (env, argv) => {
//...
return config;
};
复制代码
我们来试试
npm run dev
npm run staging
npm run build
可以看到,我们通过不同的命令就能获取到不同的MODE
值啦。有了不同的MODE
值我们就可以进行不同环境的配置啦。
比如,我们需要不同的环境定义不同的mode
,开发环境设置mode
为development
,测试和生产环境我们设置mode
为production
,进行不同的优化。
// webpack.config.js
console.log("process.env.MODE=", process.env.MODE);
module.exports = (env, argv) => {
if (process.env.MODE === "development") {
config.mode = "development";
} else {
config.mode = "production";
}
return config;
};
复制代码
前面说了,mode
定义后,会同步设置process.env.NODE_ENV
的值,我们可以在我们的源码里面获取到。
如果mode
为development
则process.env.NODE_ENV
的值为 development
,如果mode
为production
则process.env.NODE_ENV
的值为 production
。
我们啦测试下,定义入口文件index.js
,在里面输出process.env.NODE_ENV
的值。
// index.js
console.log(process.env.NODE_ENV);
复制代码
我们分别构建,然后运行构建后的js
。
npm run dev
npm run staging
npm run build
可以看到,开发环境process.env.NODE_ENV
的值为development
,测试和生产环境的值是production
。
这个没问题,那么我们上面设置的process.env.MODE
的值能获取到吗?
代码中获取自定义环境变量值
我们再来试试
// index.js
console.log(process.env.NODE_ENV);
console.log(process.env.MODE);
复制代码
再次构建,发现居然是undefined
这就有问题啦,如果我们代码中需要根据不同环境做不同处理那应该怎么办?其实我们可以用process.env.NODE_ENV
的思路,其实它就是根据mode
的不同使用DefinePlugin
插件来动态设置值的,所以我们也使用这个插件处理下。
const webpack = require("webpack");
// ...
module.exports = (env, argv) => {
if (process.env.MODE === "development") {
config.mode = "development";
} else {
config.mode = "production";
}
// 根据参数,重新定义三种模式
config.plugins.push(
new webpack.DefinePlugin({
"process.env.MODE": JSON.stringify(process.env.MODE),
})
);
return config;
};
复制代码
我们分别构建,然后运行构建后的js
。
npm run dev
npm run staging
npm run build
可以看到,process.env.NODE_ENV
和process.env.MODE
的值都能在我们的代码中正确获取到了,这样我们不仅能根据不同环境配置我们的webpack.config.js
,还能在我们的代码中根据不同的环境进行不同的处理。
这里我们根据不同的环境只设置了mode
,其实还有很多属性都可以在不同的环境进行不同的配置,比如我们下面要说的devtool
。
devtool
devtool
用于控制是否生成,以及如何生成 source map
什么是 sourceMap
SourceMap
是一个映射关系。能够帮我们更好的定位源码的错误。
举个例子,现在我们发现打包出来的 dist
目录下的 main.js
的 97
行报错了,但因为他是打包后的文件,我们知道 main.js
第几行报错其实没有任何意义。这个时候 sourcemap
就出来帮我们解决了这个问题,因为他是打包文件和源码的一个映射关系,它知道 dist
目录下 main.js
文件的 97
行 实际上对应的 src
目录下的 index.js
文件的第几行,这样我们就能够快速定位问题,并进行修复了。
devtool默认值
devtool
默认值在生产环境下,也就是mode
为production
,值是false
。在开发环境下也就是mode
为development
,值是eval
。
devtool种类
其实devtool
的值还有很多,不同的值会生成不同的SourceMap
。
从上图中我们可以看到 devtool
有非常多的配置,不同的配置构建的速度会有一些差异,中间的很多参数都是可以穿插使用的。
更多值可以参看devtool官方文档
我们简单来测试下,在源码index.js
文件中使用一个未定义的变量
// index.js
// ...
// 定义一个错误
console.log(e);
复制代码
总的来说说,其实devtool
主要分为以下几类,我们分别测试下
false
false
就是不使用SourceMap
,所以它不会生成SourceMap
文件。
因此它就不能准确定位到源码出错位置。
inline
inine
有这个的配置,直接会将 .map
文件以 base64
的形式直接打包到对应的 js
中去,而不会单独生成.map
文件,从而加快相应的速度。
可以看到这种方式它能精准定位到源码行数
cheap
cheap
有这个的配置,意思是 map
文件只会帮你定为到具体的某一行,并不会把代码定位到 具体的 某一行 某一列,从而加快速度;cheap
还有一个作用,就是这个选项只使针对业务代码,也就是说只能定位到业务代码里面的错误,并不能定位到我们引用的第三方文件(比如说 loader
,第三方模块)的错误。
会单独生成.map
文件
定位的稍微有点问题,不那么准确
module
module
有这个的配置,意思是 它不仅会帮我们定位 自己的业务代码中的错误,还会同时帮我们定位第三方模块的错误。
eval
eval
有这个的配置,使用eval
包裹模块代码,并且使用 //@sourceURL
引入SourceMap
文件,这个是打包速度最快,性能最好的的一种方式,但是有的时候,对于代码比较复杂的情况,它提示出来的错误可能不够全面。
hidden
生成 SourceMap
文件,但不使用。
最佳实践
有了上面的基础,我们就能根据不同环境进行不同devtool
的配置啦。
const webpack = require("webpack");
// ...
module.exports = (env, argv) => {
if (process.env.MODE === "development") {
config.mode = "development";
config.devtool = "eval-cheap-module-source-map"
} else if(process.env.MODE === "staging") {
config.mode = "production";
config.devtool = "source-map"
} else {
config.mode = "production";
config.devtool = false
}
// 根据参数,重新定义三种模式
config.plugins.push(
new webpack.DefinePlugin({
"process.env.MODE": JSON.stringify(process.env.MODE),
})
);
return config;
};
复制代码
本地开发我们配置eval-cheap-module-source-map"
使用最详细的SourceMap
。
测试环境我们有可能需要在线调试错误,所以配置source-map
。
生产环境直接禁用SourceMap
,一是能缩小构建后包的体积,其次能防止别人窃取源码。
dev-server
前面讲的,开发环境每次修改代码还要执行npm run dev
,这样效率太低了,有没有更好的更快的方法呢?
当然是有的,我们可以使用webpack-dev-server
。
webpack-dev-server
支持热部署、跨域代理、数据模拟等等。
安装
我们先来安装下
npm i webpack-dev-server -D
复制代码
配置
使用webpack-dev-server
后我们的构建命令不再是webpack
了,而是webpack-dev-server
,所以我们首先修改下构建命令。
"dev": "cross-env MODE=development webpack-dev-server"
复制代码
接下来,我们在webpack.config.js
里面进行配置
const config = {
// ...
devServer: {
// 新版 配置static而不是
static: path.resolve(__dirname, "./devdist"), // 静态文件目录
port: 8080, // 端口号
open:true // 是否自动打开浏览器
},
}
复制代码
static
就是服务的目录,这里我们定位到构建后的目录。
我们执行npm run dev
,就会自动打开浏览器,在8080
端口启动服务了。我们修改代码就能实时编译了。
如果有调用后端api
需求的话,我们还可以配置代理
配置代理
const config = {
// ...
devServer: {
// 新版 配置static而不是
static: path.resolve(__dirname, "./devdist"), // 静态文件目录
port: 8080, // 端口号
open:true, // 是否自动打开浏览器
proxy: {
'/api': 'http://localhost:3000',
// 接受在 HTTPS 上运行且证书无效的后端服务器
secure: false,
},
},
}
复制代码
当我们请求/api
的时候就可以代理到http://localhost:3000
上去了。
mock数据
我们还可以利用webpack-dev-server
来mock
数据。
我们在我们的index.js添加请求
// index.js
fetch("/user")
.then((res) => res.json())
.then((data) => {
console.log(data);
});
复制代码
然后使用devServer
进行数据mock
。
devServer: {
// 新版 配置static而不是
static: path.resolve(__dirname, "./devdist"), // 静态文件目录
compress: true, //是否启动压缩 gzip
port: 8080, // 端口号
// open:true // 是否自动打开浏览器
// 新版不是before,而是onBeforeSetupMiddleware
onBeforeSetupMiddleware(devServer) {
devServer.app.get("/user", (req, res) => {
res.json({ name: "randy" });
});
},
},
复制代码
构建,在浏览器控制台可以看到我们mock
的数据输出来了。
当然devServer
远不止这些功能,大家可以看看devServer官方文档。
后记
好了,关于webpack
环境相关的笔者今天先讲到这里啦。
感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!