# webpack
webpack1|webpack2|babel|webapckserver
webpack是一个打包模块化js工具,在webpack里一切文件皆模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合成的文件,webpack专注构建模块化项目。
1. “一切文件皆模块”
核心思想:Webpack 将项目中的所有资源(如 JavaScript、CSS、图片、字体等)都视为模块,而不再区分文件类型。这种设计打破了传统构建工具对文件类型的限制,使得模块化开发更加统一和灵活。
类比: 传统开发中,JavaScript 文件用 <script> 标签引入,CSS 文件用 <link> 标签引入,图片用 <img> 标签引入,不同文件类型需要不同的处理方式。Webpack 统一将这些资源视为模块,通过模块化方式引入,开发者只需关心模块的依赖关系,而无需关心文件类型。
示例:
```js
// 假设有一个 CSS 文件和一个图片文件
import './style.css';
import logo from './logo.png';
console.log('Hello Webpack!');
Webpack 会将 style.css 和 logo.png 也作为模块处理,最终打包到输出文件中。
- “通过 loader 转换文件” 核心思想:由于不同文件类型(如 CSS、图片、TypeScript 等)需要不同的处理方式,Webpack 使用 Loader 来对文件进行转换。Loader 本质上是一个函数,可以将一种文件类型转换为另一种类型(通常是 JavaScript 模块)。
类比:Loader 就像一个“翻译器”,将不同语言的文件“翻译”成 Webpack 能理解的 JavaScript 模块。例如,CSS 文件需要通过 css-loader 和 style-loader 转换为可嵌入到 JavaScript 中的样式。
module.exports = {
module: {
rules: [
{
test: /\.css$/, // 匹配所有 CSS 文件
use: ['style-loader', 'css-loader'], // 使用 loader 转换
},
{
test: /\.(png|jpg|gif)$/, // 匹配图片文件
type: 'asset/resource', // 内置的 Asset Modules 处理图片
},
],
},
};
- “通过 plugin 注入钩子”
核心思想:Webpack 的构建流程是一个高度可扩展的流水线,Plugin 可以在构建流程的不同阶段(如编译、打包、优化等)注入自定义逻辑。Plugin 通过监听 Webpack 提供的钩子(Hooks)来实现功能扩展。
类比:Plugin 就像一个“插件系统”,允许开发者在构建流程中插入自定义功能。例如,HtmlWebpackPlugin 可以自动生成 HTML 文件并注入打包后的资源。
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html', // 指定模板文件
}),
],
};
- “最后输出由多个模块组合成的文件”
核心思想:Webpack 的最终目标是生成一个或多个优化后的静态文件(通常是 JavaScript 或 CSS),这些文件包含了项目中的所有模块和资源。通过模块依赖图(Dependency Graph),Webpack 会分析模块之间的依赖关系,并将它们组合成一个或多个文件。
类比:就像把一本书的章节(模块)按照依赖关系整理成一本书(输出文件)。输出文件可以是一个或多个,具体取决于配置(如代码分割、多入口等)。
示例:假设项目中有三个模块:a.js、b.js 和 c.js,其中 a.js 依赖 b.js 和 c.js。 Webpack 会生成一个包含所有模块的打包文件(如 bundle.js),并自动处理模块之间的依赖关系。
- “Webpack 专注构建模块化项目”
核心思想:Webpack 的设计初衷是解决现代前端开发中模块化、资源管理和性能优化的问题。它通过模块化、Loader 和 Plugin 的机制,提供了一种灵活、可扩展的构建方案。
特点:
- 模块化:支持各种文件类型的模块化开发。
- 扩展性:通过 Loader 和 Plugin,可以轻松扩展功能。
- 优化:支持代码分割、Tree Shaking、懒加载等优化技术。
对比其他工具:
- 与传统的构建工具(如 Grunt、Gulp)相比,Webpack 更专注于模块化开发。
- 与其他模块打包工具(如 Rollup、Parcel)相比,Webpack 的生态更加丰富,功能更加全面。
它做的事情是,分析项目结构,找到js模块以及一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。(资源被引入后,Webpack才会对其打包)
将文件拆成一个个小部分,用script标签来加载,可以实现面向对象,但是需要加载多个script,耗性能耗时间!所以需要模块化引入。
### webpack安装和使用
```bash
npm i -g/-D webpack webpack-cli
// 启动webpack方式
1. npx webpack
2. node_modules/.bin/webpack
3. npm run xxx
webpack-cli:webpack-cli 是用来
处理命令行参数,并通过参数构建 compiler 对象,然后才是对代码进行打包的过程。所以webpack-cli对于文件打包不是必需的。既然 webpack-cli只是为了处理命令行参数,那同样可以构建自己的cli来处理参数,比如 abc-cli。React 和 Vue也没有使用 webpack-cli.
- 在cmd控制台中,
如果直接使用webpack命令,其实不管项目中有没有安装局部的webpack,都不会被调用,会直接使用全局的webpack;如果要使用项目的webpack,需要加前缀npx webpack。 - 命令行模式: npx webpack --entry ./src/main.js --output-path ./build
- 在package.json中的script脚本控制中,就不需要添加npx也会走项目的webpack
- 命令行中敲命令参数过于麻烦,可以创建webpack.config.js默认文件,如需改名,额外配置
webpack --config xx.yy.js - webpack只认识
js/json,其余文件都需要借助Loader/Plugins进行额外的处理
# webpack 信息查看
查看webpack所有版本信息
npm info webpack
如果不是全局安装,查看版本
npx webpack -v
# webpack五个核心概念
- Entry
- Output
- Loader:可以用于对模块的源代码进行转换;
- Plugins
- Mode
最基本的运行指令
webpack ./src/index.js -o ./build/built.js --mode=development
webpack会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/built.js
# webpack自身的部分配置
- Configuration 在这里通常指的是 webpack 的配置对象类型定义,它定义了 webpack 配置文件中可以设置的所有选项的结构和类型。
import { Configuration } from 'webpack'
const prodConfig: Configuration = merge(baseConfig, {
mode: 'production',
。。。。。。
}
# 几个常见的webpack-loader
- file-loader:把文件识别后打包(w4)
- url-loader:和 file-loader 类似,但能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去(w4)
- image-loader:加载并且压缩图片文件
- babel-loader:把 ES6 转换成 ES5
- css-loader:加载 CSS,支持模块化、压缩、文件导入等特性,负责将 Css 文件编译成 Webpack 能识别的模块
- postcss-loader:Css 兼容性处理,依赖postcss
- style-loader:把 CSS 代码注入到 打包的JavaScript 中,通过 DOM 操作去加载 CSS;会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容
- vue-style-loader:大体与style-loader一致,不过支持服务端渲染?
- eslint-loader:通过 ESLint 检查 JavaScript 代码(w4,webpack5中使用eslint-webpack-plugin)
- less-loader:负责将 Less 文件编译成 Css 文件
- sass-loader:负责将 Sass 文件编译成 css 文件(sass-loader 依赖 sass 进行编译)
- stylus-loader:styl文件转css
- asset:Webpack5 已经将url-loader/file-loader 功能内置到 Webpack 里了,称为asset module type(资源模块类型)
# 几个常见的webpack-plugin
- define-plugin:内置定义环境变量
- html-webpack-plugin: 为html文件中引入的外部资源,可以生成创建html入口文件
- mini-css-extract-plugin:分离css文件
- optimize-css-assets-webpack-plugin:处理css文件,W5中更推荐css-minimizer-webpack-plugin
- css-minimizer-webpack-plugin: css压缩
- clean-webpack-plugin:删除打包文件(w4)【ouput中配置选项clean:true:webpack5中可以不需要再手动安装clean-webpack-plugin,配置clean后,会在打包时自动删除output下的path对应的文件夹内容】
- eslint-webpack-plugin:校验eslint代码格式
- webpack.HotModuleReplacementPlugin (webpack内置热更新组件,新版webpack-dev-server根据devserver中hot值为true会自动调用)
- terser-webpack-plugin: w5内置,w4需要安装,处理多进程打包,可以配置在plugins中,也可以在optimization中配置(
如果配置了css压缩,这个就算不需要配置多进程打包也最好要配置) - image-minimizer-webpack-plugin: 图片优化压缩处理
- happypack:实现多线程加速编译,已不推荐
- workbox-webpack-plugin:pwa优化
- add-asset-html-webpack-plugin:Add a JavaScript or CSS asset to the HTML generated by html-webpack-plugin,相当于 html-webpack-tags-plugin再加上一个copy-webpack-plugin
- html-webpack-tags-plugin:定义要使用html-webpack-plugin注入的html标签
- copy-webpack-plugin:一个在 Webpack 构建过程中用于复制文件和目录到输出目录的插件
# webpack的一些工具库
- webpack-merge : 是一个用于合并 Webpack 配置对象的工具库。在大型项目中,Webpack 配置可能会变得非常复杂,通常需要将基础配置与特定环境的配置(如开发环境、生产环境)分开管理。webpack-merge 可以帮助我们将这些配置合并成一个完整的配置对象。
import { merge } from 'webpack-merge'
const prodConfig: Configuration = merge(baseConfig, {
mode: 'production',
plugins: [...]
}
# Hash(fullhash)、ContentHash、ChunkHash
在给打包的文件进行命名的时候,会使用placeholder,placeholder中有几个属性比较相似:
- hash本身是通过MD4的散列函数处理后,生成一个128位的hash值(32个十六进制);w5中叫fullhash
- hash值的生成和整个项目有关系:
- 比如现在有两个入口index.js和main.js;
- 它们分别会输出到不同的bundle文件中,并且在文件名称中有使用hash;
- 这个时候,如果修改了index.js文件中的内容,那么hash会发生变化;
- 那就意味着两个文件的名称都会发生变化;
每次修改任何一个文件,所有文件名的 hash 至都将改变。所以一旦修改了任何一个文件,整个项目的文件缓存都将失效。
- chunkhash可以有效的解决上面的问题,它会根据不同的入口进行解析来生成hash值:
- 比如修改了index.js,那么main.js的chunkhash是不会发生改变的;
根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。js 和 css 是同一个引入,会共享一个 hash 值。
- contenthash表示生成的文件hash名称,只和内容有关系:
- 比如index.js,引入了一个style.css,style.css有被抽取到一个独立的css文件中;
- 这个css文件在命名时,如果使用的是chunkhash;
- 那么当index.js文件的内容发生变化时,css文件的名也会发生变化;
- 这个时候我们可以使用contenthash;
根据文件内容生成 hash 值,只有文件内容变化了,hash 值才会变化。所有文件 hash 值是独享且不同的。
# webpack与grunt、gulp的不同?
Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案。
它们的工作方式也有较大区别:
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等具体步骤,工具之后可以自动完成这些任务。
Webpack的工作方式是:把项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的js文件。
grunt和gulp是基于任务和流(Task、Stream)的。类似jQuery,找到一个(或一类)文件,对其做一系列链式操作,更新流上的数据, 整条链式操作构成了一个任务,多个任务就构成了整个web的构建流程。
webpack是基于
入口的。webpack会自动地递归解析入口所需要加载的所有资源文件,然后用不同的Loader来处理不同的文件,用Plugin来扩展webpack功能。
所以总结一下:
- 从构建思路来说:
- gulp和grunt需要开发者将整个前端构建过程拆分成多个Task,并合理控制所有Task的调用关系
- webpack需要开发者找到入口,并需要清楚对于不同的资源应该使用什么Loader做何种解析和加工
- 对于知识背景来说
- gulp更像后端开发者的思路,需要对于整个流程了如指掌 webpack更倾向于前端开发者的思路
# webpack有哪些优点
- 专注于处理模块化的项目,能做到开箱即用,一步到位
- 可通过plugin扩展,完整好用又不失灵活
- 使用场景不局限于web开发
# webpack的缺点
webpack的缺点是只能用于采用模块化开发的项目
# 分别介绍bundle,chunk,module是什么
- bundle:是由webpack打包出来的文件。
- chunk:代码块,一个chunk由多个模块组合而成,用于代码的合并和分割。
- module:是开发中的单个模块,在webpack的世界,一切皆模块,一个模块对应一个文件,webpack会从配置的entry中递归开始找出所有依赖的模块。
大多数情况下,一个Chunk会生产一个Bundle。但有时候也不完全是一对一的关系,比如把 devtool配置成’source-map’。然后只有一个入口文件,也不配置代码分割:
// webpack配置
entry: {
main: __dirname + "/app/main.js",
},
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "[name].js", //打包后输出文件的文件名
},
devtool: 'source-map',
这样的配置,会产生一个Chunk,但是会产生两个bundle,如下图
module,chunk 和 bundle 其实就是同一份逻辑代码在不同转换场景下的取了三个名字:直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。
在webpack的打包配置entry中有两个入口:index和utils。分别对应index.js和utils.js。其中indexjs文件引用了common.js和index.css。那么打包的时候三个文件看成一个chunk,utilsjs文件作为一个chunk。
但是webpack配置用MiniCssExtractPlugin插件抽离出css文件,所以产生了.css和.js两个bundle文件。
# 分别介绍什么是loader?什么是plugin?
- loader:模块转换器,用于特定的模块类型进行转换,原内容按照需要转成想要的内容
- plugin:可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入等,在webpack构建流程中的特定时机注入扩展逻辑,来改变构建结果,是用来自定义webpack打包过程的方式,一个插件是含有apply方法的一个对象,通过这个方法可以参与到整个webpack打包的各个流程(生命周期)。
# 什么是Tree-shaking
Tree-shaking可以用来剔除javascript中不用的死代码,它依赖静态的es6模块化语法,css中使用Tree-shaking需要引入Purify-CSS
# 通过webpack处理长缓存
为了加快加载速度,会对用户访问的静态资源进行存储,但是每一次代码升级或是更新,都需要浏览器去下载新的代码,最方便和简单的更新方式就是引入新的文件名称。在webpack中可以在output纵输出的文件指定chunkhash,并且分离经常更新的代码和框架代码。通过NameModulesPlugin或是HashedModuleIdsPlugin使再次打包文件名不变。
# 如何提高webpack的构建速度
通过externals配置来提取常用库
利用DllPlugin和DllReferencePlugin预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin将预编译的模块加载进来。
使用Happypack 实现多线程加速编译要注意的第一点是,它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了,其他loader可以类似地换一下(过时不推荐)使用Tree-shaking和Scope Hoisting来剔除多余代码
使用fast-sass-loader代替sass-loader
babel-loader开启缓存
babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率
可以加上cacheDirectory参数或使用 transform-runtime 插件试试
不需要打包编译的插件库换成全局"script"标签引入的方式 比如jQuery插件,react, react-dom等,代码量是很多的,打包起来可能会很耗时 可以直接用标签引入,然后在webpack配置里使用 expose-loader 或 externals 或 ProvidePlugin 提供给模块内部使用相应的变量
// @1
use: [{
loader: 'expose-loader',
options: '$'
}, {
loader: 'expose-loader',
options: 'jQuery'
}]
// @2
externals: {
jquery: 'jQuery'
},
// @3
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
}),
# 优化构建时的搜索路径
在webpack打包时,会有各种各样的路径要去查询搜索,我们可以加上一些配置,让它搜索地更快 比如说,方便改成绝对路径的模块路径就改一下,以纯模块名来引入的可以加上一些目录路径 还可以善于用下resolve alias别名 这个字段来配置 还有exclude等的配置,避免多余查找的文件,比如使用babel别忘了剔除不需要遍历的
# 寻找到引入文件的位置
在 webpack 支持的前端代码模块化中,我们可以使用类似 import * as m from './index.js' 来引用代码模块 index.js。
引用第三方类库则是像这样:import React from 'react'。webpack 构建的时候,会解析依赖后,然后再去加载依赖的模块文件,那么 webpack 如何将上述编写的 ./index.js 或 react 解析成对应的模块文件路径呢?
webpack 中有一个很关键的模块 enhanced-resolve就是处理依赖模块路径的解析的,这个模块可以说是 Node.js 那一套模块路径解析的增强版本,有很多可以自定义的解析配置。
webpack学习 (opens new window) webpack学习 (opens new window) 缓存 (opens new window)
loader →