原稿:语雀 · webpack 知识点 · 原目录:Webpack › webpack 知识点

为什么要使用 webpack,不直接 require?

直接 require,而不打包,每个模块都会单独通过 http 传输下载并加载,而打包后就只有一个模块需要下载。编译后打包减少了页面的 http 请求,减少了页面加载时间,从而增加了页面的显示速度

webpack 核心概念

  • 入口(entry):入口起点(entry point)指示 webpack 应该使用哪个模块作为构建内部依赖图(dependency graph) 的开始。进入入口起点后,webpack 会递归地找出有哪些模块和库是入口起点依赖的
  • 模块(module):在 webpack 中,一个模块对应一个文件
  • 代码块(Chunk):代码块,一个 chunk 由多个模块组合而成,用于代码合并与分割
  • 加载器(loader):webpack 只能理解 JavaScript 和 JSON 文件,而各种 loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中
  • 插件(plugin):loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量
  • 输出(output):输出属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中
  • 输出束(bundle):由许多不同的模块生成,是已经经过加载和编译过程的源文件的最终版本

如何区分 module、chunk、bundle?

参考链接:webpack 中,module,chunk 和 bundle 的区别是什么?

image-20200518210532171.png
- 对于一份同逻辑的代码,当手写下每一个文件,无论是 ESM 还是 commonJS 或是 AMD,他们都是 module - 当 module 源文件传到 webpack 进行打包时,webpack 会根据文件引用关系生成 chunk 文件,webpack 会对这个 chunk 文件进行一些操作 - webpack 处理好 chunk 文件后,最后会输出 bundle 文件,这个 bundle 文件包含了经过加载和编译的最终源文件,所以它可以直接在浏览器中运行

一般来说一个 chunk 对应一个 bundle,比如上图中的 utils.js -> chunks 1 -> utils.bundle.js;但也有例外,比如说上图中,使用 MiniCssExtractPlugin 从 chunks 0 中抽离出了 index.bundle.css 文件

总结:module,chunk 和 bundle 其实就是同一份逻辑代码在不同转换场景下的取了三个名字:未经打包的源文件是 module,chunk 强调 webpack 模块捆绑过程,最后生成浏览器可以直接运行的 bundle


webpack 构建流程

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程: 2. 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数; 4. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译; 6. 确定入口:根据配置中的 entry 找出所有的入口文件; 8. 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理; 10. 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系; 12. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会; 14. 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果


loader 与 plugin

Loader 和 Plugin 区分

loader

plugin

作用

Webpack 将一切文件视为模块,但是原生只能解析 js 和 json 文件,如果想将其他文件也作为模块处理,就会用到 loader,所以 Loader的作用是让 webpack 拥有了加载和解析非 JS 文件的能力

Plugin 可以扩展 webpack 的功能,让 webpack 具有更多的灵活性,解决 loader 无法实现的事情。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

用法

通常在 module.rules 中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个 Object,里面描述了对于什么类型的文件(test),使用什么 loader 加载 (use) 和以及参数(options)

在配置文件中引入,在 module.plugins 中通过 new 实例化

image.png
image.png

Loader 原理

loader 到底做了什么?

由于 webpack 是基于Node 的所以 webpack 只能识别 js 文件,所以针对其他的文件就需要转译。loader 是文件加载器,能够加载不同类型资源文件,并对这些文件进行特定的处理,然后打包的指定文件中,简单来说就是将webpack 传入的字符串做出特定的处理修改

loader 特点

  • loader 的执行顺序和配置文件 use 引用顺序相反,即:最后一个 loader 最先执行,第一个 loader 最后执行
  • 第一个执行的 loader 会接收源文件做为参数,下一次执行的 loader 会接收前一个 loader 执行的返回值做为参数

loader 编写原则

  • 单一原则:每个 Loader 只做一件事;
  • 链式调用:Webpack 会链式依次调用每个 Loader;
  • 统一原则:遵循 Webpack 制定的设计规则和结构,输入与输出均为字符串,各个 Loader 完全独立,即插即用;

可以自己编写一个 Demo 帮助理解

实现一个 loader 虽然了解了 loader 的概念,但动手实现一个哪怕再简单不过的 loader 也比单纯的纸面了解更加深印象目标 & 初始化目标:我们打算实现一个 txt 文件的 loader,准确说是两个:reverse-loader:将 txt 文件的字符逆序toUpperClass-loader:将逆序… 前端面试指北 👆

Plugin 原理

相对于Loader而言,Plugin的编写就灵活了许多。 webpack在运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果

常见 loader

  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件
  • url-loader:和 file-loader 类似,但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
  • babel-loader:把 ES6 转换成 ES5,以提高不同浏览器的兼容性
  • css-loader:负责解析 CSS 文件,解析后会以字符串的形式打包到 JS 文件中。但此时样式并不会生效,需要把 CSS 插入到 html 里才会生效
  • style-loader:把 CSS 代码注入到 JS 中,通过 DOM 操作去加载 CSS

常见 plugin

  • HtmlWebpackPlugin:通常每次打包后的内容哈希改变,文件名也会变化,每次手动更新 index.html 中引入的 bundler 名称非常麻烦。该插件可以根据每次打包后的生成的 bundle 自动生成 html 文件
  • DllPlugin:可以为更改不频繁的代码生成单独的编译结果,提高编译速度。其原理是把网页依赖的基础模块抽离出来打包到 dll 文件中,当需要导入的模块命中 dll 时,这个模块不再被打包,而是去dll中获取
  • SplitChunksPlugin:可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk,在webpack4 后的版本中已经内置该插件
  • UglifyjsWebpackPlugin:压缩源文件中的 js 代码,优化构建过程

dev-server 热更新原理

webpack HMR 原理 参考链接:webpack热更新原理 - 填坑侠的文章 - 知乎Webpack HMR 原理解析 - 冉四夕的文章 - 知乎webpack HMR 提供了一种无需完全刷新整个页面就能重新加载已更新模块的开发体验。通过 HMR,可以保留当前页面已有状态,且只更新变更内容,节省开发时间下面介绍 HM… 前端面试指北 👆


webpack 优化

webpack-vue_3:优化 这篇完全基于上一篇的构建结果,大家随意 DIY,了解常用的 webpack 优化手段参考链接:三十分钟掌握Webpack性能优化优化构建速度首先大致总结 webpack 的打包过程webpack 打包过程会从 entry point 出发,递归地解析 modules 间的依赖,同时构建构建依赖… 前端面试指北 👆


模块加载

参考链接:简单易懂的 webpack 打包后 JS 的运行过程

webpack打包出来的是js插在模板可以允许和渲染是怎么实现的

当之后以下两个模块时

// test.js
const str = 'test is loaded';
module.exports = str;

// index.js
const test = require('./src/js/test');
console.log(test);

编译打包后的模块结构