xccjk / x-blog

学习笔记
18 stars 2 forks source link

webpack常用开发体验/分析相关工具 #63

Closed xccjk closed 1 year ago

xccjk commented 3 years ago

寻找项目中未使用资源 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": []
}

文件字段解读:

可视化分析工具 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形态的模块分布图

效果图:

使用方式:

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