webpack常用开发体验/分析相关工具
寻找项目中未使用资源 unused-webpack-plugin
它能够根据webpack的统计信息,查找出项目中未使用的资源,包含图片、js、css、html等资源,在项目重构是很有用
效果图:
使用方式:
webpack.dev.config.js
const UnusedWebpackPlugin = require('unused-webpack-plugin')
module.exports = {
...,
plugins: [
new UnusedWebpackPlugin({
directories: [path.join(__dirname, 'src')],
root: path.join(__dirname, './')
})
]
}
项目地址:github
收集统计信息
webpack在运行过程中会收集相关统计信息,包含assets、chunks、modules、entrypoints、namedChunkGroups、errors、warnings等信息
使用方式:
// 会在项目根目录下生成stats.json文件
npx webpack --json > stats.json
stats.json
{
"hash": "897897e89cdd305485ad",
"version": "5.38.1",
"time": 214,
"builtAt": 1623295024353,
"publicPath": "auto",
"outputPath": "/Users/xcc/Documents/xcc/tl/app/aep/dist",
"assetsByChunkName": {
"main": ["main.js"]
},
"assets": [
{
"type": "asset",
"name": "main.js",
"size": 352,
"emitted": false,
"comparedForEmit": false,
"cached": true,
"info": {
"javascriptModule": false,
"minimized": true
},
"chunkNames": ["main"],
"chunkIdHints": [],
"auxiliaryChunkNames": [],
"auxiliaryChunkIdHints": [],
"related": {},
"chunks": [179],
"auxiliaryChunks": [],
"isOverSizeLimit": false
}
],
"chunks": [
{
"rendered": true,
"initial": true,
"entry": true,
"recorded": false,
"size": 1033,
"sizes": {
"javascript": 1033
},
"names": ["main"],
"idHints": [],
"runtime": ["main"],
"files": ["main.js"],
"auxiliaryFiles": [],
"hash": "cc1b38641cf24d32d65e",
"childrenByOrder": {},
"id": 179,
"siblings": [],
"parents": [],
"children": [],
"modules": [
{
"type": "module",
"moduleType": "javascript/auto",
"layer": null,
"size": 1033,
"sizes": {
"javascript": 1033
},
"built": true,
"codeGenerated": true,
"buildTimeExecuted": false,
"cached": false,
"identifier": "/Users/xcc/Documents/xcc/tl/app/aep/src/index.js",
"name": "./src/index.js",
"nameForCondition": "/Users/xcc/Documents/xcc/tl/app/aep/src/index.js",
"index": 0,
"preOrderIndex": 0,
"index2": 0,
"postOrderIndex": 0,
"cacheable": true,
"optional": false,
"orphan": false,
"dependent": false,
"issuer": null,
"issuerName": null,
"issuerPath": null,
"failed": true,
"errors": 1,
"warnings": 0,
"id": 138,
"issuerId": null,
"chunks": [179],
"assets": [],
"reasons": [
{
"moduleIdentifier": null,
"module": null,
"moduleName": null,
"resolvedModuleIdentifier": null,
"resolvedModule": null,
"type": "entry",
"active": true,
"explanation": "",
"userRequest": "./src",
"loc": "main",
"moduleId": null,
"resolvedModuleId": null
}
],
"usedExports": [],
"providedExports": null,
"optimizationBailout": [
"ModuleConcatenation bailout: Module is not an ECMAScript module"
],
"depth": 0
}
],
"origins": [
{
"module": "",
"moduleIdentifier": "",
"moduleName": "",
"loc": "main",
"request": "./src"
}
]
}
],
"modules": [
{
"type": "module",
"moduleType": "javascript/auto",
"layer": null,
"size": 1033,
"sizes": {
"javascript": 1033
},
"built": true,
"codeGenerated": true,
"buildTimeExecuted": false,
"cached": false,
"identifier": "/Users/xcc/Documents/xcc/tl/app/aep/src/index.js",
"name": "./src/index.js",
"nameForCondition": "/Users/xcc/Documents/xcc/tl/app/aep/src/index.js",
"index": 0,
"preOrderIndex": 0,
"index2": 0,
"postOrderIndex": 0,
"cacheable": true,
"optional": false,
"orphan": false,
"issuer": null,
"issuerName": null,
"issuerPath": null,
"failed": true,
"errors": 1,
"warnings": 0,
"id": 138,
"issuerId": null,
"chunks": [179],
"assets": [],
"reasons": [
{
"moduleIdentifier": null,
"module": null,
"moduleName": null,
"resolvedModuleIdentifier": null,
"resolvedModule": null,
"type": "entry",
"active": true,
"explanation": "",
"userRequest": "./src",
"loc": "main",
"moduleId": null,
"resolvedModuleId": null
}
],
"usedExports": [],
"providedExports": null,
"optimizationBailout": [
"ModuleConcatenation bailout: Module is not an ECMAScript module"
],
"depth": 0
}
],
"entrypoints": {
"main": {
"name": "main",
"chunks": [179],
"assets": [
{
"name": "main.js"
}
],
"filteredAssets": 0,
"assetsSize": null,
"auxiliaryAssets": [],
"filteredAuxiliaryAssets": 0,
"auxiliaryAssetsSize": 0,
"children": {},
"childAssets": {},
"isOverSizeLimit": false
}
},
"namedChunkGroups": {
"main": {
"name": "main",
"chunks": [179],
"assets": [
{
"name": "main.js"
}
],
"filteredAssets": 0,
"assetsSize": null,
"auxiliaryAssets": [],
"filteredAuxiliaryAssets": 0,
"auxiliaryAssetsSize": 0,
"children": {},
"childAssets": {},
"isOverSizeLimit": false
}
},
"errors": [
{
"moduleIdentifier": "/Users/xcc/Documents/xcc/tl/app/aep/src/index.js",
"moduleName": "./src/index.js",
"loc": "32:2",
"message": "Module parse failed: Unexpected token (32:2)\nYou may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders\n| \n| ReactDOM.render(\n> <ConfigProvider locale={zhCN}>\n| <Provider store={store}>\n| <App />",
"moduleId": 138,
"moduleTrace": [],
"stack": "ModuleParseError: Module parse failed: Unexpected token (32:2)\nYou may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders\n| \n| ReactDOM.render(\n> <ConfigProvider locale={zhCN}>\n| <Provider store={store}>\n| <App />\n at handleParseError (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:923:19)\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:1025:5\n at processResult (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:745:11)\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:809:5\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/loader-runner/lib/LoaderRunner.js:406:3\n at iterateNormalLoaders (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/loader-runner/lib/LoaderRunner.js:232:10)\n at Array.<anonymous> (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/loader-runner/lib/LoaderRunner.js:223:4)\n at runCallbacks (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:27:15)\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:200:4\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/graceful-fs/graceful-fs.js:123:16"
}
],
"errorsCount": 1,
"warnings": [
{
"message": "configuration\nThe 'mode' option has not been set, webpack will fallback to 'production' for this value.\nSet 'mode' option to 'development' or 'production' to enable defaults for each environment.\nYou can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/",
"stack": "NoModeWarning: configuration\nThe 'mode' option has not been set, webpack will fallback to 'production' for this value.\nSet 'mode' option to 'development' or 'production' to enable defaults for each environment.\nYou can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/WarnNoModeSetPlugin.js:20:30\n at Hook.eval [as call] (eval at create (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/tapable/lib/HookCodeFactory.js:19:10), <anonymous>:21:1)\n at Hook.CALL_DELEGATE [as _call] (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/tapable/lib/Hook.js:14:14)\n at Compiler.newCompilation (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:1033:30)\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:1076:29\n at Hook.eval [as callAsync] (eval at create (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)\n at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/tapable/lib/Hook.js:18:14)\n at Compiler.compile (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:1071:28)\n at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:498:12\n at Compiler.readRecords (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:910:11)"
}
],
"warningsCount": 1,
"children": []
}
文件字段解读:
- assets:编译产物列表
- chunks:构建过程生成的 chunks 列表,数组内容包含 chunk 名称、大小、依赖关系图
- modules:本次运行触达的所有模块,数组内容包含模块的大小、所属chunk、分析耗时、构建原因等
- entrypoints:entry 列表
- namedChunkGroups:chunks 的命名版本,内容相比于 chunks 会更精简
- errors:构建过程发生的所有错误信息
- warnings:构建过程发生的所有警告信息
可视化分析工具 Webpack Analysis
通过stats.json文件,生成模块、文件等分析视图
效果图:
体验地址:Webpack Analysis
在线分析工具 Webpack Visualizer/webpack-visualizer-plugin
通过把生成的stats.json文件拖入,就可以看到打包后的模块的引用关系
效果图:
Webpack Visualizer体验地址:webpack-visualizer
webpack-visualizer-plugin项目地址:github
包体积及依赖分析 Webpack Bundle Analyzer
构建后可以生成treemap形态的模块分布图
- 可以通过模块分布图查看相关js文件的大小
- 模块是否重复打包
- 不必要的模块是否打包进去(devtool、webpack-dev-server之类)
- ...
效果图:
使用方式:
webpack.dev.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
...,
plugins: [
new BundleAnalyzerPlugin()
]
}
项目地址:github
命令行可视化 webpack-dashboard
用于美化你的构建输出结果,包含执行耗时,依赖文件大小信息,执行状态等
效果图:
使用方式:
webpack.dev.config.js
const DashboardPlugin = require('webpack-dashboard/plugin')
module.exports = {
...,
plugins: [
new DashboardPlugin()
]
}
package.json
"script": {
"start": "webpack serve --open --config webpack.dev.config.js"
}
// 修改为
"script": {
"start": "webpack-dashboard -- webpack serve --open --config webpack.dev.config.js"
}
项目地址:github
构建完成通知 webpack-build-notifier
用于在构建完成时,给你推送完成信息,而不必等待构建结果
效果图:
使用方式:
webpack.dev.config.js
const WebpackBuildNotifierPlugin = require('webpack-build-notifier')
module.exports = {
...,
plugins: [
new WebpackBuildNotifierPlugin({
title: "成教端",
logo: path.resolve("./img/favicon.png"),
suppressSuccess: true
})
]
}
项目地址:github
构建进度条 progress-bar-webpack-plugin
用于展示构建进度的plugins
效果图:
使用方式:
webpack.dev.config.js
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
module.exports = {
...,
plugins: [
new ProgressBarPlugin()
]
}
项目地址:github
构建进度条 webpackbar
用于webpack构建进度及构建分析:
- 构建实时进度条
- 多并发构建
- 高级构建分析
- ...
效果图:
使用方式:
webpack.dev.config.js
const webpackbar = require('webpackbar')
module.exports = {
...,
plugins: [
new webpackbar()
]
}
项目地址:github
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!