Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement reduced size estimation #13

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion create.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,42 @@ const manualPackagesList = /** @type {const} */ ([
'globalthis' // globalthis package's entrypoint is a function, not the implementation
]);

const https = require('https');

/**
* Makes an asynchronous HTTPS request with search params.
*
* @param {string} url - The request URL.
* @param {Object} [params={}] - The search parameters as a JSON object.
* @returns {Promise<Object>} The response JSON.
*/
async function makeRequest(url, params = {}) {
const urlObj = new URL(url);
Object.entries(params).forEach(([key, value]) => {
urlObj.searchParams.append(key, value);
});

return new Promise((resolve, reject) => {
https.get(urlObj.toString(), (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});

res.on('end', () => {
try {
const response = JSON.parse(data);
resolve(response);
} catch (error) {
reject(error);
}
});
}).on('error', (error) => {
reject(error);
});
});
}

(async () => {
await Promise.all([
...autoGeneratedPackagesList.map(pkg => createEsShimLikePackage(pkg[0], pkg[1], pkg[2], pkg[3], pkg[4], pkg[5])),
Expand Down Expand Up @@ -425,9 +461,29 @@ const manualPackagesList = /** @type {const} */ ([
}
};

const fetchOriginPackageSize = async (packageName) => {
const packageJson = await makeRequest('https://packagephobia.com/api.json', {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use registry.npmjs.org instead? registry.npmjs.org is way more reliable.

E.g. You can get unpackedSize and fileCount from https://registry.npmjs.org/nolyfill/latest.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible but only if the dependency tree is evaluated correctly. The tree of yarn is incorrect currently, however.

Check the discussions in the tg group for details.

p: packageName
});
return [packageName, {
publish: packageJson.publishSize,
install: packageJson.installSize
}];
};

const packageSize = [];
const parallel = 8;
for (let packageIndex = 0; packageIndex < allPackages.length; packageIndex += parallel) {
const packageNames = Array.from(new Array(parallel))
.map((_, i) => allPackages[packageIndex + i])
.filter(Boolean);
console.log(`Fetching package size (${Math.floor(packageIndex / parallel)}/${allPackages.length / parallel}): ${packageNames.join(', ')}`);
// eslint-disable-next-line no-await-in-loop -- this is intended to avoid sending too many requests at the same time
packageSize.push(...await Promise.all(packageNames.map(fetchOriginPackageSize)));
}
const cliAllPackagesTs = `/* Generated by create.cjs */
/* eslint-disable */
export const allPackages = ${JSON.stringify(allPackages, null, 2)};\n`;
export const allPackages = ${JSON.stringify(allPackages, null, 2)};\nexport const packageSize: Record<string, { publish: number, install: number }> = ${JSON.stringify(Object.fromEntries(packageSize), null, 2)};`;

await Promise.all([
compareAndWriteFile(
Expand Down
258 changes: 258 additions & 0 deletions packages/cli/src/all-packages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,261 @@ export const allPackages = [
"which-boxed-primitive",
"which-typed-array"
];
export const packageSize: Record<string, { publish: number, install: number }> = {
"array-buffer-byte-length": {
"publish": 8053,
"install": 222826
},
"array-includes": {
"publish": 24990,
"install": 3316588
},
"array.from": {
"publish": 31895,
"install": 3691890
},
"array.prototype.find": {
"publish": 16372,
"install": 3686390
},
"array.prototype.findlastindex": {
"publish": 28212,
"install": 4221571
},
"array.prototype.flat": {
"publish": 18207,
"install": 3319828
},
"array.prototype.flatmap": {
"publish": 18571,
"install": 3651934
},
"array.prototype.reduce": {
"publish": 29140,
"install": 3692996
},
"array.prototype.tosorted": {
"publish": 18100,
"install": 3688118
},
"arraybuffer.prototype.slice": {
"publish": 18815,
"install": 334799
},
"asynciterator.prototype": {
"publish": 7228,
"install": 27831
},
"available-typed-arrays": {
"publish": 15180,
"install": 15180
},
"deep-equal": {
"publish": 82799,
"install": 2084616
},
"define-properties": {
"publish": 12453,
"install": 143312
},
"es-aggregate-error": {
"publish": 25733,
"install": 3685728
},
"es-iterator-helpers": {
"publish": 150727,
"install": 4518765
},
"es-set-tostringtag": {
"publish": 8908,
"install": 105450
},
"function-bind": {
"publish": 26022,
"install": 26022
},
"function.prototype.name": {
"publish": 18245,
"install": 1872828
},
"get-symbol-description": {
"publish": 11291,
"install": 109472
},
"globalthis": {
"publish": 23503,
"install": 157970
},
"gopd": {
"publish": 7703,
"install": 93358
},
"harmony-reflect": {
"publish": 89584,
"install": 89584
},
"has": {
"publish": 3481,
"install": 29538
},
"has-property-descriptors": {
"publish": 9308,
"install": 94963
},
"has-proto": {
"publish": 7195,
"install": 7195
},
"has-symbols": {
"publish": 21570,
"install": 21570
},
"has-tostringtag": {
"publish": 11842,
"install": 31062
},
"is-array-buffer": {
"publish": 11882,
"install": 214773
},
"is-date-object": {
"publish": 21914,
"install": 53033
},
"is-regex": {
"publish": 31065,
"install": 141085
},
"is-shared-array-buffer": {
"publish": 11886,
"install": 121641
},
"is-string": {
"publish": 20203,
"install": 51312
},
"is-symbol": {
"publish": 23028,
"install": 42236
},
"is-weakref": {
"publish": 12967,
"install": 111080
},
"iterator.prototype": {
"publish": 9111,
"install": 4360810
},
"object-keys": {
"publish": 27637,
"install": 27637
},
"object.assign": {
"publish": 1166150,
"install": 1312309
},
"object.entries": {
"publish": 30974,
"install": 3322572
},
"object.fromentries": {
"publish": 15109,
"install": 3675104
},
"object.getownpropertydescriptors": {
"publish": 21419,
"install": 3729139
},
"object.groupby": {
"publish": 20252,
"install": 4203588
},
"object.hasown": {
"publish": 15673,
"install": 3675668
},
"object.values": {
"publish": 30470,
"install": 3322068
},
"promise.any": {
"publish": 21812,
"install": 3831524
},
"reflect.getprototypeof": {
"publish": 19551,
"install": 3832438
},
"regexp.prototype.flags": {
"publish": 38482,
"install": 205468
},
"safe-array-concat": {
"publish": 11294,
"install": 124479
},
"safe-regex-test": {
"publish": 7332,
"install": 148746
},
"string.prototype.matchall": {
"publish": 35918,
"install": 3656612
},
"string.prototype.padend": {
"publish": 16471,
"install": 3674089
},
"string.prototype.padstart": {
"publish": 16773,
"install": 3676768
},
"string.prototype.trim": {
"publish": 31730,
"install": 3659995
},
"string.prototype.trimend": {
"publish": 21205,
"install": 3624137
},
"string.prototype.trimleft": {
"publish": 19289,
"install": 187724
},
"string.prototype.trimright": {
"publish": 19355,
"install": 189340
},
"string.prototype.trimstart": {
"publish": 21444,
"install": 3659995
},
"typed-array-buffer": {
"publish": 7944,
"install": 243802
},
"typed-array-byte-length": {
"publish": 13711,
"install": 249569
},
"typed-array-byte-offset": {
"publish": 13716,
"install": 249574
},
"typed-array-length": {
"publish": 18520,
"install": 212059
},
"unbox-primitive": {
"publish": 14851,
"install": 253761
},
"which-boxed-primitive": {
"publish": 16035,
"install": 215373
},
"which-typed-array": {
"publish": 33757,
"install": 218214
}
};
35 changes: 35 additions & 0 deletions packages/cli/src/calc-reduced-size.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { packageSize } from './all-packages';
import type { PackageNode } from './types';
import picocolors from 'picocolors';

function formatBytes(bytes: number): string {
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let index = 0;

while (bytes >= 1024 && index < units.length - 1) {
bytes /= 1024;
index++;
}

return `${bytes.toFixed(2)} ${units[index]}`;
}

const calcReducedSize = (packageList: PackageNode[]) => {
let totalSizeInstall = 0;
let totalSizePublish = 0;

for (const { name } of packageList) {
totalSizeInstall += packageSize[name].install;
totalSizePublish += packageSize[name].publish;
}

return { totalSizeInstall, totalSizePublish };
};

export const genReducedSizeMessage = (packageList: PackageNode[], { willReduce = false }: { willReduce?: boolean } = {}) => {
const { totalSizeInstall, totalSizePublish } = calcReducedSize(packageList);
const formatReducedSize = (size: number) => picocolors.bold(picocolors.bgBlack(picocolors.white(formatBytes(size))));

return `Nolyfill ${willReduce ? 'will reduce' : 'have reduced'} ${formatReducedSize(totalSizeInstall)} on your disk and ${formatReducedSize(totalSizePublish)} for your users!
${picocolors.gray('Note that the size reduction is only an estimate, the actual size reduction may vary.')}`;
};
4 changes: 3 additions & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { overridesPackageJson } from './json';
import type { PKG } from './types';
import { handleSigTerm } from './handle-sigterm';
import { findPackagesCoveredByNolyfill } from './find-coverable-packages';
import { genReducedSizeMessage } from './calc-reduced-size';

interface CliOptions {
/** see full error messages, mostly for debugging */
Expand Down Expand Up @@ -88,6 +89,7 @@ const program = new Command('nolyfill');
console.log(renderTree(packagesToBeOverride));

console.log(`Run "${picocolors.bold(picocolors.green('nolyfill install'))}" to replace them with a super lightweight ✨ version.\n`);
console.log(genReducedSizeMessage(packagesToBeOverride, { willReduce: true }));
}
});

Expand All @@ -113,7 +115,7 @@ const program = new Command('nolyfill');
console.log(renderTree(packagesToBeOverride));

await overridesPackageJson(packageManager, projectPath, packagesToBeOverride);

console.log(genReducedSizeMessage(packagesToBeOverride));
printPostInstallInstructions(packageManager);
}
});
Expand Down