From f01056a51fa16f3274204b5b98bba1be3a3f496d Mon Sep 17 00:00:00 2001 From: Sukka Date: Wed, 13 Sep 2023 21:46:44 +0800 Subject: [PATCH] Replace all `lodash.*` packages (#612) * Replace `lodash.escape` w/ `html-escaper` * Replace `lodash.flatten` with a small function * Repalce `lodash.debounce` w/ `debounce` * Replace `lodash.pullall` w/ Array.prototype.filter * Chore: add a TODO comment for debounce package replacement * Replace `lodash.uniqby` w/ Set+filter * Replace `lodash.invokemap` w/ Object.values * Fix invokemap replacement * Update CHANGELOG --- CHANGELOG.md | 3 ++ client/components/ModuleItem.jsx | 2 +- client/components/Search.jsx | 3 +- package-lock.json | 36 ++++------------- package.json | 9 ++--- src/analyzer.js | 68 ++++++++++++++++++++++++-------- src/template.js | 2 +- src/tree/BaseFolder.js | 4 +- src/tree/ConcatenatedModule.js | 9 +++-- 9 files changed, 76 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8963aa4a..b86d4e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ _Note: Gaps between patch versions are faulty, broken or test releases._ ## UNRELEASED +* **Internal** + * Make module much slimmer by replacing all `lodash.*` packages ([#612](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/612)) by [@sukkaw](https://github.com/sukkaw). + ## 4.9.1 * **Internal** diff --git a/client/components/ModuleItem.jsx b/client/components/ModuleItem.jsx index 5e54bb24..efd617ec 100644 --- a/client/components/ModuleItem.jsx +++ b/client/components/ModuleItem.jsx @@ -1,5 +1,5 @@ import escapeRegExp from 'escape-string-regexp'; -import escape from 'lodash.escape'; +import {escape} from 'html-escaper'; import filesize from 'filesize'; import cls from 'classnames'; diff --git a/client/components/Search.jsx b/client/components/Search.jsx index e4ef1c8d..6c6cc1bb 100644 --- a/client/components/Search.jsx +++ b/client/components/Search.jsx @@ -1,4 +1,5 @@ -import debounce from 'lodash.debounce'; +// TODO: switch to a more modern debounce package once we drop Node.js 10 support +import debounce from 'debounce'; import s from './Search.css'; import Button from './Button'; diff --git a/package-lock.json b/package-lock.json index 55760b89..bd8cce2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3979,6 +3979,11 @@ "whatwg-url": "^8.0.0" } }, + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -6142,8 +6147,7 @@ "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" }, "http-deceiver": { "version": "1.2.7", @@ -8102,22 +8106,8 @@ "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "lodash.escape": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", - "integrity": "sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==" - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" - }, - "lodash.invokemap": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz", - "integrity": "sha512-CfkycNtMqgUlfjfdh2BhKO/ZXrP8ePOX5lEU/g0R3ItJcnuxWDwokMGKx1hWcfOikmyOVx6X9IwWnDGlgKl61w==" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true }, "lodash.memoize": { "version": "4.1.2", @@ -8137,22 +8127,12 @@ "integrity": "sha512-qsiGr0kiA31O7chhmKSUiEGtxXnYtwmaJF00TPAUW79C5PCfaVeLTUN3sLT+rEPcqZooPtiFcGhnphQzFhkqmg==", "dev": true }, - "lodash.pullall": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.pullall/-/lodash.pullall-4.2.0.tgz", - "integrity": "sha512-VhqxBKH0ZxPpLhiu68YD1KnHmbhQJQctcipvmFnqIBDYzcIHzf3Zpu0tpeOKtR4x76p9yohc506eGdOjTmyIBg==" - }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true }, - "lodash.uniqby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", - "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==" - }, "loglevel": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", diff --git a/package.json b/package.json index 4f76bcb1..99f9414a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "engines": { "node": ">= 10.13.0" }, + "packageManager": "npm@6.14.8", "scripts": { "start": "gulp watch", "build": "gulp build", @@ -36,15 +37,11 @@ "acorn": "^8.0.4", "acorn-walk": "^8.0.0", "commander": "^7.2.0", + "debounce": "^1.2.1", "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", "is-plain-object": "^5.0.0", - "lodash.debounce": "^4.0.8", - "lodash.escape": "^4.0.1", - "lodash.flatten": "^4.4.0", - "lodash.invokemap": "^4.6.0", - "lodash.pullall": "^4.2.0", - "lodash.uniqby": "^4.7.0", "opener": "^1.5.2", "picocolors": "^1.0.0", "sirv": "^2.0.3", diff --git a/src/analyzer.js b/src/analyzer.js index 175b694d..323e1777 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -1,11 +1,6 @@ const fs = require('fs'); const path = require('path'); -const pullAll = require('lodash.pullall'); -const invokeMap = require('lodash.invokemap'); -const uniqBy = require('lodash.uniqby'); -const flatten = require('lodash.flatten'); - const gzipSize = require('gzip-size'); const {parseChunked} = require('@discoveryjs/json-ext'); @@ -119,7 +114,7 @@ function getViewerData(bundleStats, bundleDir, opts) { } // Picking modules from current bundle script - const assetModules = modules.filter(statModule => assetHasModule(statAsset, statModule)); + let assetModules = modules.filter(statModule => assetHasModule(statAsset, statModule)); // Adding parsed sources if (parsedModules) { @@ -143,7 +138,7 @@ function getViewerData(bundleStats, bundleDir, opts) { unparsedEntryModules[0].parsedSrc = assetSources.runtimeSrc; } else { // If there are multiple entry points we move all of them under synthetic concatenated module. - pullAll(assetModules, unparsedEntryModules); + assetModules = assetModules.filter(mod => !unparsedEntryModules.includes(mod)); assetModules.unshift({ identifier: './entry modules', name: './entry modules', @@ -171,7 +166,7 @@ function getViewerData(bundleStats, bundleDir, opts) { statSize: asset.tree.size || asset.size, parsedSize: asset.parsedSize, gzipSize: asset.gzipSize, - groups: invokeMap(asset.tree.children, 'toChartData'), + groups: Object.values(asset.tree.children).map(i => i.toChartData()), isInitialByEntrypoint: chunkToInitialByEntrypoint[filename] ?? {} })); } @@ -191,15 +186,23 @@ function getChildAssetBundles(bundleStats, assetName) { } function getBundleModules(bundleStats) { - return uniqBy( - flatten( - ((bundleStats.chunks?.map(chunk => chunk.modules)) || []) - .concat(bundleStats.modules) - .filter(Boolean) - ), - 'id' - // Filtering out Webpack's runtime modules as they don't have ids and can't be parsed (introduced in Webpack 5) - ).filter(m => !isRuntimeModule(m)); + const seenIds = new Set(); + + return flatten( + ((bundleStats.chunks?.map(chunk => chunk.modules)) || []) + .concat(bundleStats.modules) + .filter(Boolean) + ).filter(mod => { + // Filtering out Webpack's runtime modules as they don't have ids and can't be parsed (introduced in Webpack 5) + if (isRuntimeModule(mod)) { + return false; + } + if (seenIds.has(mod.id)) { + return false; + } + seenIds.add(mod.id); + return true; + }); } function assetHasModule(statAsset, statModule) { @@ -239,3 +242,34 @@ function getChunkToInitialByEntrypoint(bundleStats) { }); return chunkToEntrypointInititalMap; }; + +/** + * arr-flatten + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + * + * Modified by Sukka + * + * Replace recursively flatten with one-level deep flatten to match lodash.flatten + * + * TODO: replace with Array.prototype.flat once Node.js 10 support is dropped + */ +function flatten(arr) { + if (!arr) return []; + const len = arr.length; + if (!len) return []; + + let cur; + + const res = []; + for (let i = 0; i < len; i++) { + cur = arr[i]; + if (Array.isArray(cur)) { + res.push(...cur); + } else { + res.push(cur); + } + } + return res; +} diff --git a/src/template.js b/src/template.js index a14c3b4f..dec70ef7 100644 --- a/src/template.js +++ b/src/template.js @@ -2,7 +2,7 @@ const path = require('path'); const fs = require('fs'); -const escape = require('lodash.escape'); +const {escape} = require('html-escaper'); const projectRoot = path.resolve(__dirname, '..'); const assetsRoot = path.join(projectRoot, 'public'); diff --git a/src/tree/BaseFolder.js b/src/tree/BaseFolder.js index 73eb7118..f9c138ae 100644 --- a/src/tree/BaseFolder.js +++ b/src/tree/BaseFolder.js @@ -1,5 +1,3 @@ -import invokeMap from 'lodash.invokemap'; - import Node from './Node'; export default class BaseFolder extends Node { @@ -111,7 +109,7 @@ export default class BaseFolder extends Node { label: this.name, path: this.path, statSize: this.size, - groups: invokeMap(this.children, 'toChartData') + groups: Object.values(this.children).map(child => child.toChartData()) }; } diff --git a/src/tree/ConcatenatedModule.js b/src/tree/ConcatenatedModule.js index c53711d8..b1788ade 100644 --- a/src/tree/ConcatenatedModule.js +++ b/src/tree/ConcatenatedModule.js @@ -1,4 +1,3 @@ -import invokeMap from 'lodash.invokemap'; import Module from './Module'; import ContentModule from './ContentModule'; import ContentFolder from './ContentFolder'; @@ -74,14 +73,18 @@ export default class ConcatenatedModule extends Module { } mergeNestedFolders() { - invokeMap(this.children, 'mergeNestedFolders'); + Object.values(this.children).forEach(child => { + if (child.mergeNestedFolders) { + child.mergeNestedFolders(); + } + }); } toChartData() { return { ...super.toChartData(), concatenated: true, - groups: invokeMap(this.children, 'toChartData') + groups: Object.values(this.children).map(child => child.toChartData()) }; }