寻找项目中未使用资源 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)
You 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
|
| ReactDOM.render(
> <ConfigProvider locale={zhCN}>
| <Provider store={store}>
| <App />",
"moduleId": 138,
"moduleTrace": [],
"stack": "ModuleParseError: Module parse failed: Unexpected token (32:2)
You 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
|
| ReactDOM.render(
> <ConfigProvider locale={zhCN}>
| <Provider store={store}>
| <App />
at handleParseError (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:923:19)
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:1025:5
at processResult (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:745:11)
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/NormalModule.js:809:5
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/loader-runner/lib/LoaderRunner.js:406:3
at iterateNormalLoaders (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/loader-runner/lib/LoaderRunner.js:232:10)
at Array.<anonymous> (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/loader-runner/lib/LoaderRunner.js:223:4)
at runCallbacks (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:27:15)
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:200:4
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/graceful-fs/graceful-fs.js:123:16"
}
],
"errorsCount": 1,
"warnings": [
{
"message": "configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/",
"stack": "NoModeWarning: configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/WarnNoModeSetPlugin.js:20:30
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)
at Hook.CALL_DELEGATE [as _call] (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/tapable/lib/Hook.js:14:14)
at Compiler.newCompilation (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:1033:30)
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:1076:29
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)
at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/tapable/lib/Hook.js:18:14)
at Compiler.compile (/Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:1071:28)
at /Users/xcc/Documents/xcc/tl/app/aep/node_modules/webpack/lib/Compiler.js:498:12
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