Skip to content

Commit

Permalink
feat: output duplicated pkg size
Browse files Browse the repository at this point in the history
  • Loading branch information
changfeng committed Jun 10, 2023
1 parent 847d19e commit 305aa29
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 9 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
},
"dependencies": {
"@rollup/pluginutils": "^5.0.2",
"axios": "^1.4.0",
"consola": "^3.1.0",
"picocolors": "^1.0.0",
"semver": "^7.5.1",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 39 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { RollupPlugin } from 'unplugin';
import { createUnplugin } from 'unplugin';
import { workspaceRoot } from 'workspace-root';

import { memoizeAsync } from './utils';
import { memoizeAsync, getPkgSize as _getPkgSize } from './utils';

export interface Options {}

Expand Down Expand Up @@ -58,6 +58,22 @@ const formatImporter = memoizeAsync(async (importer: string) => {
return formattedImporter;
});

const getPkgSize = memoizeAsync(_getPkgSize);

function colorizeSize(kb: number) {
if (Number.isNaN(kb)) return '';

let colorFunc: (str: string) => string;
if (kb > 1000) {
colorFunc = c.red;
} else if (kb > 100) {
colorFunc = c.yellow;
} else {
colorFunc = c.green;
}
return `(${colorFunc(`${kb}kb`)})`;
}

export default createUnplugin<Options | undefined>(() => {
const name = 'unplugin-detect-duplicated-deps';
let isVitePlugin = false;
Expand Down Expand Up @@ -103,7 +119,7 @@ export default createUnplugin<Options | undefined>(() => {
}
};

const buildEnd: RollupPlugin['buildEnd'] = function () {
const buildEnd: RollupPlugin['buildEnd'] = async function () {
const duplicatedPackages: string[] = [];
for (const [packageName, versionsMap] of packageToVersionsMap.entries()) {
if (versionsMap.size > 1) {
Expand All @@ -119,9 +135,7 @@ export default createUnplugin<Options | undefined>(() => {
`multiple versions of ${formattedDuplicatedPackageNames} is bundled!`,
];

for (const duplicatedPackage of duplicatedPackages) {
warningMessages.push(`\n ${c.magenta(duplicatedPackage)}:`);

const promises = duplicatedPackages.map(async (duplicatedPackage) => {
const sortedVersions = [...packageToVersionsMap.get(duplicatedPackage)!.keys()].sort(
(a, b) => (gt(a, b) ? 1 : -1),
);
Expand All @@ -133,7 +147,8 @@ export default createUnplugin<Options | undefined>(() => {
}
});

for (const version of sortedVersions) {
let totalSize = 0;
const _promises = sortedVersions.map(async (version) => {
const importers = Array.from(
packageToVersionsMap.get(duplicatedPackage)!.get(version)!,
);
Expand All @@ -144,9 +159,23 @@ export default createUnplugin<Options | undefined>(() => {
.filter((importer) => importer !== `${duplicatedPackage}@${version}`)
.map((name) => c.green(name))
.join(', ');
warningMessages.push(` - ${formattedVersion} imported by ${formattedImporters}`);
}
}
const pkgSize = await getPkgSize(duplicatedPackage, version);
totalSize += pkgSize;
warningMessages.push(
// prettier-ignore
` - ${formattedVersion}${colorizeSize(pkgSize)} imported by ${formattedImporters}`,
);
});
await Promise.all(_promises);

warningMessages.splice(
warningMessages.length - sortedVersions.length,
0,
`\n ${c.magenta(duplicatedPackage)}${colorizeSize(totalSize)}:`,
);
});
await Promise.all(promises);

// remove vite output dim colorize
// eslint-disable-next-line unicorn/escape-case, unicorn/no-hex-escape
process.stdout.write(`\x1b[0m${isVitePlugin ? '\n' : ''}`);
Expand All @@ -156,6 +185,7 @@ export default createUnplugin<Options | undefined>(() => {
getWorkspaceRootFolder.destroy();
getPackageInfo.destroy();
formatImporter.destroy();
getPkgSize.destroy();
};

return {
Expand Down
52 changes: 52 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import type { AxiosResponse } from 'axios';
import axios from 'axios';

export function memoizeAsync<F extends (...params: any[]) => Promise<any>>(f: F) {
const cache = new Map<Parameters<F>[0], Promise<Awaited<ReturnType<F>>>>();
const memoizedFuncName = `memoized ${f.name}`;
Expand Down Expand Up @@ -27,3 +30,52 @@ export function memoizeAsync<F extends (...params: any[]) => Promise<any>>(f: F)

return memoizedFunc;
}

export interface Asset {
gzip: number;
name: string;
size: number;
type: string;
}

export interface DependencySize {
approximateSize: number;
name: string;
}

export interface GetPkgSizeResponseData {
assets: Asset[];
dependencyCount: number;
dependencySizes: DependencySize[];
description: string;
gzip: number;
hasJSModule: boolean;
hasJSNext: boolean;
hasSideEffects: boolean;
isModuleType: boolean;
name: string;
repository: string;
scoped: boolean;
size?: number;
version: string;
}

export async function getPkgSize(name: string, version: string) {
let resp: AxiosResponse<GetPkgSizeResponseData>;
try {
resp = await axios.get<GetPkgSizeResponseData>(
`https://bundlephobia.com/api/size?package=${name}@${version}`,
{
timeout: 3000,
},
);
} catch {
return Number.NaN;
}

const bytes = resp.data.size;
if (typeof bytes !== 'number') return Number.NaN;

const kb = bytes / 1000;
return kb;
}

0 comments on commit 305aa29

Please sign in to comment.