diff --git a/lib/index.js b/lib/index.js index 5af916a..e98c5cd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,4 @@ // @ts-check -/** @typedef {import("lodash.defaults")} defaults */ -/** @typedef {import("lodash.assign")} assign */ /** @typedef {import("webpack").Compiler} Compiler */ /** @typedef {import("webpack").Stats} Stats */ /** @typedef {import("webpack").compilation.Compilation} Compilation */ @@ -13,11 +11,6 @@ const path = require('path'); const fs = require('fs'); const crypto = require('crypto'); -const defaults = require('lodash.defaults'); -const assign = require('lodash.assign'); -const each = require('lodash.foreach'); -const fromPairs = require('lodash.frompairs'); -const toPairs = require('lodash.topairs'); const stripAnsi = require('./utils/stripAnsi'); function getAssetPath(compilation, name) { @@ -32,16 +25,19 @@ function getSource(compilation, name) { /** * Merges the provided objects, ensuring that the resulting object has its properties in sorted order. * @template T - * @param {T} obj1 - * @param {Partial | undefined} obj2 - * @returns {T} + * @param {T} obj1 First object to merge. + * @param {Partial | undefined} obj2 Second object to merge, can be undefined. + * @returns {*} A new object containing the merged properties of obj1 and obj2, with keys sorted. */ -function mergeObjects(obj1, obj2) { - const mergedObj = assign({}, obj1, obj2); - const sortedPairs = toPairs(mergedObj).sort((e1, e2) => e1[0].localeCompare(e2[0])); - // @ts-ignore: 2322 The Lodash typedefs aren't smart enough to be able to tell TS that we're - // regenerating the object from the original key-value pairs. - return fromPairs(sortedPairs); +function mergeObjectsAndSortKeys(obj1, obj2) { + const mergedObj = Object.assign({}, obj1, obj2); + + // Generates a new object with the same keys and values as mergedObj but in sorted order + const sortedKeys = Object.keys(mergedObj).sort(); + return sortedKeys.reduce((acc, key) => { + acc[key] = mergedObj[key]; + return acc; + }, {}); } class BundleTrackerPlugin { @@ -70,17 +66,21 @@ class BundleTrackerPlugin { * @returns this */ _setParamsFromCompiler(compiler) { - this.options = defaults({}, this.options, { - path: compiler.options.output?.path ?? process.cwd(), - publicPath: compiler.options.output?.publicPath ?? '', - filename: 'webpack-stats.json', - logTime: false, - relativePath: false, - integrity: false, - indent: 2, - // https://www.w3.org/TR/SRI/#cryptographic-hash-functions - integrityHashes: ['sha256', 'sha384', 'sha512'], - }); + this.options = Object.assign( + {}, + { + path: compiler.options.output?.path ?? process.cwd(), + publicPath: compiler.options.output?.publicPath ?? '', + filename: 'webpack-stats.json', + logTime: false, + relativePath: false, + integrity: false, + indent: 2, + // https://www.w3.org/TR/SRI/#cryptographic-hash-functions + integrityHashes: ['sha256', 'sha384', 'sha512'], + }, + this.options, + ); if (this.options.filename?.includes('/')) { throw Error( @@ -91,7 +91,9 @@ class BundleTrackerPlugin { } // Set output directories - this.outputChunkDir = path.resolve(compiler.options.output?.path ?? process.cwd()); + const outputPath = compiler.options.output?.path ?? process.cwd(); + this.outputChunkDir = path.resolve(outputPath); + // @ts-ignore: TS2345 this.options.path can't be undefined here because we set a default value above // @ts-ignore: TS2345 this.options.filename can't be undefined here because we set a default value above this.outputTrackerFile = path.resolve(path.join(this.options.path, this.options.filename)); @@ -102,13 +104,13 @@ class BundleTrackerPlugin { /** * Write bundle tracker stats file * - * @param {Compiler} compiler + * @param {Compiler} _compiler * @param {Partial} contents */ - _writeOutput(compiler, contents) { - assign(this.contents, contents, { - assets: mergeObjects(this.contents.assets, contents.assets), - chunks: mergeObjects(this.contents.chunks, contents.chunks), + _writeOutput(_compiler, contents) { + Object.assign(this.contents, contents, { + assets: mergeObjectsAndSortKeys(this.contents.assets, contents.assets), + chunks: mergeObjectsAndSortKeys(this.contents.chunks, contents.chunks), }); if (this.options.publicPath) { @@ -159,7 +161,7 @@ class BundleTrackerPlugin { const error = findError(stats.compilation); this._writeOutput(compiler, { status: 'error', - error: error.name ?? 'unknown-error', + error: error?.name ?? 'unknown-error', message: stripAnsi(error['message']), }); @@ -168,7 +170,7 @@ class BundleTrackerPlugin { /** @type {Contents} */ const output = { status: 'done', assets: {}, chunks: {} }; - each(stats.compilation.assets, (file, assetName) => { + Object.entries(stats.compilation.assets).map(([assetName, _]) => { const fileInfo = { name: assetName, path: getAssetPath(stats.compilation, assetName), @@ -198,7 +200,7 @@ class BundleTrackerPlugin { output.assets[assetName] = fileInfo; }); - each(stats.compilation.chunkGroups, chunkGroup => { + stats.compilation.chunkGroups.forEach(chunkGroup => { if (!chunkGroup.isInitial()) return; output.chunks[chunkGroup.name] = chunkGroup.getFiles(); diff --git a/lib/utils/stripAnsi.js b/lib/utils/stripAnsi.js index a301b8c..a11ad99 100644 --- a/lib/utils/stripAnsi.js +++ b/lib/utils/stripAnsi.js @@ -2,7 +2,6 @@ * This code is based on the strip-ansi library by Chalk. * Source: https://github.com/chalk/strip-ansi */ - function ansiRegex({ onlyFirst = false } = {}) { const pattern = [ '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', diff --git a/package.json b/package.json index 9a7326e..f2eec14 100644 --- a/package.json +++ b/package.json @@ -27,38 +27,26 @@ "pretty": "prettier --loglevel warn --write lib/*.js tests/*.js", "pretty-lint": "prettier --check lib/*.js tests/*.js", "pretest": "npm run pretty-lint", - "test": "NODE_OPTIONS=--openssl-legacy-provider jest --runInBand --env node", - "test-debug": "NODE_OPTIONS=--openssl-legacy-provider node --inspect-brk=0.0.0.0 node_modules/jest/bin/jest --runInBand --env node", + "test": "cross-env NODE_OPTIONS=--openssl-legacy-provider jest --runInBand --env node", + "test-debug": "cross-env NODE_OPTIONS=--openssl-legacy-provider node --inspect-brk=0.0.0.0 node_modules/jest/bin/jest --runInBand --env node", "posttest": "tsc", "test-watch": "jest --runInBand --env node --watchAll", - "ci": "NODE_OPTIONS=--openssl-legacy-provider npm run pretest && jest --runInBand --coverage --env node && npm run posttest" + "ci": "cross-env NODE_OPTIONS=--openssl-legacy-provider npm run pretest && jest --runInBand --coverage --env node && npm run posttest" }, "jest": { "setupFilesAfterEnv": [ "jest-extended" ] }, - "dependencies": { - "lodash.assign": "^4.2.0", - "lodash.defaults": "^4.2.0", - "lodash.foreach": "^4.5.0", - "lodash.frompairs": "^4.0.1", - "lodash.topairs": "^4.3.0" - }, "devDependencies": { "@types/babel__traverse": "7.0.6", - "@types/lodash": "4.14.173", - "@types/lodash.assign": "^4.2.7", - "@types/lodash.defaults": "^4.2.7", - "@types/lodash.foreach": "^4.5.7", - "@types/lodash.frompairs": "^4.0.7", - "@types/lodash.topairs": "^4.3.7", "@types/node": "^13.13.52", "@types/webpack": "^4.41.33", "@typescript-eslint/eslint-plugin": "^2.34.0", "@typescript-eslint/parser": "^2.34.0", "commitizen": "^4.3.0", "compression-webpack-plugin": "^6.1.1", + "cross-env": "^7.0.3", "css-loader": "^5.2.7", "cz-conventional-changelog": "3.3.0", "eslint": "^6.8.0", diff --git a/tests/base.test.js b/tests/base.test.js index bfc7f27..0ed9c4b 100644 --- a/tests/base.test.js +++ b/tests/base.test.js @@ -2,7 +2,6 @@ 'use strict'; const fs = require('fs'); -const toPairs = require('lodash.topairs'); const zlib = require('zlib'); const path = require('path'); const rimraf = require('rimraf'); @@ -761,8 +760,8 @@ describe('BundleTrackerPlugin bases tests', () => { () => { const statsStr = fs.readFileSync(path.join(OUTPUT_DIR, 'webpack-stats.json'), 'utf8'); const stats = JSON.parse(statsStr); - const assetsKeys = toPairs(stats.assets).map(pair => pair[0]); - const chunksKeys = toPairs(stats.chunks).map(pair => pair[0]); + const assetsKeys = Object.entries(stats.assets).map(pair => pair[0]); + const chunksKeys = Object.entries(stats.chunks).map(pair => pair[0]); expect(assetsKeys).toEqual(['css/appA.css', 'js/1.js', 'js/appA.js', 'js/appZ.js', 'js/commons.js']); expect(chunksKeys).toEqual(['appA', 'appZ']); diff --git a/tests/fixtures/commons.js b/tests/fixtures/commons.js index 9485d2c..f13dd3d 100644 --- a/tests/fixtures/commons.js +++ b/tests/fixtures/commons.js @@ -1,9 +1,7 @@ 'use strict'; -const assign = require('lodash.assign'); - const output = { name: '' }; -assign(output, { name: 'common' }); +Object.assign(output, { name: 'common' }); module.exports = output; diff --git a/tests/webpack5.test.js b/tests/webpack5.test.js index e4870a0..3c1fe3b 100644 --- a/tests/webpack5.test.js +++ b/tests/webpack5.test.js @@ -2,7 +2,6 @@ 'use strict'; const fs = require('fs'); -const toPairs = require('lodash.topairs'); const zlib = require('zlib'); const path = require('path'); const rimraf = require('rimraf'); @@ -807,8 +806,8 @@ describe('BundleTrackerPlugin bases tests', () => { () => { const statsStr = fs.readFileSync(path.join(OUTPUT_DIR, 'webpack-stats.json'), 'utf8'); const stats = JSON.parse(statsStr); - const assetsKeys = toPairs(stats.assets).map(pair => pair[0]); - const chunksKeys = toPairs(stats.chunks).map(pair => pair[0]); + const assetsKeys = Object.entries(stats.assets).map(pair => pair[0]); + const chunksKeys = Object.entries(stats.chunks).map(pair => pair[0]); expect(assetsKeys).toEqual(['css/appA.css', 'js/75.js', 'js/appA.js', 'js/appZ.js', 'js/commons.js']); expect(chunksKeys).toEqual(['appA', 'appZ']);