核心概念
webpack处理应用程序时,会在内部从一个或多个入口点构建一个依赖图,然后将项目中所需的每一个模块组合成一个或多个bundles,它们均为静态资源,用于展示内容。
webpack遵循CommonJS规范,通过require()引入其他文件
入口entry
指示webpack应该使用哪个模块来作为构建其内部依赖图的开始。进入入口起点后,webpack会找出哪些模块和库是入口起点(直接和间接)依赖的
默认值是./src/index.js
,可以通过在配置文件中配置entry属性,来指定一个或多个不同的入口起点。
输出output
告诉webpack在哪里输出它创建的bundle,以及如何命名这些文件。主要输出文件的默认值是./dist/main.js
,其他生成文件默认放置在./dist
文件夹中。可以配置output字段。
loader
webpack只能理解JavaScript和JSON文件,loader让webpack能去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。
webpack的配置中,loader有两个属性:
1、test属性,识别哪些文件会被转换
2、use属性,定义出在进行转换时,应该使用哪个loader
const path=require('path');
module.exports={
ouput:{
filename:'my-first-webpack.bundle.js',
},
module:{
rules:[{test:/\.txt$/, use: 'raw-loader'}],
}
}
插件plugin
loader用于转换某些类型的模块,而插件则可以用于执行范围更广的任务,包括:打包优化、资源管理、注入环境变量。
想要使用一个插件,只需要require()它,然后把它添加到plugins数组中。多数插件可以通过选项自定义,也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用new操作符来创建一个插件实例
const HtmlWebpackPlugin=require('html-webpack-plugin');
const webpack=require('webpack');//用于访问内置插件
module.exports={
module:{
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
plugins:[new HtmlWebpackPlugin({template:'./src/index.html'})],
}
html-webpack-plugin 为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中
模式mode
通过选择development,production或none之中的一个,来设置mode参数,可以启用webpack内置在相应环境下的优化,其默认值为production
module.exports={
mode:'production',
}
浏览器兼容性browser compatibility
Webpack支持所有符合ES5标准的浏览器(不支持IE8及以下版本)。
webpack的import()和require.ensure()需要Promise。如果要支持旧版本,需要提前加载polyfill
环境environment
Webpack 5 运行于 Node.js v10.13.0+ 的版本。
其他概念
模块Modules
在模块化编程中,开发者将程序分解为功能离散的chunk,并称之为模块。
每个模块都拥有小于完整程序的体积,使得验证、调试及测试变得轻而易举。精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具备了条理清晰的设计和明确的目的。
Node.js从一开始就支持模块化编程,然而,web的模块化正在缓慢支持中。
与Node.js模块相比,webpack模块能以各种方式表达它们的依赖关系,示例:
ES2015 import语句
CommonJS require()语句
AMD define和require语句
css/sass/less文件中的
@import
语句stylesheet
url(...)
或者HTML<img src=...>
文件中的图片链接
webpack天生支持如下模块类型:
ECMAScript模块
CommonJS模块
AMD模块
Assets
WebAssembly模块
通过loader可以使webpack支持多种语言和预处理器语法编写的模块。loader向webpack描述了如何处理非原生模块,并将相关依赖引入到bundles中,webpack社区已经为各种流行的语言和预处理器创建了loader,其中包括:
CoffeeScript
TypeScript
ESNext(Babel)
Sass
Less
Stylus
Elm
模块解析Module Resolution
resolver是一个帮助寻找模块绝对路径的库,一个模块可以作为另一个模块的依赖模块,然后被后者引用
resolver帮助webpack从每个require/import语句中,找到需要引入bundle中的模块代码。
打包模块时,webpack使用enhanced-resolve来解析文件路径,能解析绝对路径,相对路径,模块路径
- 模块路径
import 'module';
import 'module/lib/file';
在resolve.modules中指定的所有目录中的检索模块。
解析loader:loader的解析规则也遵循特定的规范,但是resolveLoader配置项可以为loader设置独立的解析规则
缓存:每次文件系统访问文件都会被缓存,以便于更快触发对同一文件的多个并行或串行请求。在watch模式下,只有修改过的文件会被从缓存中移出。如果关闭watch模式,则会在每次编译前清理缓存。
Module Federation
多个独立的构建可以组成一个应用程序,这些独立的构建之间不应该存在依赖关系,因此可以单独开发和部署。
这通常被称作微前端。
本地模块:即为普通模块,是当前构建的一部分。
远程模块:不属于当前构建,并在运行时从所谓的容器加载
加载远程模块被视为异步操作,当使用远程模块时,这些异步操作将被放置在远程模块和入口之间的下一个chunk的加载操作中,如果没有chunk加载操作,就不能使用远程模块。
chunk的加载操作通常是通过import()实现的,也支持require.ensure或require([])之类的旧语法。
容器是由容器入口创建的,该入口暴露了对特定模块的异步访问。暴露的访问分为两个步骤:
1、加载模块(异步的),在chunk加载期间完成
2、执行模块(同步的),在与其他(本地和远程)的模块交错执行期间完成
依赖图
当webpack处理应用程序时,会根据命令行参数中或配置文件中定义的模块列表开始处理。从入口开始,webpack会递归的构建一个依赖关系图,这个依赖图包含着应用程序中所需的每个模块,然后将所有模块打包为少量的bundle——通常只有一个,可由浏览器加载。
target
manifest
webpack构建应用程序或站点,有三类主要的代码类型:
1、团队自己编写的;
2、第三方library或“vendor”代码;
3、webpack的runtime和manifest,管理所有模块的交互。
runtime
runtime,以及伴随的manifest,主要是指:在浏览器运行过程中,webpack用来连接模块化应用程序所需的所有代码。
包含:模块交互时,连接模块所需的加载和解析逻辑。包括:已经加载到浏览器中的连接模块逻辑,以及尚未加载模块的延迟加载逻辑
manifest
一旦应用在浏览器中以index.html文件的形式被打开,一些bundle和应用所需要的各种资源都需要用某种方式被加载与链接起来。在经过打包、压缩、为延迟加载而拆分为细小的 chunk 这些 webpack 优化 之后,你精心安排的 /src 目录的文件结构都已经不再存在。所以 webpack 如何管理所有所需模块之间的交互呢?这就是 manifest 数据用途的由来……
当 compiler 开始执行、解析和映射应用程序时,它会保留所有模块的详细要点。这个数据集合称为 "manifest",当完成打包并发送到浏览器时,runtime 会通过 manifest 来解析和加载模块。无论你选择哪种 模块语法,那些 import 或 require 语句现在都已经转换为 __webpack_require__
方法,此方法指向模块标识符(module identifier)。通过使用 manifest 中的数据,runtime 将能够检索这些标识符,找出每个标识符背后对应的模块。
模块热替换HMR
模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:
保留在完全重新加载页面期间丢失的应用程序状态。
只更新变更内容,以节省宝贵的开发时间。
在源代码中 CSS/JS 产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。
通过以下步骤,可以做到在应用程序中置换(swap in and out)模块:
应用程序要求 HMR runtime 检查更新。
HMR runtime 异步地下载更新,然后通知应用程序。
应用程序要求 HMR runtime 应用更新。
HMR runtime 同步地应用更新。