Webpack

本文最后更新于:8 个月前

现代网页越来越复杂,资源必须通过增量加载的方式来优化网页加载速度,在这个过程中,模块打包器发挥了关键作用,而webpack是目前主流的模块的打包器之一。本文记录了《webpack中文文档》阅读笔记,以及参照”指南“部分,实践的记录。

Webpack

《中文指南》阅读笔记

一本webpack中文文档,适合了解一些基本概念(不适合作为严格的参考指南)

链接:前言 | Webpack 中文指南 (zhaoda.net)

现代前端开发已经从单一网页向更庞大的webapp发展,同时前端产品交付基于浏览器,资源是通过增量加载的方式运行到浏览器的,但是大量资源的加载将增加浏览器加载的时间,降低用户体验。如何让用户能够快速地。优雅地加载和更新,模块化系统在这样的问题背景下应运而生。

模块化有很多标准:CommonJS(同步)、AMD(异步模块定义)、CMD(异步)、ES6Module(同步)

而Webpack是一个兼容上面许多规规范的模块打包器
各种Loader的作用,webpack只能处理原生javasrcipt模块,而Loader可以把各种类型文件转换为JS,这样就可以加载任何类型的模块或文件

《webpack指南》实践记录

链接:参照《webpack指南》,实践代码,可作为webpack入门实践 (github.com)

《webpack概念》笔记

链接:概念 | webpack 中文网 (webpackjs.com)

webpack做了什么

本质上,webpack 是一个现代 JavaScript 应用程序的**静态模块打包器(module bundler)*。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph)*,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle

一、入口

用法:entry: string|Array<string>

单个入口,两种写法

1
2
3
4
5
6
7
8
9
10
11
12
//对象语法
module.exports = {
entry: {
app: './src/index.js'
},
}

//上面的简写形式
module.exports = {
entry: './src/index.js'

}

如果传入的是string数组,将创建多个主入口。在你想要多个依赖文件一起注入,并且将它们的依赖导向(graph)到一个“chunk”时,传入数组的方式就很有用

对象语法,常用,用法:entry: {[entryChunkName: string]: string|Array<string>}

1
2
3
4
5
6
7
module.exports = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
}
//webpack 将从 `app.js` 和 `vendors.js` 开始创建依赖图(dependency graph)。这些依赖图是彼此完全分离、互相独立的(每个 bundle 中都有一个 webpack 引导(bootstrap))

常见场景

SPA,单页面应用常见的做法是:将应用程序和第三方库(vendor)分入口打包构建

MPA,多页面应用常见的做法是将每个页面作为一个入口,然后可以使用CommonsChunkPlugin 为每个页面间的应用程序共享代码创建 bundle,这样,多页应用能够复用入口起点之间的大量代码/模块

二、输出

配置 output 选项可以控制 webpack 如何向硬盘写入编译文件。注意,即使可以存在多个入口起点,但只指定一个输出配置

在 webpack 中配置 output 属性的最低要求是,将它的值设置为一个对象,包括以下两点:

  • filename 用于输出文件的文件名。
  • 目标输出目录 path 的绝对路径
1
2
3
4
5
6
7
8
9
10
const path = require('path')
module.exports = {
entry: {
app: './src/index.js'
},
output: {
filename: '[name].[chunkhash].js',//[name]是占位符,表示入口起点的名称,在这里是app,也有可能CommonsChunkPlugin 这样的插件生成的文件的名称。[chunkhash]指使用chunk的内容哈希值作为名称一部分
path: path.resolve(__dirname, 'dist')
}
}

三、模式

提供 mode 配置选项,告知 webpack 使用相应模式的内置优化

选项 描述
development 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPluginNamedModulesPlugin
production 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin

四、loader

loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件。借助于loader,webpack可以处理各种类型的文件(webpack本身只能处理JavaScript模块)

loader的3种使用方式

  • 配置,在webpack.config.js文件中配置,推荐使用
  • 内联,在每个import语句中指定
  • CLI,在shell命令中指定

配置

1
2
3
4
5
6
7
8
9
10
11
12
//webpack.config.js
module.exports = {
,,,
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}

内联

1
import Styles from 'style-loader!css-loader?modules!./styles.css'

CLI

1
2
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
//这会对 .jade 文件使用 jade-loader,对 .css 文件使用 style-loader 和 css-loader

loader特性

  • 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript
  • loader 接收查询参数。用于对 loader 传递配置
  • loader 也能够使用 options 对象进行配置
  • loader 运行在 Node.js 中,并且能够执行任何可能的操作
  • loader 可以是同步的,也可以是异步的
  • loader 能够产生额外的任意文件

五、插件

插件目的在于解决 loader 无法实现的其他事,范围包括,从打包优化和压缩,一直到重新定义环境中的变量

由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例

下例展示插件在webpack.config.js文件中的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')

module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
title: '渐进式网络应用程序'
}),
new CleanWebpackPlugin(),
new webpack.ProvidePlugin({
// _: 'lodash'
join:['lodash','join']
})
]
}

六、配置

webpack 的配置文件,是导出一个对象的 JavaScript 文件。是标准的 Node.js CommonJS 模块,你可以做到以下事情

  • 通过 require(...) 导入其他文件
  • 通过 require(...) 使用 npm 的工具函数
  • 使用 JavaScript 控制流表达式,例如 ?: 操作符
  • 对常用值使用常量或变量
  • 编写并执行函数来生成部分配置
1
2
3
4
5
6
7
8
9
10
var path = require('path');

module.exports = {
mode: 'development',
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js'
}
};

七、依赖图

任何时候,一个文件依赖于另一个文件,webpack 就把此视为文件之间有 依赖关系。

webpack从指定的入口开始,递归地构建一个依赖图,这个依赖图包含应用程序所需的每个模块,然后将这些模块打包成少量的bundle

八、manifest

manifest是什么?

runtime,以及伴随的 manifest 数据,主要是指:在浏览器运行时,webpack 用来连接模块化的应用程序的所有代码

runtime

包含:在模块交互时,连接模块所需的加载和解析逻辑。包括浏览器中的已加载模块的连接,以及懒加载模块的执行逻辑

manifest

当编译器(compiler)开始执行、解析和映射应用程序时,它会保留所有模块的详细要点。这个数据集合称为 “Manifest”,当完成打包并发送到浏览器时,会在运行时通过 Manifest 来解析和加载模块。所有 importrequire 语句现在都已经转换为 __webpack_require__ 方法,此方法指向模块标识符(module identifier)。通过使用 manifest 中的数据,runtime 将能够查询模块标识符,检索出背后对应的模块。


Webpack
http://timegogo.top/2022/08/17/前端工程化/前端工具:Webpack/
作者
丘智聪
发布于
2022年8月17日
更新于
2023年7月16日
许可协议