说说你对前端工程化的理解?为什么要工程化
前端工程化是将软件开发工程学 的理念引入前端开发,通过规范化流程、工具链集成、自动化手段 ,解决复杂项目中的协作、维护、性能等问题,最终实现高效、稳定、可扩展 的研发体系。其核心包括: www.jianshu.com/p/7f2c0a818...
维度 | 具体表现 |
---|---|
模块化 | 代码按功能拆分(如 ES Module、组件库),降低耦合度 |
规范化 | 统一代码风格(ESLint)、提交规范(Commitizen)、目录结构 |
自动化 | 构建(Webpack)、测试(Jest)、部署(CI/CD)等流程无需手动干预 |
可维护性 | 通过类型系统(TypeScript)、文档生成(Storybook)提升长期迭代效率 |
原因
指标 | 工程化影响 |
---|---|
开发效率 | 减少重复劳动(如热更新代替手动刷新),工具链集成节省配置时间 |
代码质量 | 静态检查 + 自动化测试提前拦截 Bug,类型系统减少运行时错误 |
性能表现 | 构建优化(Chunk 拆分、按需加载)、资源压缩(CSS/JS minify)、缓存策略 |
团队协作 | 统一开发环境、规范提交日志,降低新人上手成本 |
总结
前端工程化不是单纯引入工具,而是通过标准化、自动化、数据化 的手段,将"手工作坊"升级为"现代化工厂"。其本质是用工具约束人,用流程保证质量 ,最终实现可预测、可度量、可持续的交付能力。
与webpack类似的工具还有哪些?区别?
场景 | 推荐工具 | 理由 |
---|---|---|
企业级复杂应用 | Webpack | 大而全 ,丰富的生态,loader,plugin可以满足各种使用场景的 |
偏向JS库/框架打包 | Rollup | 输出代码精简,Tree-shaking ,可选的输出格式 |
零配置简单项目 | Parcel | 资源编译流程优化,无需复杂配置 (简称0配置) 不支持tree shaking |
追求极限构建速度 | esbuild | Go 语言实现,线程间可以共享内存,性能碾压传统工具 |
快速原型/现代 SPA | Vite | 取长补短(用Rollup pro输入输出,用esbuild dev快速构建),按需打包,未来趋势 |
webpack的配置有哪些
Webpack的配置主要包括以下几个方面:
- 入口(Entry) :Webpack通过入口点开始打包过程。可以配置单个入口点或多个入口点。例如,可以指定一个或多个JavaScript文件作为入口点。
- 输出(Output) :配置打包后的文件输出位置和文件名。通常在
webpack.config.js
文件中设置output
对象,包括filename
和path
等属性。 - 加载器(Loaders) :Webpack本身只能理解JavaScript和JSON,加载器允许webpack处理其他类型的文件,如CSS、Images等。例如,使用
style-loader
和css-loader
来处理CSS文件。 - 插件(Plugins) :插件用于执行范围更广的任务,如bundle优化、资源管理和环境变量注入等。常见的插件包括
HtmlWebpackPlugin
和MiniCssExtractPlugin
等。 - 开发服务器(DevServer) :配置开发服务器以提供实时重新加载功能。可以通过
webpack-dev-server
来实现。 - 模式(Mode) :Webpack支持两种模式------开发模式(development)和生产模式(production)。不同模式下,Webpack会应用不同的优化策略。
- 拆分代码(Code Splitting) :通过入口起点、入口起点依赖和运行时依赖等方式拆分代码,以优化加载时间15。
- 性能优化:包括压缩代码、减少文件大小、缓存处理等,以提高应用性能。
- 跨域请求(CORS) :在开发服务器中配置代理解决跨域问题,通常使用
devServer.proxy
选项。 - 自定义配置 :根据项目需求自定义配置项,如环境变量、别名等。 **optimization。可以使用optimization.splitChunks和optimization.runtimeChunk配置代码拆分和运行时代码提取等优化策略。
-
externals。用于配置排除打包的模块,例如,可以将jQuery作为外置扩展,避免将其打包到应用程序中。
-
devtool。配置source-map类型。
-
context。webpack使用的根目录,string类型必须是绝对路径。
-
target。指定Webpack编译的目标环境。
-
performance。输出文件的性能检查配置。
-
noParse。不用解析和处理的模块。
-
stats。控制台输出日志控制。
webpack核心原理(也就是webpack做了什么)(webpack介绍)
Webpack是一个开源的JavaScript静态 模块打包工具(Module Bundler),其最核心的功能是解决模块之间的依赖 (模块打包),把各个模块按照特定的规则和顺序组织在一起,最终合并为一个JS文件(有时会有多个)使其打包后的结果能运行在浏览器上。这个过程就叫作模块打包。其核心目标是解决前端开发中的依赖管理 和资源优化问题。
为了什么需要webpack? 当应用的规模大了之后,就必须借助一定的工具,否则人工维护代码的成本将逐渐变得难以承受。使用工具可以让开发效率成倍地提升,所谓"工欲善其事,必先利其器"就是这个意思。
为何模块? 在设计程序结构时,把所有代码都堆到一起是非常糟糕的做法。更好的组织方式是按照特定的功能将其拆分为多个代码段,每个代码段实现一个特定的目的。你可以对其进行独立的设计、开发和测试,最终通过接口来将它们组合在一起。这就是基本的模块化思想。
markdown
1. 通过导入和导出语句我们可以清晰地看到模块间的依赖关系
2. 模块可以借助工具来进行打包,所以在页面中只需要加载合并后的资源文件,减少了网络开销。
3. 多个模块之间的作用域是隔离的,彼此不会有命名冲突。
核心原理/为什么选择webpack
- 模块化支持
- 统一处理 ES Module、CommonJS AMD等模块化规范 。
- 依赖管理
- 自动解析模块间的依赖关系,避免手动维护加载顺序。
- 代码转换
- 通过 Loader 处理非 JS 文件(如 SASS → CSS → JS 内联)。
- 扩展功能
- 通过插件(Plugin)实现环境变量注入、HTML 生成等高级功能。 生态成熟
- 打包优化
- 代码分割(Code Splitting)、按需加载(Lazy Loading)优化性能。** **
- 开发支持
- 提供热更新(HMR)、Source Map 等提升开发效率。
webpack5 的新特性
-
持久化缓存:通过将编译结果缓存到磁盘上,可以显著提高构建速度.
- 配置中设置
cache.type:'filesystem'
,可以启用持久化缓存 - webpack4 每次编译都需要重新执行构建流程,即使文件没变化也重新构建,所以导致速度慢。
- 社区提供
HardSourceWebpackPlugin
实现持久化缓存,5 代是对这功能进行官方支持与优化。
- 配置中设置
css
cache: {
type: 'filesystem', // 使用文件系统级别的缓存
}
-
长缓存优化: 通过文件名哈希和缓存控制头来缓存静态资源,减少服务器负载和加快页面加载速度。
-
Tree Shaking 优化:提高了对未使用模块的检测能力,从而在打包时排除更多未使用的代码。
-
输出文件名优化 :ContentHash,基于内容粒度变化来判断是否更新文件名
-
资产模块:是一种新的模块类型,处理字体、图标、图片等资源。
- Webpack 4 中需通过
file-loader
、url-loader
处理的文件,5 代不用额外的 Loader 就能用
- Webpack 4 中需通过
-
模块联邦:通过插件实现不同前端应用见资源共享与集成,跟微前端相关,细节没用过。
webpac的生命周期/构建流程(高频)
webpack打包的整个过程
webpack如何优化编译速度/webpack打包优化
webpack如何减少打包后的体积代码?(高频)
以下是减少 Webpack 打包体积的优化方案,按优先级排序:
一、代码压缩
-
JS 压缩
使用
TerserPlugin
压缩 JS 代码:javascriptoptimization: { minimize: true, minimizer: [new TerserPlugin()] }
-
CSS 压缩
使用
css-minimizer-webpack-plugin
压缩 CSS:javascriptconst CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); optimization: { minimizer: [new CssMinimizerPlugin()] }
二、Tree Shaking
-
启用 ES 模块
确保使用
import/export
语法,并在package.json
中设置"sideEffects": false
。 -
标记未使用代码
使用
/*#__PURE__*/
标记无副作用的函数调用,帮助 Tree Shaking 识别。
三、代码分割
-
提取公共代码
使用
SplitChunksPlugin
提取公共模块:javascriptoptimization: { splitChunks: { chunks: 'all', cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, name: 'vendors' } } } }
-
动态加载
使用
import()
实现按需加载:javascriptimport('path/to/module').then(module => { module.default(); });
四、优化依赖
-
按需引入
使用
babel-plugin-import
按需加载组件库(如 Ant Design):javascriptplugins: [ ['import', { libraryName: 'antd', style: 'css' }] ]
-
移除无用依赖
使用
webpack-bundle-analyzer
分析并移除未使用的依赖。
五、图片优化
-
压缩图片
使用
image-webpack-loader
压缩图片:javascript{ test: /\.(png|jpe?g|gif|svg)$/, use: [ { loader: 'file-loader', options: { name: 'images/[name].[hash:8].[ext]' } }, { loader: 'image-webpack-loader' } ] }
-
Base64 内联
小图片转为 Base64:
javascript{ test: /\.(png|jpe?g|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } // 小于 8KB 的图片转为 Base64 } ] }
六、Gzip 压缩
-
启用 Gzip
使用
compression-webpack-plugin
生成.gz
文件:javascriptconst CompressionPlugin = require('compression-webpack-plugin'); plugins: [ new CompressionPlugin({ algorithm: 'gzip', test: /\.(js|css)$/ }) ]
-
服务器配置
确保服务器支持 Gzip 压缩(如 Nginx 配置
gzip on;
)。
七、其他优化
-
Scope Hoisting
启用作用域提升,减少闭包:
javascriptoptimization: { concatenateModules: true }
-
移除调试代码
使用
DefinePlugin
移除开发环境代码:javascriptnew webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') })
总结
通过 代码压缩 、Tree Shaking 、代码分割 、依赖优化 等策略,可显著减少 Webpack 打包体积,提升应用性能。
webpack proxy工作原理?为什么能解决跨域
多页面打包是什么,如何实现 / webpack怎么实现多入口分模块打包
SPA打包:只有一个 HTML 页面和一个 JS 入口文件
MPA打包:是指在一个项目中,通过配置,构建多个独立的 HTML 页面,每个页面有自己的 JS 入口和依赖。更适合页面间相互独立。实现步骤如下:
- 定义入口配置:为每个页面配置一个入口文件,例如 page1 和 page2;
- 定义出口配置 :使用
[name].bundle.js
模板字符串,为每个入口文件生成独立的输出文件。 - HTML插件配置 :
HtmlWebpackPlugin
插件能为每个页面生成一个 HTML 文件,并将构建后的资源自动注入到这个 HTML 文件中。 - 优化配置(可选) :根据需要配置代码分割、压缩等优化功能。
- 输出结果:dist 目录中将包含 page1.html、page2.html 以及对应的 page1.bundle.js 和 page2.bundle.js 文件。
css
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'production', // 或 'development'
entry: {
page1: './src/page1/index.js',
page2: './src/page2/index.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
// 为每个页面生成独立的 HTML 文件
plugins: [
new HtmlWebpackPlugin({
filename: 'page1.html',
template: './src/page1/index.html',
chunks: ['page1'],
}),
new HtmlWebpackPlugin({
filename: 'page2.html',
template: './src/page2/index.html',
chunks: ['page2'],
}),
],
};
Chunkhash和Contenthash区别
- Chunkhash:基于整个代码块(chunk)内容生成哈希值,只要该chunk内的任一模块发生变动,哈希值就会改变
- Contenthash:基于单个文件内容生成哈希值,仅当文件内容变化时,哈希值才会更新
打包时Hash码是怎么生成的
一、Hash 码的作用
在文件名中插入 Hash 码,用于标识文件内容。当文件内容变化时,Hash 值改变,触发浏览器缓存失效,确保用户获取最新资源。
二、Hash 码生成规则
Webpack 通过 内容摘要算法(如 MD4)生成哈希值,具体规则由配置的哈希类型决定。
三、三种哈希类型
哈希类型 | 作用范围 | 触发变化的因素 | 适用场景 |
---|---|---|---|
[hash] |
整个项目构建 | 任何文件内容或配置变化 | 不推荐使用(全局影响) |
[chunkhash] |
单个代码块(Chunk) | 当前 Chunk 内容或其依赖变化 | JS 文件 |
[contenthash] |
单个文件内容 | 仅文件自身内容变化 | CSS/图片/字体等静态资源 |
四、配置示例
javascript
// webpack.config.js
module.exports = {
output: {
// JS 文件使用 chunkhash
filename: '[name].[chunkhash:8].js',
// 图片使用 contenthash
assetModuleFilename: 'images/[name].[contenthash:8][ext]'
},
plugins: [
// CSS 文件使用 contenthash
new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' })
]
};
五、哈希生成流程图
总结
[hash]
:全局哈希,任何改动都会变化(慎用)。[chunkhash]
:基于 Chunk 内容,适合 JS 文件。[contenthash]
:基于文件内容,适合静态资源。
合理选择哈希类型可精准控制缓存策略,平衡构建性能和用户体验。
随机值存在一样的情况,如何避免
1. webpack.HashedModuleIdsPlugin
该插件可根据模块路径生成稳定的哈希 ID,避免因模块顺序变化而导致 ID 改变,确保每次构建时模块 ID 一致
2. webpack.NamedModulesPlugin
(Webpack 4 及以下)或 webpack.NamedChunksPlugin
(Webpack 5 及以上)
这两个插件可以使用模块或代码块的路径作为 ID,使 ID 具有可读性和稳定性。
3. terser-webpack-plugin
该插件用于压缩 JavaScript 代码,在压缩过程中可以确保生成的代码具有稳定的哈希值。
总结:通过使用这些插件,可以确保 Webpack 构建过程中生成的随机值(如模块 ID、哈希值等)具有稳定性和唯一性,避免因随机值重复导致的缓存失效等问题。
验证方法
- 修改文件内容后重新构建,观察哈希值是否变化
- 使用
webpack-bundle-analyzer
检查重复模块 - 运行
npx webpack --stats=verbose
查看详细构建日志
通过以上措施可有效避免哈希冲突,确保构建产物的唯一性。
如何对相对路径引用进行优化
webpack和vite的区别都有哪些, 分别适用于什么样的情形
### 为什么 Vite 速度比 Webpack 快?
一、开发模式的差异
- 当使用 Webpack 时,所有的模块都需要在开发前进行打包 , 会增加启动时间和构建时间。
- Vite 则是直接启动,它会在请求模块时再进行实时编译,这种按需动态编译的模式极大地缩短了编译时间,特别是在大型项目中,文件数量众多,Vite 的优势更为明显。
二、底层语言的差异
- Webpack 是基于 Node.js 构建的,毫秒级别的
- Vite 则是基于 esbuild 进行预构建依赖。esbuild 是采用 Go 语言编写的,纳秒级别的
因此,Vite 在打包速度上相比Webpack 有 10-100
倍的提升。
三、热更新的处理
-
Webpack 中,当一个模块或其依赖的模块内容改变时,需要重新编译这些模块。
-
Vite 中,当某个模块内容改变时,只需要让浏览器重新请求该模块即可,这大大减少了热更新的时间。
使用webpack构建时有无做一些自定义操作
在使用 Webpack 构建时,你可以通过编写自定义 Loader、自定义插件或者使用 Webpack 的配置选项来实现一些自定义操作。下面为你详细介绍具体的实现方式。
编写自定义 Loader
Loader 用于对模块的源代码进行转换,你可以编写自己的 Loader 来处理特定类型的文件。
编写自定义插件
插件可以在 Webpack 构建过程的不同阶段执行自定义操作,例如在构建完成后生成一个文件清单。
使用 Webpack 配置选项
Webpack 提供了丰富的配置选项,你可以通过配置这些选项来实现自定义操作,例如修改输出文件名、添加环境变量等。
通过以上方法,你可以在 Webpack 构建过程中实现各种自定义操作,满足不同的项目需求。
什么是长缓存?在webpack中如何做到长缓存优化?
一、什么是长缓存?
长缓存(Long-term Caching) 是一种通过优化资源文件名和缓存策略,使浏览器能够长期缓存静态资源(如 JS、CSS 文件)的技术。其核心目标是:
- 减少重复加载:用户再次访问时直接从缓存加载资源,提升页面加载速度。
- 降低服务器压力:减少不必要的资源请求,节省带宽。
二、长缓存的核心原理
- 内容哈希:根据文件内容生成唯一哈希值,内容不变则文件名不变。
- 分离稳定代码:将频繁变动的代码与稳定代码分离,避免缓存失效。
三、Webpack 长缓存优化方案
1. 使用 [contenthash]
在文件名中添加内容哈希,确保内容变化时文件名更新:
javascript
output: {
filename: '[name].[contenthash:8].js', // JS 文件名
chunkFilename: '[name].[contenthash:8].chunk.js' // 异步 chunk 文件名
}
2. 提取第三方库
将 node_modules
中的依赖单独打包,避免业务代码更新导致缓存失效:
javascript
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
3. 提取 Webpack Runtime
将 Webpack 的运行时代码单独打包,避免因模块 ID 变化导致缓存失效:
javascript
optimization: {
runtimeChunk: 'single'
}
4. 模块 ID 固化
使用 HashedModuleIdsPlugin
或 moduleIds: 'deterministic'
固定模块 ID,避免因模块顺序变化导致缓存失效:
javascript
optimization: {
moduleIds: 'deterministic' // Webpack 5+ 推荐
}
5. 提取 CSS 文件
将 CSS 提取为独立文件,并添加内容哈希:
javascript
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash:8].css', // CSS 文件名
chunkFilename: '[name].[contenthash:8].chunk.css'
})
]
};
四、验证长缓存效果
-
构建产物分析
使用
webpack-bundle-analyzer
检查打包结果,确保代码分割合理。 -
缓存命中率测试
修改业务代码后重新构建,观察
vendors
和runtime
文件是否未变化。 -
浏览器缓存验证
通过开发者工具的 Network 面板,检查资源是否从缓存加载。
五、注意事项
- 避免过度分割
过多的 chunk 文件会增加 HTTP 请求数,影响性能。 - CDN 缓存策略
确保 CDN 配置支持长缓存(如设置Cache-Control: max-age=31536000
)。 - 版本管理
使用版本号或时间戳管理 HTML 文件,确保用户获取最新资源。
通过以上优化,可实现高效的长缓存策略,显著提升用户体验和服务器性能。
什么是bundle,是什么chunk,什么是module?
-
Module:webpack 里一个概念性内容,每个文件都可以看为一个 module。 js、css、图片等都可以看作 module。
-
Chunk:代码块,webpack 处理代码时候的一个中间态,它表示有一组功能相关的模块的集合。一个 Chunk 可以由多个模块(module)组成
-
Bundle:是 Webpack 构建结果的输出,由一个或多个 Chunk 的合并优化后的结果,最终以文件形式输出,用于在浏览器中加载和执行。
externals
文件监听是什么,怎么用,原理是什么
按需加载如何实现,原理是什么(高频)
一、什么是按需加载?
按需加载(Lazy Loading) 是一种将代码分割为多个小块,在需要时动态加载的技术。其核心目标是:
- 减少首屏加载时间:只加载当前页面所需的代码。
- 优化资源利用率:按需加载非关键资源,减少带宽消耗。
二、实现方式
1. 使用 import()
动态导入
Webpack 会将 import()
语法自动转换为动态加载的代码块。
示例:
javascript
// 动态加载模块
button.addEventListener('click', () => {
import('./module.js').then(module => {
module.default(); // 调用模块的默认导出
});
});
打包结果:
- 生成独立的 chunk 文件(如
1.bundle.js
)。 - 在用户点击按钮时动态加载该文件。
2. Vue 中的按需加载
使用 defineAsyncComponent
实现组件的动态加载。
示例:
javascript
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
);
三、核心原理
-
代码分割
- Webpack 将
import()
语法标记为动态加载点,生成独立的 chunk 文件。
- Webpack 将
-
运行时加载
- 在浏览器中通过
JSONP
或fetch
动态加载 chunk 文件。
- 在浏览器中通过
-
缓存管理
- 使用
webpackJsonp
或import()
的缓存机制,避免重复加载。
- 使用
四、Webpack 配置
-
默认配置
Webpack 5+ 默认支持动态加载,无需额外配置。
-
自定义 chunk 名称
使用魔法注释指定 chunk 名称:
javascriptimport(/* webpackChunkName: "my-chunk" */ './module.js');
-
预加载与预获取
使用魔法注释优化加载优先级:
javascriptimport(/* webpackPrefetch: true */ './module.js'); // 空闲时预加载 import(/* webpackPreload: true */ './module.js'); // 高优先级预加载
五、优化建议
-
合理分割代码
- 按路由或功能模块分割代码,避免过度拆分。
-
预加载关键资源
- 对非首屏但关键的资源(如首页轮播图)启用
webpackPreload
。
- 对非首屏但关键的资源(如首页轮播图)启用
-
错误处理
-
捕获动态加载失败的情况:
javascriptimport('./module.js') .then(module => module.default()) .catch(err => console.error('加载失败', err));
-
六、注意事项
-
兼容性
import()
语法需要支持 Promise 的浏览器(可通过@babel/plugin-syntax-dynamic-import
转译)。
-
性能监控
- 使用
webpack-bundle-analyzer
分析 chunk 文件大小,确保合理分割。
- 使用
-
SEO 影响
- 动态加载的内容可能不被搜索引擎抓取,需结合服务端渲染(SSR)优化。
通过按需加载,可显著提升应用性能,优化用户体验。
AMD和CMD
AMD (Asynchronous Module Definition)和CMD (Common Module Definition)的主要区别在于加载方式、依赖声明和适用环境
加载方式
- AMD :支持异步加载,模块的加载不会阻塞页面其他内容的加载和执行。这种异步加载方式使得AMD尤其适合在浏览器环境中使用,尤其是在Web应用**中12。
- CMD:支持同步加载,模块会在遇到时立即执行,不管它是否已经加载完成。这种同步加载方式使得CMD更适合在服务器端环境或需要同步加载的场景中使用
依赖声明
- AMD:在定义模块时需要明确列出所有依赖的模块,并将它们作为参数传递给模块的回调函数。这种"依赖前置"的方式使得代码结构清晰,但可能会增加模块间的耦合度
- CMD:不需要在定义模块时明确列出所有依赖的模块,而是在需要使用模块时再引入它们。这种"依赖就近"的方式使得代码更加灵活,适合复杂的模块化需求。
适用环境
模块规范 | 适用场景 |
---|---|
AMD | 浏览器端,适合依赖关系明确、模块数量较少的场景。 |
CMD | 浏览器端和 Node.js,适合依赖关系复杂、模块数量较多的场景。 |
介绍模块化发展历程
模块化主要作用:抽离公共代码,隔离作用域,避免代码冲突
- 无模块化 → 2. IIFE → 3. CommonJS → 4. AMD → 5. UMD → 6. ES6 Module
最终趋势是 ES6 Module,成为现代 JavaScript 开发的标准。
常用的loader/用过哪些loader
-
babel-loader:将ES6+的代码转换成ES5的代码。
-
css-loader:解析CSS文件,并处理CSS中的依赖关系。
-
style-loader:将CSS代码注入到HTML文档中。
-
file-loader:用于打包文件类型的资源,并返回其publicPath。
-
url-loader:类似于file-loader,但是可以将小于指定大小的文件转成base64编码的Data URL格式
-
sass-loader:将Sass文件编译成CSS文件。
-
less-loader:将Less文件编译成CSS文件。
-
postcss-loader:自动添加CSS前缀,优化CSS代码等。
-
vue-loader:将Vue单文件组件编译成JavaScript代码。
-
source-map-loader: 加载额外的
Source Map
文件 -
eslint-loader: 通过ESlint 检查js代码
-
cache-loader: 可以在一些开销较大的
Loader
之前添加可以将结果缓存到磁盘中,提高构建的效率 -
thread-loader: 多线程打包,加快打包速度
如何编写loaders/自定义loader
juejin.cn/post/713820... 详细参考loader编写思路
在 Webpack 中编写 Loader 的核心流程(以同步 Loader 为例):
1. 接收输入:获取源码内容
- loader支持链式调用,上一个loader的执行结果会作为下一个loader的入参。 根据这个特性,我们知道我们的loader 想要有返回值,并且这个返回值必须是标准的JavaScript字符串或者
AST
代码结构,这样才能保证下一个loader的正常调用。
javascript
// 基础结构
module.exports = function(source, map, meta) {
// source: 输入内容
// map: SourceMap
// meta: 其他元数据
return transformedSource; // 返回处理后的字符串
}
2. 转换处理:按需求修改源码
-
loader的主要职责就是将代码转译为webpack可以理解的js代码。
- 根据这个特性,loader内部一般需要通过
return / this.callback
来返回转换后的结果
- 根据这个特性,loader内部一般需要通过
-
单个loader一把只负责单一的功能。
- 根据这个特性,我们的loader应该符合单一职责的原则,尽量别让单个loader执行太多职责
-
善于利用开发工具
- loader-utils : loader-utils 是一个非常重要的 Loader 开发辅助工具,为开发中提供了诸如读取配置、
requestString
的序列化和反序列化、getOptions/getCurrentRequest/parseQuery
等核心接口....等等功能,对于loader的开发十分有用 - schema--utils :schema-utils是用于校验用户传入loader的参数配置的校验工具,也是在开发中十分有用
- loader-utils : loader-utils 是一个非常重要的 Loader 开发辅助工具,为开发中提供了诸如读取配置、
-
loader是无状态的
- 根据此特性,我们不应该在loader保存状态
javascript
module.exports = function(source) {
// 替换操作
const result = source.replace(/world/g, 'loader');
// 返回处理后的 JS 代码
return `export default ${JSON.stringify(result)}`;
}
3. 异步 Loader 写法
处理需要异步操作时(如文件读取):
javascript
module.exports = function(source) {
const callback = this.async(); // 获取异步回调
setTimeout(() => {
const result = source.replace(/world/g, 'loader');
callback(null, result); // 参数:错误, 处理结果
}, 100);
}
4. 本地测试方法
在 webpack.config.js
中直接引用本地 Loader:
javascript
module.exports = {
module: {
rules: [
{
test: /\.txt$/,
use: [
{
loader: path.resolve(__dirname, 'loaders/my-loader.js'),
options: { /* 传参 */ }
}
]
}
]
}
}
5. 核心特性
功能 | 实现方式 |
---|---|
获取参数 | 通过 this.getOptions() 获取配置中的 options |
处理二进制 | 设置 raw = true ,接收 Buffer 类型输入 |
Source Map | 返回 this.callback(null, result, sourceMap) |
缓存优化 | 通过 this.cacheable(false) 关闭缓存(默认启用) |
6. 完整示例(带参数传递)
javascript
// my-loader.js
module.exports = function(source) {
const options = this.getOptions(); // 获取配置参数
return source.replace(new RegExp(options.target, 'g'), options.replaceWith);
}
// webpack.config.js
{
loader: path.resolve(__dirname, 'loaders/my-loader.js'),
options: {
target: 'foo',
replaceWith: 'bar'
}
}
总结
编写 Loader 只需三步:
- 接收输入:获取源码内容
- 转换处理:按需求修改源码
- 返回输出:返回字符串或调用回调
实际开发中可结合 loader-utils
等工具库处理参数和复杂场景。
webpack 如何确定依赖引用顺序
依赖图的构建过程
- 入口点:Webpack 从配置的入口点
entry
开始,从入口文件开始解析。 - 递归解析:递归解析每个模块的依赖,找到所有被引用的模块。
- 构建依赖图:根据模块之间的依赖关系构建一个依赖图。
- 确定顺序:根据依赖图确定模块的引用顺序,确保被依赖的模块先于依赖它们的模块打包。
如何保证众多Loader按照想要的顺序执行?
可以通过enforce
来强制控制Loader的执行顺序 (pre
表示在所有正常的loader执行之前执行,post
则表示在之后执行)
loader的执行顺序为什么是后写的先执行
Webpack 中 ***Loader 的执行顺序是「从右到左」*(配置数组靠后的 Loader 先执行),原因如下:
核心原理:
-
链式管道模型 :
Loader 处理资源的过程类似管道传输,后一个 Loader 的输入是前一个 Loader 的输出。配置顺序需要直观反映资源逐步加工 的逻辑。
示例:lessjavascriptCopy Code use: ['style-loader', 'css-loader', 'sass-loader']
实际流程:
SCSS →
sass-loader
(编译为 CSS) →css-loader
(解析依赖) →style-loader
(注入 DOM)。
一句话总结:
后写的 Loader 先执行,是为了让配置顺序与资源处理的实际步骤一致(如先编译 SCSS → 再处理 CSS → 最后插入 DOM)。
webpack如何配sass,需要配哪些loader
所需的 loader
sass-loader
:该 loader 依赖 Sass 编译器(如 Dart Sass),它能把 Sass(.sass
)或 SCSS(.scss
)文件编译成 CSS 文件。css-loader
:负责解析 CSS 文件里的@import
和url()
等语句,处理 CSS 模块和 CSS 中的依赖关系,将 CSS 文件转换为 CommonJS 模块。style-loader
:会把编译后的 CSS 以<style>
标签的形式插入到 DOM 中,让样式在页面上生效。mini-css-extract-plugin
(可选) :在生产环境中,通常使用该插件将 CSS 提取到单独的文件中,而不是将其内嵌到 JavaScript 代码里,这样有助于提升性能和缓存效率。
配置解释
entry
和output
:指定入口文件和输出文件的路径。module.rules
:定义了处理不同类型文件的规则。对于.scss
或.sass
文件,使用style-loader
(开发环境)或MiniCssExtractPlugin.loader
(生产环境)、css-loader
和sass-loader
来处理。MiniCssExtractPlugin
:在生产环境下,使用该插件将 CSS 提取到单独的文件中。
开发环境与生产环境的区别
- 开发环境 :使用
style-loader
将 CSS 内联到 JavaScript 中,这样可以实现热更新,方便开发调试。 - 生产环境 :使用
MiniCssExtractPlugin.loader
将 CSS 提取到单独的文件中,以提高性能和缓存效率。
postcss配置
PostCSS 是一个用 JavaScript 编写的工具,用于将 CSS 转换为另一种 CSS。它可以处理诸如添加浏览器前缀、压缩 CSS、使用未来的 CSS 特性等任务。以下为你详细介绍在不同场景下如何配置 PostCSS。
安装依赖
首先,确保你已经安装了 PostCSS 及其相关插件,在项目根目录下的终端中执行以下命令: bash
css
npm install postcss postcss-loader autoprefixer cssnano --save-dev
postcss
:核心库。postcss-loader
:用于在 Webpack 中使用 PostCSS。autoprefixer
:自动添加浏览器前缀。cssnano
:压缩和优化 CSS。
在 package.json
中配置浏览器列表
为了让 autoprefixer
知道要为哪些浏览器添加前缀,需要在 package.json
中配置 browserslist
字段:
json
json
{
"browserslist": [
"last 2 versions",
"> 1%",
"not dead"
]
}
这个配置表示为最近两个版本的浏览器、市场占有率大于 1% 的浏览器以及未停止维护的浏览器添加前缀。
如何配置把js、css、html单独打包成一个文件
在项目根目录下的终端中执行以下命令来安装所需的依赖:
bash
css
npm install webpack webpack-cli html-webpack-plugin mini-css-extract-plugin --save-dev
webpack
和webpack-cli
:Webpack 的核心库和命令行工具。html-webpack-plugin
:用于生成 HTML 文件,并自动注入打包后的 JS 和 CSS 文件。mini-css-extract-plugin
:用于将 CSS 提取到单独的文件中。
loader和plugin有什么区别(高频)
webpack的plugins和loaders的实现原理( webpack里面的插件是怎么实现的) x4(高频)
常用的plugins
如何编写plugins
webpack热更新(HMR)原理(高频)
什么是code spliting?原理
Code Splitting代码分割,是一种优化技术。它允许将一个大的chunk拆分成多个小的chunk,从而实现按需加载,减少初始加载时间,并提高应用程序的性能 。在Webpack中通过optimization.splitChunks配置项来开启代码分割
什么是tree shaking?原理?如何实现
一、什么是 Tree Shaking?
Tree Shaking 是一种通过静态分析移除 JavaScript 中未使用代码的优化技术。其名称源自"摇树"动作------摇掉树上未成熟的果实(未使用的代码)。可以减小打包文件的体积,提高加载性能
二、核心原理
-
静态分析
- 在编译阶段分析代码的
import/export
依赖关系。 - 识别未被引用的模块或函数。
- 在编译阶段分析代码的
-
标记未使用代码
- 通过
/*#__PURE__*/
标记无副作用的函数调用。 - 结合
package.json
的"sideEffects"
字段排除副作用模块。
- 通过
-
移除死代码
- 在压缩阶段(如 Terser)移除标记为未使用的代码。
Tree shaking的工作流程可以分为
1.标记 哪些导出值没有被使用; 2. 使用Terser将这些没用到的导出语句删除
标记的流程如下:
-
make阶段:收集模块导出变量并记录到模块依赖关系图中
-
seal阶段:遍历模块依赖关系图并标记那些导出变量有没有被使用
-
构建 阶段:利用Terser将没有被用到的导出语句删除
三、实现条件
-
使用 ES 模块
- 代码必须使用
import/export
语法(CommonJS 不支持 Tree Shaking)。
- 代码必须使用
-
配置生产模式
- Webpack 的
mode
设置为production
,默认启用 Tree Shaking。
- Webpack 的
-
标记副作用
-
在
package.json
中声明无副作用的模块:json{ "sideEffects": false // 或指定有副作用的文件 ["*.css", "*.scss"] }
-
四、Webpack 配置
-
启用 Tree Shaking
javascriptmodule.exports = { mode: 'production', // 生产模式默认启用 optimization: { usedExports: true, // 标记未使用的导出 启动 minimize: true // 压缩时移除未使用代码 } };
-
标记无副作用函数
javascript/*#__PURE__*/ someFunction(); // 标记为无副作用
五、验证 Tree Shaking 效果
-
检查打包结果
- 使用
webpack-bundle-analyzer
分析打包文件,确认未使用代码被移除。
- 使用
-
查看 Terser 日志
- 启用
TerserPlugin
的extractComments
选项,查看移除的代码。
- 启用
六、注意事项
-
避免副作用
- 确保模块的导入不会触发副作用(如全局变量修改)。
-
第三方库支持
- 确保第三方库提供 ES 模块版本(如
lodash-es
)。
- 确保第三方库提供 ES 模块版本(如
-
Babel 配置
-
避免 Babel 将 ES 模块转换为 CommonJS(设置
modules: false
):json{ "presets": [["@babel/preset-env", { "modules": false }]] }
-
通过以上配置和优化,可有效实现 Tree Shaking,减少打包体积,提升应用性能。
dev-server是怎么跑起来?
-
初始化配置
- 读取
webpack.config.js
中的devServer
配置(如端口、代理、静态目录等)。 - 合并 Webpack 的默认配置和用户自定义配置。
- 读取
-
创建本地服务器
- 基于 Express 框架启动 HTTP 服务,托管静态资源。
- 使用 webpack-dev-middleware 中间件将 Webpack 的编译结果写入内存(而非磁盘),提升性能。
-
绑定 WebSocket 通信
- 通过 sockjs 或原生 WebSocket 建立浏览器与服务器的长连接,用于推送热更新(HMR)消息。
-
启动 Webpack 编译
- 调用 Webpack 的 API 触发初次编译,生成内存中的打包文件。
- 监听文件变化,触发增量编译。
``
基础配置
arduino
// webpack.config.js
module.exports = {
devServer: {
port: 8080, // 端口
hot: true, // 启用热更新
static: './dist', // 托管静态目录(优先使用内存文件)
open: true, // 自动打开浏览器
historyApiFallback: true // 支持前端路由(如 React Router)
}
};
核心运行原理
1. 内存资源托管
2. 热更新(HMR)机制
3.解决跨域:将特定 API 请求转发到后端服务器:
总结
Webpack Dev Server 通过内存编译 + WebSocket 通信 + HMR 运行时 的组合,实现了高效的本地开发体验。理解其原理有助于优化配置(如调整 watchOptions
)和解决热更新失效等疑难问题。
babel概念及原理
babel 可以将代码转译为想要的目标代码,并且对目标环境不支持的api 自动 polyfill
。而babel 实现这些功能的流程是 解析(parse)-转换(transfrom)-生产(generator)
,接下来我们就看看每个流程都做了啥工作
-
解析
:根据代码生成对应的AST
结构- 进行代码分析,将代码分割成token 流(语法单元数组),再根据token 流生成对应的
AST
- 进行代码分析,将代码分割成token 流(语法单元数组),再根据token 流生成对应的
-
转换
:遍历AST
节点并生成新的AST
节点 -
生成
:根据新的AST
生成目标代码
SourceMap 原理(高频)
source map 是将编译打包后的代码映射回源码 可以通过devtool 配置项来设置,还可以通过SourceMapDevToolPlugin
实现更加精细粒度的控制
devtool 配置项和
SourceMapDevToolPlugin
不能同时使用,因为devtool选项已经内置了这些插件,如果同时使用相当于应用了两次插件
配置 devtool: 'source-map'
后,在编译过程中,会生成一个 .map
文件,一般用于代码调试和错误跟踪。
-
包含了源代码、编译后的代码、以及它们之间的映射关系。
-
编译后的文件通常会在文件末尾添加一个注释,指向 SourceMap文件的位置。
// # sourceMappingURL=example.js.map
-
当在浏览器开发者工具调试时,浏览器会读取这行注释并加载对应的 SourceMap 文件
报错时,点击跳转。即使运行的是编译后的代码,也能够追溯到原始源代码的具体位置,而不是处理经过转换或压缩后的代码,从而提高了调试效率。
模式 | 特点 | 适用场景 |
---|---|---|
eval |
最快,但映射信息内联在 eval 中,只能映射到转换后的代码(非原始代码)。 |
开发环境(快速构建) |
cheap-source-map |
生成单独的 .map 文件,仅映射行号(不映射列号),速度较快。 |
开发环境(平衡速度与精度) |
source-map |
完整独立的 .map 文件,包含行列精确映射,但构建速度较慢。 |
生产环境(需精确调试) |
hidden-source-map |
生成 .map 文件,但 Bundle 中不包含引用注释,需手动关联。 |
生产环境(保护源码隐私) |
cheap-module-source-map |
类似 cheap-source-map ,但映射到 Loader 转换前的源码(如 Babel 前的代码)。 |
开发环境(需调试原始代码) |
这么多的选择,那么我们应该如何使用呢,根据我的实践,我觉得比较好的设置应该是下面这样
- 开发环境:
cheap-module-eval-source-map
,生产这种source map
速度最快,并且由于开发环境下没有代码压缩,所以不会影响断点调试 - 生产环境:
hidden-source-map
,由于进行了代码压缩,所以并不会占用多大的体积
避免在生产中使用
inline-
和eval-
因为它们会增加 bundle 体积大小 并且降低整体性能
选择原则
- 开发环境 :优先速度,选
eval
、cheap-
系列。 - 生产环境 :需调试则用
source-map
,否则禁用或选hidden-source-map
。 - 精度要求 :精确调试选含
source-map
的模式,快速构建选eval
或cheap-
。
跟 Mainfest 的区别
-
SourceMap 主要用于调试目的,让开发者能够在压缩或转译后的代码中追踪到原始代码。
-
Manifest 文件用于资源管理,用于优化资源的加载和缓存。
如何对bundle体积进行监控和分析
VSCode
中有一个插件 Import Cost
可以帮助我们对引入模块的大小进行实时监测,还可以使用 webpack-bundle-analyzer
生成 bundle
的模块组成图,显示所占体积。
bundlesize
工具包可以进行自动化资源体积监控。
文件指纹是什么?怎么用?
概念
文件指纹是指文件打包后的一连串后缀,如哈希值。
作用
- 版本管理: 在发布版本时,通过文件指纹来区分 修改的文件 和 未修改的文件。
- 使用缓存: 浏览器通过文件指纹是否改变来决定使用缓存文件还是请求新文件(浏览器可复用本地缓存,提升加载速度)。
种类
Hash
:和整个项目的构建相关,只要项目有修改(compilation
实例改变),Hash
就会更新粒度最粗)Contenthash
:和文件的内容有关,只有内容发生改变时才会修改Chunkhash
:和webpack 构架的chunk有关 不同的entry 会构建出不同的chunk (不同ChunkHash
之间的变化互不影响) javascript
复制
css
// webpack.config.js
module.exports = {
output: {
filename: 'js/[name].[chunkhash:8].js', // JS 使用 chunkhash
chunkFilename: 'js/[name].[chunkhash:8].js',
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css', // CSS 使用 contenthash
}),
],
module: {
rules: [
{
test: /.(png|jpe?g|gif)$/,
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]', // 图片使用 hash
},
},
],
},
};
如何使用
- JS文件:使用
Chunkhash
- CSS文件:使用
Contenthash
- 图片等静态资源: 使用
hash
生产环境的output 为了区分版本变动,通过
Contenthash
来达到清理缓存及时更新的效果,而开发环境中为了加快构建效率,一般不引入Contenthash
为什么pnpm比npm快
Pnpm 比 npm 快的原因在于其优化的文件存储方式、依赖管理方式以及并行下载能力。 以下是详细介绍:
-
Pnpm 使用基于内容寻址的文件系统来存储磁盘上的所有文件,这意味着它不会在磁盘中重复存储相同的依赖包,即使这些依赖包被不同的项目所依赖。这种存储方式使得Pnpm在安装依赖时能够更高效地利用磁盘空间,同时也减少了下载和安装的时间。
-
Pnpm 在下载和安装依赖时采用了并行下载的能力,这进一步提高了安装速度。
-
Pnpm 还具有一些其他特性,例如节省空间的硬链接和符号链接的使用,这些都有助于提高其性能。
npm run start 的整个过程
以下是 npm run start
的简明执行过程:
1. 解析命令
-
查找脚本 :在
package.json
的scripts
字段中查找start
命令。json{ "scripts": { "start": "react-scripts start" } }
2. 执行脚本
- 调用命令 :运行
start
对应的命令(如react-scripts start
)。 - 环境变量注入 :自动注入
NODE_ENV=development
(开发环境)。
3. 启动开发服务器
- 初始化构建工具:调用 Webpack/Vite 等工具,加载配置文件。
- 编译代码:将源代码打包为浏览器可执行的文件(如 JS、CSS)。
- 启动本地服务器:通过 Express 或 Webpack Dev Server 托管静态资源。
4. 热更新(HMR)
- 监听文件变化:实时监控文件修改。
- 局部更新:通过 WebSocket 推送更新内容,浏览器局部刷新。
5. 打开浏览器
- 自动访问 :默认打开
http://localhost:3000
(端口可配置)。
npm install的执行过程
详细细节copy title dp
执行过程大致如下:
- 读取
package.json
文件,该文件列出了项目所需要的依赖。 - 根据
package.json
中的依赖信息以及node_modules
目录状态,npm 会决定哪些模块需要下载和安装。 - npm 会查看每个模块的可用版本,并选择符合
package.json
中指定版本范围的最新版本进行安装。 - 下载所需模块到本地的
node_modules
目录。 - 如果模块包含子模块(
package.json
中dependencies
或devDependencies
中的模块),则递归执行上述步骤安装这些子模块
常见问题与优化
问题 | 原因与解决 |
---|---|
安装速度慢 | 使用国内镜像(npm config set registry https://registry.npmmirror.com )或 pnpm |
node_modules 体积过大 |
使用 npm dedupe 减少冗余,或切换到 pnpm (硬链接节省空间) |
版本冲突(Peer Deps) | 根据警告手动调整版本,或使用 npm install --force 强制覆盖 |
锁文件冲突 | 禁止手动修改锁文件,始终通过 npm install 自动更新 |
总结
npm install
的核心流程是:解析依赖 → 下载包 → 扁平化安装 → 执行脚本 → 生成锁文件 。
理解这一过程有助于:
- 解决依赖冲突问题。
- 优化安装速度和体积。
- 保证多环境的一致性(通过锁文件)。
eslint概念以及原理
ESLint 概念 :
ESLint 是一个用于 JavaScript/TypeScript 的静态代码分析工具,用于检测代码中代码质量检查(如未定义变量) 和风格统一。
核心原理:
-
解析代码为 AST
将源代码解析为抽象语法树(AST),结构化表示代码逻辑,便于分析。
-
遍历 AST 应用规则
通过预定义的规则(如变量未使用、缩进错误等)检查 AST 节点,识别问题。规则可自定义或通过插件扩展(如 Vue、React 专用规则)。
-
报告与修复
标记问题位置并输出警告/错误,部分问题可通过
--fix
自动修复(如自动校正缩进)。 -
配置灵活
支持全局/项目级配置(如
.eslintrc
),可继承共享配置(如eslint-config-airbnb
),集成到编辑器、构建流程中实时反馈。
作用场景:
- 代码质量检查(如未定义变量)
- 风格统一(如引号、缩进)
- 最佳实践约束(如避免
eval()
) - 团队协作规范强制执行。
package.json文件中的devDependdencies和dependdencies对象有什么区别
总结
dependencies
:生产环境依赖,打包时会包含。devDependencies
:开发环境依赖,不会打包到最终产物。
正确区分两者可以优化项目体积和构建速度。
什么是CI/CD dp
- CI(持续集成,Continuous Integration)
开发者频繁将代码合并到主分支,自动触发构建和测试
,确保代码质量。 - CD(持续交付/部署,Continuous Delivery/Deployent)
将通过测试的代码自动部署
到测试或生产环境
,快速交付新功能。
Mainfest 文件是什么,有什么用
Mainfest(更新清单),通常是一个 JSON 文件。需要配置 WebpackManifestPlugin
插件 在 Webpack 输出阶段生成,用于记录所有模块及其依赖关系的映射用来管理模块加载、优化浏览器缓存。 包含:
- 模块标识符: 每个模块都有一个唯一标识符,这些标识符用于在运行时查找和加载模块。
- Chunk 映射关系:包含 chunk 与包含的模块之间的映射关系,以及 chunk 之间的依赖关系。这有助于运行时确定哪些 chunk 需要被加载。
- Hash 值: 每个输出文件的 hash 值。有助于浏览器判断文件是否有更新,从而决定是加载缓存中的资源还是重新请求新的资源。
css
{
"main.js": "main.1a2b3c4d5e6f7g8h9i0j.js",
"vendor.js": "vendor.1a2b3c4d5e6f7g8h9i0j.js"
}
生成的 Manifest 文件可以用于以下场景:
- 服务端渲染: 在服务端渲染时,可以使用 Manifest 文件来生成正确的脚本标签,确保引用最新的资源。
- 缓存管理: 通过记录文件的哈希值,确保在文件内容变化时,客户端能够获取到最新的文件,而不是使用缓存的旧文件。
- 动态加载: 在需要按需加载模块时,可以使用 Manifest 文件来查找模块的路径。
如何在 WebPack 中代码分割/提取一个公共模块
这里方案我们使用 SplitChunksPlugin ,这是 Webpack 的内置插件,用于将公共的依赖模块提取到单独的 chunk 中,减少代码重复、提高加载速度。
在 webpack.config.js 文件中,你可以在配置 optimization.splitChunks
选项来指定如何提取公共模块
基本配置
java
js
代码解读
复制代码
module.exports = {
// 其他配置...
optimization: {
splitChunks: {
chunks: 'all', // 对所有模块进行优化
}
}
};
高级配置: 通过cacheGroups
自定义分割策略
less
js
代码解读
复制代码
module.exports = {
// 其他配置...
optimization: {
splitChunks: {
chunks: 'all', // 对所有模块进行优化
minSize: 20000, // 生成chunk的最小大小(以字节为单位)
minChunks: 1, // 分割前必须共享模块的最小块数
maxAsyncRequests: 30, // 按需加载时的最大并行请求数
maxInitialRequests: 30, // 入口点的最大并行请求数
automaticNameDelimiter: '~', // 默认情况下,webpack将使用块的来源和名称生成名称(例如vendors~main.js)
cacheGroups: { // 缓存组可以继承或覆盖splitChunks.*的任何选项
vendors: {
test: /[/]node_modules[/]/, // 控制哪些模块被这个缓存组选中
priority: -10 // 一个模块可以属于多个缓存组。优化将优先考虑具有更高优先级的缓存组
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true // 如果当前块包含已经从主束分离出的模块,则将重用它而不是生成新的块
}
}
}
}
};
-
提取第三方库为chunk:通过
vendors
缓存组。- 可以将
node_modules
的模块提取到单独的文件中,这对于提取大型的第三方库(如React, Vue等)特别有用。
- 可以将
-
提取公共模块为chunk:通过
default
缓存组。- Webpack 会自动提取,被多个入口共享的模块到一个或多个公共块中。