对于入门选手来讲,webpack 配置项很多很重,如何快速配置一个可用于线上环境的 webpack 就是一件值得思考的事情。其实熟悉 webpack 之后会发现很简单,基础的配置可以分为以下几个方面: entry
、 output
、 mode
、 resolve
、 module
、 optimization
、 plugin
、 source map
、 performance
等,本文就来重点分析下这些部分。
将源文件加入到 webpack 构建流程,可以是单入口:
构建包名称 [name]
为 main
;
或多入口:
key:value
键值对的形式:
[name]
,在这里为 index
入口决定 webapck 从哪个模块开始生成依赖关系图(构建包),每一个入口文件都对应着一个依赖关系图。
当构建项目包含多个子项目时,每次增加一个子系统都需要将入口文件写入 webpack 配置文件中,其实我们让webpack 动态获取入口文件,例如:
则会将所有匹配 ./project/**/index.js
的文件作为入口文件进行打包,如果你想要增加一个子项目,仅仅需要在 project
创建一个子项目目录,并创建一个 index.js
作为入口文件即可。
这种方式比较适合入口文件不集中且较多的场景。
在构建多系统应用或组件库时,我们每次打包可能仅仅需要打包某一模块,此时,可以通过命令行的形式请求打印某一模块,例如:
在打包的时候解析命令行参数:
然后配置入口:
相当于:
当然,你可以传入其它参数,也可以应用于多个地方,例如 resolve.alias
中。
用于告知 webpack 如何构建编译后的文件,可以自定义输出文件的位置和名称:
在 webpack4 开发模式下,会默认启动 output.pathinfo
,它会输出一些额外的注释信息,对项目调试非常有用,尤其是使用 eval devtool 时。
filename
:[name]
为 entry 配置的 key
,除此之外,还可以是 [id]
(内部块 id )、 [hash]
、[contenthash]
等。
对于我们开发的每一个应用,浏览器都会对静态资源进行缓存,如果我们更新了静态资源,而没有更新静态资源名称(或路径),浏览器就可能因为缓存的问题获取不到更新的资源。在我们使用 webpack 进行打包的时候,webpack 提供了 hash 的概念,所以我们可以使用 hash 来打包。
在定义包名称(例如 chunkFilename
、 filename
),我们一般会用到哈希值,不同的哈希值使用的场景不同:
build-specific, 哈希值对应每一次构建( Compilation
),即每次编译都不同,即使文件内容都没有改变,并且所有的资源都共享这一个哈希值,此时,浏览器缓存就没有用了,可以用在开发环境,生产环境不适用。
chunk-specific, 哈希值对应于 webpack 每个入口点,每个入口都有自己的哈希值。如果在某一入口文件创建的关系依赖图上存在文件内容发生了变化,那么相应入口文件的 chunkhash
才会发生变化,适用于生产环境
content-specific,根据包内容计算出的哈希值,只要包内容不变,contenthash
就不变,适用于生产环境
webpack 也允许哈希的切片。如果你写 [hash:8]
,那么它会获取哈希值的前 8 位。
filename
影响,受 chunkFilename
影响hash/chunkhash/contenthash
一般会配合 html-webpack-plugin
(创建 html ,并捆绑相应的打包文件) 、clean-webpack-plugin
(清除原有打包文件) 一起使用。当使用 webapck 构建一个可以被其它模块引用的库时:
设置 mode
,可以让 webpack 自动调起相应的内置优化。参考 前端进阶面试题详细解答
或在命令行里配置:
在设置了 mode
之后,webpack4 会同步配置 process.env.NODE_ENV
为 development
或 production
。
webpack4 最引人注目的主要是:
打包时间减小了超过 60%
我们可以在没有任何配置文件的情况下将 webpack 用于各种项目
webpack4 支持零配置使用,这里的零配置就是指,mode
以及 entry
(默认为 src/index.js
)都可以通过入口文件指定,并且 webpack4 针对对不同的 mode
内置相应的优化策略。
配置:
相当于默认内置了:
配置:
相当于默认内置了:
不进行任何默认优化选项。
配置:
相当于默认内置了:
production 模式下给你更好的用户体验:
development 模式会给予你最好的开发体验:
尽管 webpack4 在尽力让零配置做到更多,但仍然是有限度的,大多数情况下还是需要一个配置文件。我们可以在项目的初期使用零配置,在后期业务复杂的时候再配置。
第三方框架或库,以及我们的业务代码,都会针对不同的环境配置,执行不同的逻辑代码,例如:
我们可以通过以下方式定义环境变量:
方法一:webpack4 中 mode: 'production' 已经默认配置了 process.env.NODE_ENV = 'production' ,所以 webapck4 可以不定义
尽管 webpack4 中定义 mode
会自动配置 process.env.NODE_ENV
,那么我们就不需要手动配置环境变量了吗?
其实不然,mode
只可以定义成 development
或 production
,而在项目中,我们不仅仅只有开发或生产环境,很多情况下需要配置不同的环境(例如测试环境),此时我们就需要手动配置其它环境变量(例如测试环境,就需要定义 process.env.NODE_ENV
为 'test'
),你可以采取以下方式:
方法二:webpack.DefinePlugin
config/prod.env.js
:
方法三:webpack 命令时, NODE_ENV=development
在 window 中配置 NODE_ENV=production
可能会卡住,所以使用 cross-env:
方法四:使用 new webpack.EnvironmentPlugin(['NODE_ENV'])
EnvironmentPlugin
是一个通过 webpack.DefinePlugin
来设置 process.env
环境变量的快捷方式。
注意:上面其实是给 NODE_ENV
设置一个默认值 'production'
,如果其它地方有定义 process.env.NODE_ENV
,则该默认值无效。
自定义寻找依赖模块时的策略(例如 import _ from 'lodash'
):
决定如何处理项目中不同类型的模块,通常是配置 module.rules 里的 Loader:
指明 webpack 不去解析某些内容,该方式有助于提升 webpack 的构建性能。
常见的 loader 有:
babel-loader
:解析 .js
和 .jsx
文件// 配置 .babelrc
{
}
tsx-loader
:处理 ts 文件less-loader
:处理 less 文件,并将其编译为 csssass-loader
:处理 sass、scss 文件,并将其编译为 csspostcss-loader
:// postcss.config.js
module.exports = { // 解析CSS文件并且添加浏览器前缀到 CSS 内容里
};
css-loader
:处理 css 文件style-loader
:将 css 注入到 DOMfile-loader
:将文件上的import
/ require
解析为 url
,并将该文件输出到输出目录中url-loader
:用于将文件转换成 base64 uri 的 webpack 加载程序html-loader
:将 HTML 导出为字符串, 当编译器要求时,将 HTML 最小化webapck4 会根据你所选择的 mode
进行优化,你可以手动配置,它将会覆盖自动优化
主要涉及两方面的优化:
optimization.removeAvailableModules
删除已可用模块optimization.removeEmptyChunks
删除空模块optimization.occurrenceOrder
标记模块的加载顺序,使初始包更小optimization.providedExports
、 optimization.usedExports
、concatenateModules
、optimization.sideEffects
删除死代码optimization.splitChunks
提取公共包optimization.minimizer
|| TerserPlugin
来最小化包当包过大时,如果我们更新一小部分的包内容,那么整个包都需要重新加载,如果我们把这个包拆分,那么我们仅仅需要重新加载发生内容变更的包,而不是所有包,有效的利用了缓存。
很多情况下,我们不需要手动拆分包,可以使用 optimization.splitChunks
:
我们不必制定拆包策略,chunks: all
会自动将 node_modules
中的所有内容放入一个名为 vendors〜main.js
的文件中。
采用多入口的方式,当有业务代码更新时,更新相应的包即可
当第三方包更新时,仅更新相应的包即可。
注意,当包太多时,浏览器会发起更多的请求,并且当文件过小时,对代码压缩也有影响。
现在我们已经对包拆分的很彻底了,但以上的拆分仅仅是对浏览器缓存方面的优化,减小首屏加载时间,实际上我们也可以使用按需加载的方式来进一步拆分,减小首屏加载时间:
配置 Plugin 去处理及优化其它的需求,
常用 plugins:
html-webpack-plugin
:生成 html 文件,并将包添加到 html 中webpack-parallel-uglify-plugin
:压缩 js(多进程并行处理压缩)happypack
:多线程loader,用于提升构建速度hard-source-webpack-plugin
:为模块提供中间缓存步骤,显著提高打包速度webpack-merge
:合并 webpack 配置mini-css-extract-plugin
:抽离 cssoptimize-css-assets-webpack-plugin
:压缩 cssadd-asset-html-webpack-plugin
:将 JavaScript 或 CSS 资产添加到 html-webpack-plugin 生成的 HTML 中更多插件可见:plugins
配置 webpack 如何生成 Source Map,用来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度:
生产环境:默认为 null
,一般不设置( none
)或 nosources-source-map
开发环境:默认为 eval
,一般设置为 eval
、 cheap-eval-source-map
、cheap-module-eval-source-map
策略为:
如果默认的 webpack minimizer
已经被重定义(例如 terser-webpack-plugin
),你必须提供 sourceMap:true
选项来启用 source map 支持。
当打包是出现超过特定文件限制的资产和入口点,performance
控制 webpack 如何通知:
监视文件更新,并在文件更新时重新编译:
在 webpack-dev-server
和 webpack-dev-middleware
中,默认启用了监视模式。
或者我们可以在命令行里启动监听( --watch
):
排除打包时的依赖项,不纳入打包范围内,例如你项目中使用了 jquery
,并且你在 html 中引入了它,那么在打包时就不需要再把它打包进去:
配置:
构建目标,用于为 webpack 指定一个环境:
缓存生成的 webpack 模块和块以提高构建速度。在开发模式中,缓存设置为 type: 'memory'
,在生产模式中禁用。cache: true
是 cache: {type: 'memory'}
的别名。要禁用缓存传递 false
:
在内存中,缓存仅在监视模式下有用,并且我们假设你在开发中使用监视模式。 在不进行缓存的情况下,内存占用空间较小。
配置的名称,用于加载多个配置:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。