Introduction
本质上就是个命令行工具
- 沿袭自 npm 的脚本和生态系统
Problems with Script Loading
管理 js
- 最初用 IIFE
- 后来的 gulp 等目的只是将文件连接在一起
- 传统的模块化方式迫使 JavaScript 引擎急于解析代码,从而引起性能浪费。懒加载和摇树才是我们想要的。
History of Modules
模块化
- CommonJS 和 npm,但没有浏览器支持
- 需要解决自我引用和循环引用的问题
- require 实际上是一个可以传递到任何地方的函数,所以 webpack 重新定义了 require
- 下一个问题是如何异步加载,用 AMD 解决吗?NO,那像是依赖注入,太动态化了。
EcmaScript Modules (ESM)
对模块化问题的解决方案
- Node 的 ESM 有点悬而未决
- 浏览器的 ESM 非常慢
Introducing Webpack
所有的资产都有模块
- Webpack 是一个模块捆绑器
- Webpack 支持代码分割或静态异步捆绑
- 之后诞生了热更新功能,甚至是 redux
Configuring Webpack
有三种方法可以使用 Webpack
- cli
- 配置
- node,像 Neutrino 和 joy
Using Webpack for the First Time
- webpack 只做 barebones,帮助用户定制工作流
- 使用 npm 脚本封装如 webpack 这样的二进制命令
Adding npm Scripts for Environment Builds
- webpack 4+ 零配置
- 为工作流定制环境:开发、线上、构建、调试
Setting Up Debugging
- node --inspect --debug-brk
"debug":"node --inspect --inspect-brk ./node_modules/webpack/bin/webpack.js",
"dev:debug":"npm run debug -- --env.mode development"
Coding Your First Module
Adding Watch Mode
ES Module Syntax
- Webpack中 会解析出一个依赖图
CommonJS Export
- Webpack 支持使用 require,但强烈支持不要尽可能多地使用 CommonJS
- 像 Bable 和 Typescript 这样的工具可以安全地默认在后台将ESM转换为 CommonJS,然后将其传递给 Webpack。
CommonJS Named Exports
- 建议将导出保留在文件的底部
- 使用命名参数而不仅仅是模块或模块点导出
Tree Shaking
- 增量编译
Webpack Bundle Walkthrough 重要
- 编译后的每个模块都是 IIFE
- 会预置一段运行时代码,首先是 installedModules,它是一个模块缓存
- 还有一个名为 webpack_require 的函数,这就是 require 函数,它需要一个模块 ID 参数,返回 .exports
- 找到模块后会调用 .call 方法
- 这个过程叫做动态绑定,为了避免循环依赖,会对对象进行冻结
- 第一个模块在最后一行被调用,不是 IIFE
Webpack Entry
- 依赖的切入点
- 与 output 属性搭配使用
Output & Loaders
- output 告诉 Webpack 在哪里以及如何分发这些文件
- loader 需要规则集,从而匹配和转换文件
- loader 可以组合使用
Chaining Loaders
- 总是从右到左执行,类似一个组合函数
Webpack Plugins
- 它只是一个实例。它是一个 JavaScript 对象,在原型链中有一个 apply 属性。它允许您挂钩整个事件的 Webpack 生命周期。
- 通过监听事件来根据数据的内容进行一些操作。
- 记得使用的时候 new 一下
- 80% 的 Webpack 源代码都是由这些插件组成的。Webpack 本身是一个完全由事件驱动的架构。
Webpack Config
- webpack 可以接受一个对象,作为配置模块的默认导出,但它也可以使用一个返回对象的函数。
Passing Variable to Webpack Config
- 三套配置
npm run webpack -- --env.mode production
Adding Webpack Plugins
- 以 html-webpack-plugin 做例子
Setting Up a Local Development Server
- 以 webpack-dev-server 为例,是基于 Express 的 Web 服务器。只不过写到内存里。
Starting to Code with Webpack
随便写了点代码
Splitting Environment Config Files
- webpack-merge 合并
- 在创建 JavaScript 模块时可以对其进行哈希处理,比如说 chunckhash
Webpack Q&A
- webpack-dev-server 可以进行服务端开发吗?
实际上是 webpack-dev-middleware,当然可以
- 有没有办法利用多个模板的 HTML webpack 插件?
实际上是多页应用程序架构:multipage-webpack-plugin?为每个条目创建一个新的 html-webpack-plugin 插件实例。
- 是否存在 webpack 进程遇到内存不足错误以及捕获该异常的情况?
webpack 性能的空间复杂度和模块是线性的,所以需要很多内存。webpack 5 会有一些缓存。如果出现内存泄漏就加哈希。
Using CSS with Webpack
- 传统的方法是在磁盘文件夹中提供它并在 style 标记中引用。
- 需要一个合适的加载器来处理这个文件:css-loader
Hot Module Replacement with CSS
- Webpack 具有以下功能:能够对以增量方式进行的更改进行修补,并在不必重新加载浏览器的情况下应用它们。
- mini-css-extra 插件可以将 css 提取到一个文件里
- 代码拆分 CSS 时,将它们分成异步应用程序变得很有价值。所以 CSS 模块出现了。
File Loader & URL Loader
- 将媒体资源转换成 base64
Loading Images with JavaScript
Limit Filesize Option in URL Loader
- 各种图像
Implementing Presets
- 添加一个预设系统,不仅仅是开发和生产环境
- 有时,肖恩称他们为附加组件。你可以随意调用它。通过传 env 来取出预设选项
- 将若干个预设选选项对应的配置合并:applyPresets
const webpackMerge = require("webpack-merge");
const loadPresets = (env = { presets: [] }) => {
const presets = env.presets || [];
const mergedPresets = [].concat(...[presets]);
const mergedConfigs = mergedPresets.map(presetName => {
return require(`./presets/webpack.${presetName}`)(env);
});
return webpackMerge({}, ...mergedConfigs);
};
module.exports = loadPresets;
Bundle Analyzer Preset
- 当 webpack 构建时,它会发出这个 stats 对象。stats 对象要么转换为字符串,要么转换为 JSON
- WebpackBundleAnalyzer 插件可视化分析
Compression Plugin
- 压缩所有资产成 gzip
Source Maps
- 可以通过多种不同的方式生成源映射
- devtool 是负责创建源映射的属性。
- sourcemap 有不同的质量:快慢轻重
- 可以做调试驱动的开发
- 常见的有 source-map、cheap-module-source-map、eval 等
Q&A and Closing Remarks
- 如何避免打包文件过大?
代码拆分、关闭缓存、懒加载等。
- 摇树在 output 独立的函数而不是 class 时都会受益吗?
只需使用 ESM 即可获得依赖注入。所以与导出整个类相比,最好是导出单个函数和值以及基元。
- 如何找到好插件和坏插件?
Webpack-Contrib,以及看 github 的 pr 和 issue 处理程度
网友评论