Skip to content
Merged
74 changes: 38 additions & 36 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -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 */
Expand All @@ -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) {
Expand All @@ -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<T> | undefined} obj2
* @returns {T}
* @param {T} obj1 First object to merge.
* @param {Partial<T> | 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 {
Expand Down Expand Up @@ -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(
Expand All @@ -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));
Expand All @@ -102,13 +104,13 @@ class BundleTrackerPlugin {
/**
* Write bundle tracker stats file
*
* @param {Compiler} compiler
* @param {Compiler} _compiler
* @param {Partial<Contents>} 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) {
Expand Down Expand Up @@ -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']),
});

Expand All @@ -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),
Expand Down Expand Up @@ -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();
Expand Down
1 change: 0 additions & 1 deletion lib/utils/stripAnsi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)',
Expand Down
20 changes: 4 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 2 additions & 3 deletions tests/base.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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']);
Expand Down
4 changes: 1 addition & 3 deletions tests/fixtures/commons.js
Original file line number Diff line number Diff line change
@@ -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;
5 changes: 2 additions & 3 deletions tests/webpack5.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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']);
Expand Down