package-build-stats 8.0.2 → 8.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -46,16 +46,31 @@ async function getAllPackageExports(packageString, options = {}) {
46
46
  }
47
47
  async function getPackageExportSizes(packageString, options = {}) {
48
48
  const startTime = perf_hooks_1.performance.now();
49
+ const timings = {};
49
50
  const { name: packageName, normalPath } = (0, common_utils_1.parsePackageString)(packageString);
51
+ const preparePathStart = perf_hooks_1.performance.now();
50
52
  const installPath = await installation_utils_1.default.preparePath(packageName);
53
+ timings.preparePath = perf_hooks_1.performance.now() - preparePathStart;
54
+ console.log(`[PERF] [ExportSizes] preparePath: ${timings.preparePath.toFixed(2)}ms`);
51
55
  try {
56
+ const installStart = perf_hooks_1.performance.now();
52
57
  await installPackage(packageString, installPath, options);
58
+ timings.install = perf_hooks_1.performance.now() - installStart;
59
+ console.log(`[PERF] [ExportSizes] installPackage: ${timings.install.toFixed(2)}ms`);
53
60
  // The package is installed in node_modules subdirectory
54
61
  const packagePath = normalPath || path_1.default.join(installPath, 'node_modules', packageName);
62
+ const getAllExportsStart = perf_hooks_1.performance.now();
55
63
  const exportMap = await (0, exports_utils_1.getAllExports)(packageString, packagePath, packageName, installPath);
64
+ timings.getAllExports = perf_hooks_1.performance.now() - getAllExportsStart;
65
+ console.log(`[PERF] [ExportSizes] getAllExports: ${timings.getAllExports.toFixed(2)}ms`);
56
66
  const exports = Object.keys(exportMap).filter(exp => !(exp === 'default'));
57
67
  debug('Got %d exports for %s', exports.length, packageString);
68
+ console.log(`[PERF] [ExportSizes] Found ${exports.length} exports`);
69
+ const externalsStart = perf_hooks_1.performance.now();
58
70
  const externals = (0, common_utils_1.getExternals)(packageName, installPath);
71
+ timings.getExternals = perf_hooks_1.performance.now() - externalsStart;
72
+ console.log(`[PERF] [ExportSizes] getExternals: ${timings.getExternals.toFixed(2)}ms`);
73
+ const buildStart = perf_hooks_1.performance.now();
59
74
  const builtDetails = await build_utils_1.default.buildPackageIgnoringMissingDeps({
60
75
  name: packageName,
61
76
  installPath,
@@ -66,6 +81,8 @@ async function getPackageExportSizes(packageString, options = {}) {
66
81
  includeDependencySizes: false,
67
82
  },
68
83
  });
84
+ timings.build = perf_hooks_1.performance.now() - buildStart;
85
+ console.log(`[PERF] [ExportSizes] buildPackage: ${timings.build.toFixed(2)}ms`);
69
86
  telemetry_utils_1.default.packageExportsSizes(packageString, startTime, true, options);
70
87
  return {
71
88
  ...builtDetails,
@@ -40,9 +40,14 @@ function getPackageJSONDetails(packageName, installPath) {
40
40
  }
41
41
  async function getPackageStats(packageString, options = {}) {
42
42
  const startTime = perf_hooks_1.performance.now();
43
+ const timings = {};
43
44
  const { name: packageName, isLocal } = (0, common_utils_1.parsePackageString)(packageString);
45
+ const preparePathStart = perf_hooks_1.performance.now();
44
46
  const installPath = await installation_utils_1.default.preparePath(packageName, options.client);
47
+ timings.preparePath = perf_hooks_1.performance.now() - preparePathStart;
48
+ console.log(`[PERF] preparePath: ${timings.preparePath.toFixed(2)}ms`);
45
49
  try {
50
+ const installStart = perf_hooks_1.performance.now();
46
51
  await installation_utils_1.default.installPackage(packageString, installPath, {
47
52
  isLocal,
48
53
  client: options.client,
@@ -50,7 +55,13 @@ async function getPackageStats(packageString, options = {}) {
50
55
  networkConcurrency: options.networkConcurrency,
51
56
  installTimeout: options.installTimeout,
52
57
  });
58
+ timings.install = perf_hooks_1.performance.now() - installStart;
59
+ console.log(`[PERF] installPackage: ${timings.install.toFixed(2)}ms`);
60
+ const externalsStart = perf_hooks_1.performance.now();
53
61
  const externals = (0, common_utils_1.getExternals)(packageName, installPath);
62
+ timings.getExternals = perf_hooks_1.performance.now() - externalsStart;
63
+ console.log(`[PERF] getExternals: ${timings.getExternals.toFixed(2)}ms`);
64
+ const parallelStart = perf_hooks_1.performance.now();
54
65
  const [pacakgeJSONDetails, builtDetails] = await Promise.all([
55
66
  getPackageJSONDetails(packageName, installPath),
56
67
  build_utils_1.default.buildPackageIgnoringMissingDeps({
@@ -65,6 +76,8 @@ async function getPackageStats(packageString, options = {}) {
65
76
  },
66
77
  }),
67
78
  ]);
79
+ timings.parallelBuild = perf_hooks_1.performance.now() - parallelStart;
80
+ console.log(`[PERF] parallel (packageJSON + build): ${timings.parallelBuild.toFixed(2)}ms`);
68
81
  const hasCSSAsset = builtDetails.assets.some(asset => asset.type === 'css');
69
82
  const mainAsset = builtDetails.assets.find(asset => asset.name === 'main' && asset.type === (hasCSSAsset ? 'css' : 'js'));
70
83
  if (!mainAsset) {
@@ -18,9 +18,13 @@ const promises_1 = __importDefault(require("fs/promises"));
18
18
  const telemetry_utils_1 = __importDefault(require("./telemetry.utils"));
19
19
  const perf_hooks_1 = require("perf_hooks");
20
20
  // Initialize resolver with ESM-first configuration
21
- // Following oxc-linter's resolver configuration:
22
21
  // - main_fields: ["module", "main"] - prioritize ESM entry points
23
- // - condition_names: ["module", "import"] - standard ESM export conditions
22
+ // - condition_names: ["import", "default", "require"] - ESM-first export conditions
23
+ // NOTE: We intentionally exclude "node" because Node.js conditional exports resolution
24
+ // uses the PACKAGE's exports field order (not our conditionNames order) to determine
25
+ // priority. Packages like Vue have "node" before "import" in their exports, so including
26
+ // "node" would resolve to CJS files instead of ESM. We keep "require" as a fallback for
27
+ // packages that only export via "require" condition.
24
28
  // - extensions: all common JS/TS extensions
25
29
  // - symlinks: false - keep paths as-is without resolving symlinks (matches enhanced-resolve behavior)
26
30
  const resolver = new oxc_resolver_1.ResolverFactory({
@@ -35,8 +39,8 @@ const resolver = new oxc_resolver_1.ResolverFactory({
35
39
  '.cts',
36
40
  '.json',
37
41
  ],
38
- mainFields: ['module', 'main'], // ESM-first: prioritize \"module\" field over \"main\"
39
- conditionNames: ['import', 'require', 'node', 'default'], // Standard export conditions
42
+ mainFields: ['module', 'main'], // ESM-first: prioritize "module" field over "main"
43
+ conditionNames: ['import', 'default', 'require'], // ESM-first: exclude "node" which resolves to CJS
40
44
  symlinks: false, // Don't resolve symlinks to match enhanced-resolve behavior
41
45
  });
42
46
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "package-build-stats",
3
- "version": "8.0.2",
3
+ "version": "8.0.3",
4
4
  "author": "Shubham Kanodia <shubham.kanodia10@gmail.com>",
5
5
  "repository": "https://github.com/pastelsky/package-build-stats",
6
6
  "publishConfig": {
@@ -38,6 +38,7 @@
38
38
  "compare:test": "tsx scripts/index.ts test",
39
39
  "compare:top": "tsx scripts/index.ts top",
40
40
  "compare:advanced": "tsx scripts/index.ts compare",
41
+ "perf:test": "tsx scripts/performance-test.ts",
41
42
  "prepublish": "rm -rf build && yarn check && tsc && yarn format"
42
43
  },
43
44
  "prettier": {
@@ -62,27 +62,53 @@ export async function getPackageExportSizes(
62
62
  options: GetPackageStatsOptions = {},
63
63
  ) {
64
64
  const startTime = performance.now()
65
+ const timings: Record<string, number> = {}
66
+
65
67
  const { name: packageName, normalPath } = parsePackageString(packageString)
68
+
69
+ const preparePathStart = performance.now()
66
70
  const installPath = await InstallationUtils.preparePath(packageName)
71
+ timings.preparePath = performance.now() - preparePathStart
72
+ console.log(
73
+ `[PERF] [ExportSizes] preparePath: ${timings.preparePath.toFixed(2)}ms`,
74
+ )
67
75
 
68
76
  try {
77
+ const installStart = performance.now()
69
78
  await installPackage(packageString, installPath, options)
79
+ timings.install = performance.now() - installStart
80
+ console.log(
81
+ `[PERF] [ExportSizes] installPackage: ${timings.install.toFixed(2)}ms`,
82
+ )
70
83
 
71
84
  // The package is installed in node_modules subdirectory
72
85
  const packagePath =
73
86
  normalPath || path.join(installPath, 'node_modules', packageName)
87
+
88
+ const getAllExportsStart = performance.now()
74
89
  const exportMap = await getAllExports(
75
90
  packageString,
76
91
  packagePath,
77
92
  packageName,
78
93
  installPath, // Pass installPath as base for relative path calculation
79
94
  )
95
+ timings.getAllExports = performance.now() - getAllExportsStart
96
+ console.log(
97
+ `[PERF] [ExportSizes] getAllExports: ${timings.getAllExports.toFixed(2)}ms`,
98
+ )
80
99
 
81
100
  const exports = Object.keys(exportMap).filter(exp => !(exp === 'default'))
82
101
  debug('Got %d exports for %s', exports.length, packageString)
102
+ console.log(`[PERF] [ExportSizes] Found ${exports.length} exports`)
83
103
 
104
+ const externalsStart = performance.now()
84
105
  const externals = getExternals(packageName, installPath)
106
+ timings.getExternals = performance.now() - externalsStart
107
+ console.log(
108
+ `[PERF] [ExportSizes] getExternals: ${timings.getExternals.toFixed(2)}ms`,
109
+ )
85
110
 
111
+ const buildStart = performance.now()
86
112
  const builtDetails = await BuildUtils.buildPackageIgnoringMissingDeps({
87
113
  name: packageName,
88
114
  installPath,
@@ -93,6 +119,10 @@ export async function getPackageExportSizes(
93
119
  includeDependencySizes: false,
94
120
  },
95
121
  })
122
+ timings.build = performance.now() - buildStart
123
+ console.log(
124
+ `[PERF] [ExportSizes] buildPackage: ${timings.build.toFixed(2)}ms`,
125
+ )
96
126
 
97
127
  Telemetry.packageExportsSizes(packageString, startTime, true, options)
98
128
  return {
@@ -53,14 +53,20 @@ export default async function getPackageStats(
53
53
  options: GetPackageStatsOptions = {},
54
54
  ) {
55
55
  const startTime = performance.now()
56
+ const timings: Record<string, number> = {}
56
57
 
57
58
  const { name: packageName, isLocal } = parsePackageString(packageString)
58
59
 
60
+ const preparePathStart = performance.now()
59
61
  const installPath = await InstallationUtils.preparePath(
60
62
  packageName,
61
63
  options.client,
62
64
  )
65
+ timings.preparePath = performance.now() - preparePathStart
66
+ console.log(`[PERF] preparePath: ${timings.preparePath.toFixed(2)}ms`)
67
+
63
68
  try {
69
+ const installStart = performance.now()
64
70
  await InstallationUtils.installPackage(packageString, installPath, {
65
71
  isLocal,
66
72
  client: options.client,
@@ -68,9 +74,15 @@ export default async function getPackageStats(
68
74
  networkConcurrency: options.networkConcurrency,
69
75
  installTimeout: options.installTimeout,
70
76
  })
77
+ timings.install = performance.now() - installStart
78
+ console.log(`[PERF] installPackage: ${timings.install.toFixed(2)}ms`)
71
79
 
80
+ const externalsStart = performance.now()
72
81
  const externals = getExternals(packageName, installPath)
82
+ timings.getExternals = performance.now() - externalsStart
83
+ console.log(`[PERF] getExternals: ${timings.getExternals.toFixed(2)}ms`)
73
84
 
85
+ const parallelStart = performance.now()
74
86
  const [pacakgeJSONDetails, builtDetails] = await Promise.all([
75
87
  getPackageJSONDetails(packageName, installPath),
76
88
  BuildUtils.buildPackageIgnoringMissingDeps({
@@ -85,6 +97,10 @@ export default async function getPackageStats(
85
97
  },
86
98
  }),
87
99
  ])
100
+ timings.parallelBuild = performance.now() - parallelStart
101
+ console.log(
102
+ `[PERF] parallel (packageJSON + build): ${timings.parallelBuild.toFixed(2)}ms`,
103
+ )
88
104
 
89
105
  const hasCSSAsset = builtDetails.assets.some(asset => asset.type === 'css')
90
106
  const mainAsset = builtDetails.assets.find(
@@ -13,9 +13,13 @@ import Telemetry from './telemetry.utils'
13
13
  import { performance } from 'perf_hooks'
14
14
 
15
15
  // Initialize resolver with ESM-first configuration
16
- // Following oxc-linter's resolver configuration:
17
16
  // - main_fields: ["module", "main"] - prioritize ESM entry points
18
- // - condition_names: ["module", "import"] - standard ESM export conditions
17
+ // - condition_names: ["import", "default", "require"] - ESM-first export conditions
18
+ // NOTE: We intentionally exclude "node" because Node.js conditional exports resolution
19
+ // uses the PACKAGE's exports field order (not our conditionNames order) to determine
20
+ // priority. Packages like Vue have "node" before "import" in their exports, so including
21
+ // "node" would resolve to CJS files instead of ESM. We keep "require" as a fallback for
22
+ // packages that only export via "require" condition.
19
23
  // - extensions: all common JS/TS extensions
20
24
  // - symlinks: false - keep paths as-is without resolving symlinks (matches enhanced-resolve behavior)
21
25
  const resolver = new ResolverFactory({
@@ -30,8 +34,8 @@ const resolver = new ResolverFactory({
30
34
  '.cts',
31
35
  '.json',
32
36
  ],
33
- mainFields: ['module', 'main'], // ESM-first: prioritize \"module\" field over \"main\"
34
- conditionNames: ['import', 'require', 'node', 'default'], // Standard export conditions
37
+ mainFields: ['module', 'main'], // ESM-first: prioritize "module" field over "main"
38
+ conditionNames: ['import', 'default', 'require'], // ESM-first: exclude "node" which resolves to CJS
35
39
  symlinks: false, // Don't resolve symlinks to match enhanced-resolve behavior
36
40
  })
37
41