关于 Webpack4
create by db on 2022-11-9 15:47:48
Recently revised in 2022-11-9 16:42:11闲时要有吃紧的心思,忙时要有悠闲的趣味
前言
本文基于 webpack4。
正文
一、Webpack 介绍
Webpack 是什么?
webpack 是一个现代 JavaScript 应用程序的静态模块打包器,webpack 本质上是一个打包工具,它会根据代码的内容解析模块依赖,帮助我们把多个模块的代码打包。
如下图,webpack 会把我们项目中使用到的多个代码模块(可以是不同文件类型),打包构建成项目运行仅需要的几个静态文件。
Webpack 的核心概念
1. 入口(Entry):
- 指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。
2. 输出(Output):
- 指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。
3. Loader(加载器)
- 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript), 我们可以把 loader 理解为是一个转换器,负责把某种文件格式的内容转换成 webpack 可以支持打包的模块。
4. 插件(Plugin):
- 可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。可以这么理解,模块代码转换的工作由 loader 来处理,除此之外的其他任何工作都可以交由 plugin 来完成。
5. 模式(Mode):
- 指示 webpack 使用相应模式的配置。develop 模式,production 模式,不同的运行环境上线运行。
Webpack 的执行流程
一句话形容 webpack:根据入口文件 entry 的依赖关系(内部依赖图),将这些资源全部引进来,引进来形成 chunk 代码块,chunk 会根据不同的资源进行处理,这个处理过程叫打包;输出的东西,叫做 bundle。
一个简单的 webpack 配置
我们把上述涉及的几部分配置内容合到一起,就可以创建一个简单的 webpack 配置了,webpack 运行时默认读取项目下的 webpack.config.js 文件作为配置。所以我们在项目中创建一个 webpack.config.js 文件:
const path = require("path");
const UglifyPlugin = require("uglifyjs-webpack-plugin");
module.exports = {
entry: "./src/index.js", // 入口
entry: "./src/index.js", // 入口
output: { // 出口
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
module: {
rules: [ // 配置Loader
{
test: /\.jsx?/,
include: [path.resolve(__dirname, "src")],
use: "babel-loader",
},
],
},
// 代码模块路径解析的配置
resolve: {
modules: ["node_modules", path.resolve(__dirname, "src")],
extensions: [".wasm", ".mjs", ".js", ".json", ".jsx"],
},
plugins: [ // 配置Plugin
new UglifyPlugin(), // 使用 uglifyjs-webpack-plugin 来压缩 JS 代码
],
};
webpack 的配置其实是一个 Node.js 的脚本,这个脚本对外暴露一个配置对象,webpack 通过这个对象来读取相关的一些配置。
二、常用 Loader
css-loader
css-loader 负责解析 CSS 代码,主要是为了处理 CSS 中的依赖,例如 @import 和 url() 等引用外部文件的声明;
style-loader
style-loader 会将 css-loader 解析的结果转变成 JS 代码,运行时动态插入 style 标签来让 CSS 代码生效。
less-loader/sass-loader
在上述使用 CSS 的基础上,通常我们会使用 Less/Sass 等 CSS 预处理器,webpack 可以通过添加对应的 loader 来支持
file-loader
图片对应的 jpg/png/gif 等文件格式,webpack 处理不了。file-loader 可以用于处理很多类型的文件,它的主要作用是直接输出文件,把构建后的文件路径返回。
babel-loader
Babel 是一个让我们能够使用 ES 新特性的 JS 编译工具,我们可以在 webpack 中配置 Babel,以便使用 ES6、ES7 标准来编写 JS 代码。
三、常用 Plugin
DefinePlugin
DefinePlugin 是 webpack 内置的插件,可以使用 webpack.DefinePlugin 直接获取。 这个插件用于创建一些在编译时可以配置的全局常量,这些常量的值我们可以在 webpack 的配置中去指定。
copy-webpack-plugin
我们一般会把开发的所有源码和资源文件放在 src/ 目录下,构建的时候产出一个 build/ 目录,通常会直接拿 build 中的所有文件来发布。有些文件没经过 webpack 处理,但是我们希望它们也能出现在 build 目录下,这时就可以使用 CopyWebpackPlugin 来处理了
extract-text-webpack-plugin
可以用它来把依赖的 CSS 分离出来成为单独的文件
四、Webpack 优化
资源体积优化
图片体积压缩
图像压缩可使用 image-webpack-loader 进行压缩
CSS 代码压缩
CSS 代码压缩使用 css-minimizer-webpack-plugin,效果包括压缩、去重。不过代码的压缩比较耗时间,所以只用在打包项目时,所以只需要在 webpack.prod.js 中配置
JS 代码压缩
S 代码压缩使用 terser-webpack-plugin,实现打包后 JS 代码的压缩(代码的压缩比较耗时间,所以只用在打包项目时)
抽离重复代码
SplitChunksPlugin 插件开箱即用,可以将公共的依赖模块提取到已有的入 chunk 中,或者提取到一个新生成的 chunk。将公共的模块单独打包,不再重复引入。
构建区分环境
开发环境主要实现的是热更新,不要压缩代码,完整的 sourceMap。 生产环境主要实现的是压缩代码、提取 css 文件、合理的 sourceMap、分割代码
缩小文件的搜索范围
配置 include,exclude,alias 等
-
alias: 当我们代码中出现 import 'vue'时, webpack 会采用向上递归搜索的方式去 node_modules 目录下找。为了减少搜索范围我们可以直接告诉 webpack 去哪个路径下查找。也就是别名(alias)的配置。
-
include exclude 同样配置 include exclude 也可以减少 webpack loader 的搜索转换时间。
打包速度优化
cache-loader
cache-loader 可以缓存资源,提高二次构建的速度,使用方法是将 cache-loader 放在比较费时间的 loader 之前,比如 babel-loader
thread-loader
thread-loader 可以把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
把 thread-loader 放置在其它 loader 之前,那么放置在这个 loader 之后的 loader 就会在一个单独的 worker 池中运行。
五、Webpack5
Webpack5 在 2020 年 10 月 10 日正式发布,我们看下 Webpack5 有什么优势。
1. 压缩代码
Webpack4 上需要下载安装 terser-webpack-plugin 插件
Webpack5 内部本身就自带 js 压缩功能,他内置了 terser-webpack-plugin 插件,我们不用再下载安装。而且在 mode=“production” 的时候会自动开启 js 压缩功能。
2. 缓存
webpack4 缓存需要下载安装 hard-source-webpack-plugin 插件
webpack5 内部内置了 cache 缓存机制。直接配置即可。
3. 更强大的 tree-shaking
tree-shaking 就在打包的时候剔除没有用到的代码
webpack4 本身的 tree shaking 比较简单(直接 import 整个文件或者对象内部未使用的不能被剔除;commonJs 模式不支持),主要是找一个 import 进来的变量是否在这个模块内出现过
webpack5 可以进行根据作用域之间的关系来进行优化,开始支持分析模块的引用关系
4、持久化缓存的优化
以前 v4 是根据代码的结构生成 chunkhash,现在 v5 根据完全内容生成 chunkhash,比如改了内容的注释或者变量则不会引起 chunkhash 的变化,让浏览器继续使用缓存。
在 webpack4 中,chunkId 与 moduleId 都是自增 id。也就是只要我们新增一个模块,那么代码中 module 的数量就会发生变化,从而导致 moduleId 发生变化,于是文件内容就发生了变化。chunkId 也是如此,新增一个入口的时候,chunk 数量的变化造成了 chunkId 的变化,导致了文件内容变化。
webpack4 可以通过设置 optimization.moduleIds ='hashed’optimization.namedChunks=true 来解决这写问题,但都有性能损耗等副作用。
而 webpack5 在 production 模式下 optimization.chunkIds 和 optimization.moduleIds 默认会设为’deterministic’,webpack 会采用新的算法来计算确定性的 chunkI 和 moduleId。
总结
参考文档
后记:Hello 小伙伴们,如果觉得本文还不错,记得点个赞或者给个 star,你们的赞和 star 是我编写更多更丰富文章的动力!GitHub 地址
文档协议
db 的文档库 由 db 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于github.com/danygitgit上的作品创作。
本许可协议授权之外的使用权限可以从 creativecommons.org/licenses/by… 处获得。