打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
十分钟——带你了解webpack的主要配置
简单说几句
webpack 本质上是一个打包工具,它会根据代码的内容解析模块依赖,帮助我们把多个模块的代码打包。借用 webpack 官网的图片。
webpack入口
多个代码模块中会有一个起始的.js文件,这个便是 webpack 构建的入口。webpack 会读取这个文件,并从他开始解析依赖,然后进行打包。默认的入口文件就是./src/index.js。
常见的项目中,多是单页面应用,那么可能入口只有一个;如果是多页面应用,那么就是多个页面对应多个构建入口了。入口可以使用entry来进行配置,webpack 支持配置多个入口来进行构建:
// 单个入口
module.exports = {
entry: './src/index.js'
}
// 上述配置等同于
module.exports = {
entry: {
main: './stc/index.js'
}
}
// 或者配置多个入口
module.exports = {
entry: {
foo: './src/page-foo.js',
bar: './src/page-bar.js',
// ...
}
}
// 使用数组来对多个文件进行打包也可
// 也可以理解为多个文件作为一个入口,webpack会解析两个文件的依赖后进行打包
module.exports = {
entry: {
main: [
'./src/foo.js',
'./src/bar.js'
]
}
}
loader
webpack 中提供了一种处理多种文件格式的机制,便是使用 loader。我们可以把 loader 理解为一个转换器,负责把某种文件格式的内容转换为 webpack 可以支持打包的模块。
举个例子,在没有添加额外插件的情况下,webpack 会默认把所有依赖打包为 js 文件,入口入口文件依赖一个.hbs 的模板文件以及一个.css 的样式文件,那么我们需要handlebars-loader来处理.hbs 文件,需要css-loader来处理.css 文件(这里还需要style-loader,后续详解),最终把不同格式的文件都解析成 js 代码,以便打包在浏览器中运行。
当我们需要不同的 loader 来解析处理不同类型的文件时,我们可以在modul.rules字段下来配置相关的规则,例如使用 Babel 来处理.js 文件
module.exports = {
module: {
// ...
rules: [
{
test: /\.jsx?/, // 匹配文件路径的正则表达式,通常用来匹配文件后缀名
include: [
path.resolve(__dirname, 'src') // 指定那些路径下的文件需要启用loader的处理
],
use: 'babel-loader' // 指定使用的loader
}
]
}
}
loader 是 webpack 中比较复杂的一块内容,它支撑着 webpack 来处理文件的多样性,后续我们还会介绍如何更好地使用 loader 以及如何开发 loader。
plugin
在 webpack 的构建流程中,plugin 用于处理更多其他的一些构建任务。可以这么理解,模块代码转换的工作由 loader 来处理,除此之外的其他任何工作都可以交由 plugin 来完成。通过添加我们需要的 plugin,可以满足更多构建中的特殊需求。例如,要使用压缩 js 代码的uglifyjs-webpack-plugin插件,只需在配置中通过plugins字段添加新的 plugin 即可:
import UglifyPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
// ...
plugins: [
new UglifyPlugin()
]
}
除了压缩 js 代码的uglifyjs-webpack-plugin,常用的还有定义环境变量的DefinePlugin,生成 css 文件的ExtractTextWebpackPlugin等。
plugin 理论上可以干涉 webpack 整个构建流程,可以在流程的每一个步骤中定制自己的构建需求。
输出
webpack 的输出即指 webpack 最终构建出来的静态文件,可以看看上面的 webpack 官方图片右侧的那些文件。当然,构建结果的文件名、路径等都是可以配置的,使用output字段。
const path = require('path');
module.exports = {
// ...
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
}
// 或者多个入口生成不同的文件
module.exports = {
entry: {
foo: './src/foo.js',
bar: './src/bar.js'
},
output: {
filename: '[name].js',
path: __dirname '/dist/'
}
}
// 在路径中使用hash,每次构建时会有一个不同hash值,避免发布新版本时线上使用浏览器缓存
module.exports = {
// ...
output: {
filename: '[name].js',
path: __dirname '/dist/[hash]'
}
}
我们一开始直接使用 webpack 构建时,默认创建的输出内容就是./dist/main.js。
开发环境和生产环境配置的差异
一般在前端开发中,都会有两套的构建环境:一套开发时使用,构建结果用于本地调试,不进行代码压缩,打印 debug 信息,包含 sourcemap 文件;另一台构建后的结果应用于生产环境,代码需要经过压缩,运行时不打印 debug 信息,静态文件不包括 sourcemap 的。有的时候还需要一套测试环境,在运行时直接请求 mock 等工作。
在配置文件中区分 mode
webpack 的配置文件都是直接暴露一个 js 对象,这种方式暂时没有办法获取到 webpack 的 mode 参数,所以需要一些曲线救国的方式。特别是在 webpack 3.x 版本中,只能依靠运行环境的 node 提供的机制来给 webpack 传递环境变量,控制不同环境下的构建行为,例如:我们在 npm 中的scripts字段添加一个用于生产环境的构建命令:
'scripts': {
'build': 'NODE_ENV=production webpack',
'develop': 'NODE_ENV=development webpack-dev-server'
}
然后在webpack.config.js中通过process.env.NODE_ENV来获取命令传入的环境变量
const config = {
// webpack配置
}
if(process.env.NODE_ENV === 'production'){
// 生产环境需要做的事,比如使用代码压缩插件等
config.plugins.push(new UglifyJsPlugin())
}
module.exports = config;
在 webpack4.x 的做法略有不同,不需要这么曲线救国的方式获取环境变量了,根据官方文档多种配置类型[1],配置文件可以对外暴露一个函数,因此我们可以这么做:
module.exports = (env, argv) => ({
// ... 其他配置
optimization: {
minimize: false,
// 使用argv.mode来获取环境参数
minimizer: argv.mode === 'production' ? [
new UglifyJsPlugin({}),
// 其他需要在产生环境配置的plugin
] : [
// 开发环境
]
}
})
这样获取到 mode 之后,就可以根据不同的环境来配置不同的 loader 和 plugin 了。
4.x 也可以通过设置mode[2],或者从 CLI 参数中传递 webpack --mode=production
选项描述
development会将DefinePlugin中的process.env.NODE_ENV的值设置为development。启用NamedChunksPlugin和NameModulesPlugin。
production会将DefinePlugin中的process.env.NODE_ENV的值设置为production。启用FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin。
none退出任何默认优化选项
如果没有设置,webpack 会将mode默认值设置为production。记住,设置NODE_ENV并不会自动地设置mode。
运行时的环境变量
在 webpack4.x 中,可以直接在项目运行时访问process.env.NODE_ENV来访问环境变量,而在 3.x 中就需要我们使用DefinePlugin插件手动的声明环境变量了。
const webpack = require('webpack');
module.exports = {
// webpack配置
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
]
}
常见的环境差异配置
生产环境可能需要分离 css 成单独的文件,以便多个页面共享同一个 css 文件
生产环境需要压缩 html/css/js 代码
生产环境需要压缩图片
开发环境需要生成 sourcemap 文件
开发环境需要打印 debug 信息
开发环境需要 live reload 或者 hot reload 功能
以上便是常见的环境需求差异,可能更加复杂的项目中会有更多的构建需求(如划分静态域名等),但是我们都可以通过判断环境变量来实现这些有环境差异的构建需求。
webpack4.x 已经提供了上述差异配置的大部分功能,mode 为 production 时默认使用 js 代码压缩,而 mode 为 development 时默认启用 hot reload 功能等等。这样让我们配置更为简洁,只需要针对特别使用的 loader 和 pulugin 就可以了。
webpack3.x 版本则还是只能自己手动修改配置来满足大部分差异需求。
拆分配置
前面列出的几个环境差异的配置,可能这些构件需求就已经有点多了,会让整个 webpack 的配置变得复杂,尤其是有这大量环境变量判断的配置。我们可以把 webpack 的配置按照不同的环境拆分为多个文件,运行时直接根据环境变量加载对应的配置即可。基本的划分如下:
webpack.base.js: 基础部分,即多个文件中共享的配置
webpack.development.js: 开发环境使用的配置
webpack.prodution.js: 生成环境使用的配置
webpack.test.js: 测试环境使用的配置
首先我们知道,对于 webpack 的配置,其实本质上就是一个 js 对象,所以对于这个对象,我们可以使用 js 代码来修改:
const config = {
// ... webpack配置
}
// 我们可以修改这个config来调整配置,例如添加一个新的插件
config.plugins.push(new YourPlugin());
module.exports = config;
我们可以使用webpack-merge工具,它会通过判断环境变量,然后比较智能地合并多个配置对象,这样就可以很轻松的拆分 webapck 配置了。
# 首先需要安装 webpack-merge
npm install -D webpack-merge
# or
yarn add -D webpack-merge
然后配置 webapck.base.js,大概是这样:
// webpack.base.js
module.exports = {
entry: '...',
output: {
// ...
},
resolve: {
// ...
},
module: {
// 这里是一个简单的例子
rules: [
{
test: /\.js$/,
use: ['babel']
}
]
},
plugins: [
// ...
]
}
然后 webpack.development.js 需要添加开发环境的 loader 和 plugin,就可以使用 webpack-merge 的 api 了:
// webpack.development.js
const {smart} = require('webpack-merge');
const webpack = require('webpack');
const base = require('./webpack.base.js');
// 用smart api,rules中的匹配规则相同,use又都是数组的时候,smart会识别后处理
module.exports = smart(base, {
module: {
rules: [
{
test: /\.js$/,
use: ['coffee']
}
// 和上述base配置合并后,这里是{test: /\.js$/, use: ['babel', 'coffee']}
// 如果use的值用的是字符串或者对象的话,那么就会替换掉原本的规则use的值
]
},
plugins: [
// plugins这里的数组会和base中的plugins数组合并
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
]
})
可见 webpack-merge 插件提供的 smart 方法,可以帮助我们更加轻松的处理 loader 配置的合并。webpack-merge 还有其他 api 可以用于自定义合并行为,这里就不详细介绍了,可以查阅官方文档[3]
每次花个十分钟,懂一个前端知识点,走得虽慢,但坚持走下去,足以致千里。
参考资料
[1]
多种配置类型: https://webpack.docschina.org/configuration/configuration-types/
[2]
mode: https://webpack.docschina.org/concepts/mode/
[3]
官方文档: https://github.com/survivejs/webpack-merge
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
我们如何使用 Webpack 将启动时间减少 80%
webpack4.0各个击破(2)—— CSS篇
SCSS提取和懒加载
webpack进阶之插件篇
Babel介绍
Vue学习笔记之Webpack环境中集成Vuejs的配置过程与使用
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服