package-build-stats 8.2.3 → 8.2.5
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.
- package/build/common.types.d.ts +26 -0
- package/build/common.types.js +1 -0
- package/build/config/config.d.ts +4 -0
- package/build/config/config.js +5 -0
- package/build/config/makeRspackConfig.d.ts +11 -0
- package/build/config/makeRspackConfig.js +170 -0
- package/build/errors/CustomError.d.ts +42 -0
- package/build/errors/CustomError.js +69 -0
- package/build/getDependencySizeTree.d.ts +6 -0
- package/build/getDependencySizeTree.js +271 -0
- package/build/getPackageExportSizes.d.ts +18 -0
- package/build/getPackageExportSizes.js +95 -0
- package/build/getPackageStats.d.ts +26 -0
- package/build/getPackageStats.js +98 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +4 -0
- package/build/utils/build.utils.d.ts +51 -0
- package/build/utils/build.utils.js +288 -0
- package/build/utils/common.utils.d.ts +20 -0
- package/build/utils/common.utils.js +112 -0
- package/build/utils/exports.utils.d.ts +26 -0
- package/build/utils/exports.utils.js +192 -0
- package/build/utils/installation.utils.d.ts +9 -0
- package/build/utils/installation.utils.js +203 -0
- package/build/utils/telemetry.utils.d.ts +17 -0
- package/build/utils/telemetry.utils.js +121 -0
- package/package.json +4 -2
- package/src/utils/build.utils.ts +39 -14
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import Telemetry from './utils/telemetry.utils.js';
|
|
2
|
+
import { performance } from 'perf_hooks';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import createDebug from 'debug';
|
|
5
|
+
const debug = createDebug('bp:worker');
|
|
6
|
+
import { getExternals, parsePackageString } from './utils/common.utils.js';
|
|
7
|
+
import { getAllExports } from './utils/exports.utils.js';
|
|
8
|
+
import InstallationUtils from './utils/installation.utils.js';
|
|
9
|
+
import BuildUtils from './utils/build.utils.js';
|
|
10
|
+
async function installPackage(packageString, installPath, options) {
|
|
11
|
+
const { isLocal } = parsePackageString(packageString);
|
|
12
|
+
await InstallationUtils.installPackage(packageString, installPath, {
|
|
13
|
+
isLocal,
|
|
14
|
+
client: options.client,
|
|
15
|
+
limitConcurrency: options.limitConcurrency,
|
|
16
|
+
networkConcurrency: options.networkConcurrency,
|
|
17
|
+
installTimeout: options.installTimeout,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export async function getAllPackageExports(packageString, options = {}) {
|
|
21
|
+
const startTime = performance.now();
|
|
22
|
+
const { name: packageName, normalPath } = parsePackageString(packageString);
|
|
23
|
+
const installPath = await InstallationUtils.preparePath(packageName);
|
|
24
|
+
try {
|
|
25
|
+
await installPackage(packageString, installPath, options);
|
|
26
|
+
// The package is installed in node_modules subdirectory
|
|
27
|
+
const packagePath = normalPath || path.join(installPath, 'node_modules', packageName);
|
|
28
|
+
const results = await getAllExports(packageString, packagePath, packageName, installPath);
|
|
29
|
+
Telemetry.packageExports(packageString, startTime, true);
|
|
30
|
+
return results;
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
Telemetry.packageExports(packageString, startTime, false, err);
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await InstallationUtils.cleanupPath(installPath);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function getPackageExportSizes(packageString, options = {}) {
|
|
41
|
+
const startTime = performance.now();
|
|
42
|
+
const timings = {};
|
|
43
|
+
const { name: packageName, normalPath } = parsePackageString(packageString);
|
|
44
|
+
const preparePathStart = performance.now();
|
|
45
|
+
const installPath = await InstallationUtils.preparePath(packageName);
|
|
46
|
+
timings.preparePath = performance.now() - preparePathStart;
|
|
47
|
+
console.log(`[PERF] [ExportSizes] preparePath: ${timings.preparePath.toFixed(2)}ms`);
|
|
48
|
+
try {
|
|
49
|
+
const installStart = performance.now();
|
|
50
|
+
await installPackage(packageString, installPath, options);
|
|
51
|
+
timings.install = performance.now() - installStart;
|
|
52
|
+
console.log(`[PERF] [ExportSizes] installPackage: ${timings.install.toFixed(2)}ms`);
|
|
53
|
+
// The package is installed in node_modules subdirectory
|
|
54
|
+
const packagePath = normalPath || path.join(installPath, 'node_modules', packageName);
|
|
55
|
+
const getAllExportsStart = performance.now();
|
|
56
|
+
const exportMap = await getAllExports(packageString, packagePath, packageName, installPath);
|
|
57
|
+
timings.getAllExports = performance.now() - getAllExportsStart;
|
|
58
|
+
console.log(`[PERF] [ExportSizes] getAllExports: ${timings.getAllExports.toFixed(2)}ms`);
|
|
59
|
+
const exports = Object.keys(exportMap).filter(exp => !(exp === 'default'));
|
|
60
|
+
debug('Got %d exports for %s', exports.length, packageString);
|
|
61
|
+
console.log(`[PERF] [ExportSizes] Found ${exports.length} exports`);
|
|
62
|
+
const externalsStart = performance.now();
|
|
63
|
+
const externals = getExternals(packageName, installPath);
|
|
64
|
+
timings.getExternals = performance.now() - externalsStart;
|
|
65
|
+
console.log(`[PERF] [ExportSizes] getExternals: ${timings.getExternals.toFixed(2)}ms`);
|
|
66
|
+
const buildStart = performance.now();
|
|
67
|
+
const builtDetails = await BuildUtils.buildPackageIgnoringMissingDeps({
|
|
68
|
+
name: packageName,
|
|
69
|
+
installPath,
|
|
70
|
+
externals,
|
|
71
|
+
options: {
|
|
72
|
+
customImports: exports,
|
|
73
|
+
splitCustomImports: true,
|
|
74
|
+
includeDependencySizes: false,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
timings.build = performance.now() - buildStart;
|
|
78
|
+
console.log(`[PERF] [ExportSizes] buildPackage: ${timings.build.toFixed(2)}ms`);
|
|
79
|
+
Telemetry.packageExportsSizes(packageString, startTime, true, options);
|
|
80
|
+
return {
|
|
81
|
+
...builtDetails,
|
|
82
|
+
assets: builtDetails.assets.map(asset => ({
|
|
83
|
+
...asset,
|
|
84
|
+
path: exportMap[asset.name],
|
|
85
|
+
})),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
Telemetry.packageExportsSizes(packageString, startTime, false, options, err);
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await InstallationUtils.cleanupPath(installPath);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parts of the code are inspired from the `import-cost` project
|
|
3
|
+
* @see https://github.com/wix/import-cost/blob/master/packages/import-cost/src/webpack.js
|
|
4
|
+
*/
|
|
5
|
+
import { GetPackageStatsOptions } from './common.types.js';
|
|
6
|
+
export default function getPackageStats(packageString: string, options?: GetPackageStatsOptions): Promise<{
|
|
7
|
+
size: number;
|
|
8
|
+
gzip: number;
|
|
9
|
+
assets: Array<{
|
|
10
|
+
name: string;
|
|
11
|
+
type: string;
|
|
12
|
+
size: number;
|
|
13
|
+
gzip: number;
|
|
14
|
+
}>;
|
|
15
|
+
dependencySizes?: Array<{
|
|
16
|
+
name: string;
|
|
17
|
+
approximateSize: number;
|
|
18
|
+
}>;
|
|
19
|
+
ignoredMissingDependencies?: Array<string>;
|
|
20
|
+
dependencyCount?: number | undefined;
|
|
21
|
+
hasJSNext?: any;
|
|
22
|
+
hasJSModule?: any;
|
|
23
|
+
isModuleType?: boolean | undefined;
|
|
24
|
+
hasSideEffects?: any;
|
|
25
|
+
peerDependencies?: string[] | undefined;
|
|
26
|
+
}>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parts of the code are inspired from the `import-cost` project
|
|
3
|
+
* @see https://github.com/wix/import-cost/blob/master/packages/import-cost/src/webpack.js
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { getExternals, parsePackageString } from './utils/common.utils.js';
|
|
8
|
+
import InstallationUtils from './utils/installation.utils.js';
|
|
9
|
+
import BuildUtils from './utils/build.utils.js';
|
|
10
|
+
import { UnexpectedBuildError } from './errors/CustomError.js';
|
|
11
|
+
import Telemetry from './utils/telemetry.utils.js';
|
|
12
|
+
import { performance } from 'perf_hooks';
|
|
13
|
+
function getPackageJSONDetails(packageName, installPath) {
|
|
14
|
+
const startTime = performance.now();
|
|
15
|
+
const packageJSONPath = path.join(installPath, 'node_modules', packageName, 'package.json');
|
|
16
|
+
return fs.readFile(packageJSONPath, 'utf8').then((contents) => {
|
|
17
|
+
const parsedJSON = JSON.parse(contents);
|
|
18
|
+
Telemetry.getPackageJSONDetails(packageName, true, startTime);
|
|
19
|
+
return {
|
|
20
|
+
dependencyCount: 'dependencies' in parsedJSON
|
|
21
|
+
? Object.keys(parsedJSON.dependencies).length
|
|
22
|
+
: 0,
|
|
23
|
+
hasJSNext: parsedJSON['jsnext:main'] || false,
|
|
24
|
+
hasJSModule: parsedJSON['module'] || false,
|
|
25
|
+
isModuleType: parsedJSON['type'] === 'module',
|
|
26
|
+
hasSideEffects: 'sideEffects' in parsedJSON ? parsedJSON['sideEffects'] : true,
|
|
27
|
+
peerDependencies: 'peerDependencies' in parsedJSON
|
|
28
|
+
? Object.keys(parsedJSON.peerDependencies)
|
|
29
|
+
: [],
|
|
30
|
+
};
|
|
31
|
+
}, err => {
|
|
32
|
+
Telemetry.getPackageJSONDetails(packageName, false, startTime, err);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export default async function getPackageStats(packageString, options = {}) {
|
|
36
|
+
const startTime = performance.now();
|
|
37
|
+
const timings = {};
|
|
38
|
+
const { name: packageName, isLocal } = parsePackageString(packageString);
|
|
39
|
+
const preparePathStart = performance.now();
|
|
40
|
+
const installPath = await InstallationUtils.preparePath(packageName, options.client);
|
|
41
|
+
timings.preparePath = performance.now() - preparePathStart;
|
|
42
|
+
console.log(`[PERF] preparePath: ${timings.preparePath.toFixed(2)}ms`);
|
|
43
|
+
try {
|
|
44
|
+
const installStart = performance.now();
|
|
45
|
+
await InstallationUtils.installPackage(packageString, installPath, {
|
|
46
|
+
isLocal,
|
|
47
|
+
client: options.client,
|
|
48
|
+
limitConcurrency: options.limitConcurrency,
|
|
49
|
+
networkConcurrency: options.networkConcurrency,
|
|
50
|
+
installTimeout: options.installTimeout,
|
|
51
|
+
});
|
|
52
|
+
timings.install = performance.now() - installStart;
|
|
53
|
+
console.log(`[PERF] installPackage: ${timings.install.toFixed(2)}ms`);
|
|
54
|
+
const externalsStart = performance.now();
|
|
55
|
+
const externals = getExternals(packageName, installPath);
|
|
56
|
+
timings.getExternals = performance.now() - externalsStart;
|
|
57
|
+
console.log(`[PERF] getExternals: ${timings.getExternals.toFixed(2)}ms`);
|
|
58
|
+
const parallelStart = performance.now();
|
|
59
|
+
const [pacakgeJSONDetails, builtDetails] = await Promise.all([
|
|
60
|
+
getPackageJSONDetails(packageName, installPath),
|
|
61
|
+
BuildUtils.buildPackageIgnoringMissingDeps({
|
|
62
|
+
name: packageName,
|
|
63
|
+
installPath,
|
|
64
|
+
externals,
|
|
65
|
+
options: {
|
|
66
|
+
debug: options.debug,
|
|
67
|
+
minify: options.minify !== false,
|
|
68
|
+
customImports: options.customImports,
|
|
69
|
+
includeDependencySizes: true,
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
]);
|
|
73
|
+
timings.parallelBuild = performance.now() - parallelStart;
|
|
74
|
+
console.log(`[PERF] parallel (packageJSON + build): ${timings.parallelBuild.toFixed(2)}ms`);
|
|
75
|
+
const hasCSSAsset = builtDetails.assets.some(asset => asset.type === 'css');
|
|
76
|
+
const mainAsset = builtDetails.assets.find(asset => asset.name === 'main' && asset.type === (hasCSSAsset ? 'css' : 'js'));
|
|
77
|
+
if (!mainAsset) {
|
|
78
|
+
throw new UnexpectedBuildError('Did not find a main asset in the built bundle');
|
|
79
|
+
}
|
|
80
|
+
const totalTime = performance.now() - startTime;
|
|
81
|
+
Telemetry.packageStats(packageString, true, totalTime, options);
|
|
82
|
+
return {
|
|
83
|
+
...pacakgeJSONDetails,
|
|
84
|
+
...builtDetails,
|
|
85
|
+
size: mainAsset.size,
|
|
86
|
+
gzip: mainAsset.gzip,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
Telemetry.packageStats(packageString, false, performance.now() - startTime, options);
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
if (!options.debug) {
|
|
95
|
+
await InstallationUtils.cleanupPath(installPath);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Entry } from '@rspack/core';
|
|
2
|
+
import type { Stats } from '@rspack/core';
|
|
3
|
+
import { Externals, BuildPackageOptions, CreateEntryPointOptions } from '../common.types.js';
|
|
4
|
+
type CompilePackageArgs = {
|
|
5
|
+
name: string;
|
|
6
|
+
externals: Externals;
|
|
7
|
+
entry: Entry;
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
minify?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type CompilePackageReturn = {
|
|
12
|
+
stats: Stats;
|
|
13
|
+
error: Error | null;
|
|
14
|
+
};
|
|
15
|
+
type BuildPackageArgs = {
|
|
16
|
+
name: string;
|
|
17
|
+
installPath: string;
|
|
18
|
+
externals: Externals;
|
|
19
|
+
options: BuildPackageOptions;
|
|
20
|
+
};
|
|
21
|
+
type BuildPackageResult = {
|
|
22
|
+
assets: Array<{
|
|
23
|
+
name: string;
|
|
24
|
+
type: string;
|
|
25
|
+
size: number;
|
|
26
|
+
gzip: number;
|
|
27
|
+
}>;
|
|
28
|
+
dependencySizes?: Array<{
|
|
29
|
+
name: string;
|
|
30
|
+
approximateSize: number;
|
|
31
|
+
}>;
|
|
32
|
+
};
|
|
33
|
+
type BuildPackageResultWithIgnored = BuildPackageResult & {
|
|
34
|
+
ignoredMissingDependencies?: Array<string>;
|
|
35
|
+
};
|
|
36
|
+
declare function getCompilationErrors(stats: Stats): import("@rspack/core").RspackError[];
|
|
37
|
+
declare const BuildUtils: {
|
|
38
|
+
createEntryPoint(packageName: string, installPath: string, options: CreateEntryPointOptions): string;
|
|
39
|
+
compilePackage({ name, entry, externals, debug, minify, }: CompilePackageArgs): Promise<CompilePackageReturn>;
|
|
40
|
+
_parseMissingModules(errors: ReturnType<typeof getCompilationErrors>): string[];
|
|
41
|
+
buildPackage({ name, installPath, externals, options, }: BuildPackageArgs): Promise<{
|
|
42
|
+
assets: {
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
size: number;
|
|
46
|
+
gzip: number;
|
|
47
|
+
}[];
|
|
48
|
+
}>;
|
|
49
|
+
buildPackageIgnoringMissingDeps({ name, externals, installPath, options, }: BuildPackageArgs): Promise<BuildPackageResultWithIgnored>;
|
|
50
|
+
};
|
|
51
|
+
export default BuildUtils;
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { rspack } from '@rspack/core';
|
|
3
|
+
import isValidNPMName from 'is-valid-npm-name';
|
|
4
|
+
import { gzipSync } from 'zlib';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import getDependencySizes from '../getDependencySizeTree.js';
|
|
7
|
+
import makeRspackConfig from '../config/makeRspackConfig.js';
|
|
8
|
+
import { performance } from 'perf_hooks';
|
|
9
|
+
import { BuildError, CLIBuildError, EntryPointError, MissingDependencyError, UnexpectedBuildError, } from '../errors/CustomError.js';
|
|
10
|
+
import Telemetry from './telemetry.utils.js';
|
|
11
|
+
function notEmpty(value) {
|
|
12
|
+
return value !== null && value !== undefined;
|
|
13
|
+
}
|
|
14
|
+
function getCompilationErrors(stats) {
|
|
15
|
+
return [...stats.compilation.errors].filter(notEmpty).flat();
|
|
16
|
+
}
|
|
17
|
+
function closeCompiler(compiler) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
compiler.close(error => {
|
|
20
|
+
if (error) {
|
|
21
|
+
reject(error);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
resolve();
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const BuildUtils = {
|
|
30
|
+
createEntryPoint(packageName, installPath, options) {
|
|
31
|
+
const entryPath = path.join(installPath, options.entryFilename || 'index.js');
|
|
32
|
+
let importStatement;
|
|
33
|
+
if (options.esm) {
|
|
34
|
+
if (options.customImports) {
|
|
35
|
+
importStatement = `
|
|
36
|
+
import { ${options.customImports.join(', ')} } from '${packageName}';
|
|
37
|
+
console.log(${options.customImports.join(', ')})
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
importStatement = `import * as p from '${packageName}'; console.log(p)`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
if (options.customImports) {
|
|
46
|
+
importStatement = `
|
|
47
|
+
const { ${options.customImports.join(', ')} } = require('${packageName}');
|
|
48
|
+
console.log(${options.customImports.join(', ')})
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
importStatement = `const p = require('${packageName}'); console.log(p)`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
fs.writeFileSync(entryPath, importStatement, 'utf-8');
|
|
57
|
+
return entryPath;
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
throw new EntryPointError(err);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
compilePackage({ name, entry, externals, debug, minify, }) {
|
|
64
|
+
const startTime = performance.now();
|
|
65
|
+
const options = makeRspackConfig({
|
|
66
|
+
packageName: name,
|
|
67
|
+
entry,
|
|
68
|
+
externals,
|
|
69
|
+
debug,
|
|
70
|
+
minify,
|
|
71
|
+
});
|
|
72
|
+
const compiler = rspack(options);
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
compiler.run(async (error, stats) => {
|
|
75
|
+
try {
|
|
76
|
+
if (!stats) {
|
|
77
|
+
throw new Error('stats is null');
|
|
78
|
+
}
|
|
79
|
+
await closeCompiler(compiler);
|
|
80
|
+
if (error) {
|
|
81
|
+
console.error(error);
|
|
82
|
+
Telemetry.compilePackage(name, false, startTime, {}, error);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
Telemetry.compilePackage(name, true, startTime, {});
|
|
86
|
+
}
|
|
87
|
+
resolve({ stats, error });
|
|
88
|
+
}
|
|
89
|
+
catch (closeError) {
|
|
90
|
+
reject(closeError);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
_parseMissingModules(errors) {
|
|
96
|
+
// There's a better way to get the missing module's name, maybe ?
|
|
97
|
+
const missingModuleRegex = /Can't resolve '(.+)' in/;
|
|
98
|
+
const missingModules = errors.map(err => {
|
|
99
|
+
const matches = err.message.match(missingModuleRegex);
|
|
100
|
+
if (!matches) {
|
|
101
|
+
throw new UnexpectedBuildError('Expected to find a file path in the module not found error, but found none. Regex for this might be out of date.');
|
|
102
|
+
}
|
|
103
|
+
const missingFilePath = matches[1];
|
|
104
|
+
let packageNameMatch;
|
|
105
|
+
if (missingFilePath.startsWith('@')) {
|
|
106
|
+
packageNameMatch = missingFilePath.match(/@[^/]+\/[^/]+/); // @babel/runtime/object/create -> @babel/runtime
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
packageNameMatch = missingFilePath.match(/[^/]+/); // babel-runtime/object/create -> babel-runtime
|
|
110
|
+
}
|
|
111
|
+
if (!packageNameMatch) {
|
|
112
|
+
throw new UnexpectedBuildError('Failed to resolve the missing package name. Regex for this might be out of date.');
|
|
113
|
+
}
|
|
114
|
+
return packageNameMatch[0];
|
|
115
|
+
});
|
|
116
|
+
let uniqueMissingModules = Array.from(new Set(missingModules));
|
|
117
|
+
uniqueMissingModules = uniqueMissingModules.filter(mod => !mod.startsWith(`${uniqueMissingModules[0]}/`));
|
|
118
|
+
return uniqueMissingModules;
|
|
119
|
+
},
|
|
120
|
+
async buildPackage({ name, installPath, externals, options, }) {
|
|
121
|
+
var _a;
|
|
122
|
+
let entry = {};
|
|
123
|
+
if (options.splitCustomImports) {
|
|
124
|
+
if (!options.customImports || !options.customImports.length) {
|
|
125
|
+
return { assets: [] };
|
|
126
|
+
}
|
|
127
|
+
options.customImports.forEach(importt => {
|
|
128
|
+
entry[importt] = BuildUtils.createEntryPoint(name, installPath, {
|
|
129
|
+
customImports: [importt],
|
|
130
|
+
entryFilename: importt,
|
|
131
|
+
esm: true,
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
entry['main'] = BuildUtils.createEntryPoint(name, installPath, {
|
|
137
|
+
esm: true,
|
|
138
|
+
customImports: options.customImports,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const { stats, error } = await BuildUtils.compilePackage({
|
|
142
|
+
name,
|
|
143
|
+
entry,
|
|
144
|
+
externals,
|
|
145
|
+
debug: options.debug,
|
|
146
|
+
minify: options.minify,
|
|
147
|
+
});
|
|
148
|
+
const jsonStatsStartTime = performance.now();
|
|
149
|
+
let jsonStats = stats.toJson({
|
|
150
|
+
assets: true,
|
|
151
|
+
source: true,
|
|
152
|
+
chunks: false,
|
|
153
|
+
chunkGroups: false,
|
|
154
|
+
chunkModules: true,
|
|
155
|
+
modules: true,
|
|
156
|
+
nestedModules: true,
|
|
157
|
+
reasons: true,
|
|
158
|
+
depth: true,
|
|
159
|
+
errors: true,
|
|
160
|
+
entrypoints: false,
|
|
161
|
+
warnings: false,
|
|
162
|
+
});
|
|
163
|
+
if (!jsonStats) {
|
|
164
|
+
Telemetry.parseWebpackStats(name, false, jsonStatsStartTime);
|
|
165
|
+
throw new UnexpectedBuildError('Expected webpack json stats to be non-null, but was null');
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
Telemetry.parseWebpackStats(name, true, jsonStatsStartTime);
|
|
169
|
+
}
|
|
170
|
+
const compilationErrors = getCompilationErrors(stats);
|
|
171
|
+
if (error && !stats) {
|
|
172
|
+
throw new BuildError(error);
|
|
173
|
+
}
|
|
174
|
+
else if (compilationErrors.length) {
|
|
175
|
+
const missingModules = BuildUtils._parseMissingModules(compilationErrors);
|
|
176
|
+
if (missingModules.length) {
|
|
177
|
+
if (missingModules.length === 1 && missingModules[0] === name) {
|
|
178
|
+
throw new EntryPointError(compilationErrors.map(err => err.message));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
throw new MissingDependencyError(compilationErrors.map(err => err.toString()), { missingModules });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (jsonStats.errors && jsonStats.errors.length > 0) {
|
|
185
|
+
if (jsonStats.errors.some(error => error.message.includes("Unexpected character '#'"))) {
|
|
186
|
+
throw new CLIBuildError(jsonStats.errors);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
throw new BuildError(jsonStats.errors);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
throw new UnexpectedBuildError('The webpack stats object was unexpectedly empty');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
const getAssetStats = async (asset) => {
|
|
198
|
+
const bundle = path.join(process.cwd(), 'dist', asset.name);
|
|
199
|
+
const bundleContents = await fs.promises.readFile(bundle);
|
|
200
|
+
const gzip = gzipSync(bundleContents, {}).length;
|
|
201
|
+
const matches = asset.name.match(/(.+?)\.bundle\.(.+)$/);
|
|
202
|
+
if (!matches) {
|
|
203
|
+
throw new UnexpectedBuildError('Found an asset without the `.bundle` suffix. ' +
|
|
204
|
+
'A loader customization might be needed to recognize this asset type' +
|
|
205
|
+
asset.name);
|
|
206
|
+
}
|
|
207
|
+
const [, entryName, extension] = matches;
|
|
208
|
+
return {
|
|
209
|
+
name: entryName,
|
|
210
|
+
type: extension,
|
|
211
|
+
size: asset.size,
|
|
212
|
+
gzip,
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
const assetStatsPromises = ((_a = jsonStats === null || jsonStats === void 0 ? void 0 : jsonStats.assets) === null || _a === void 0 ? void 0 : _a.filter(asset => {
|
|
216
|
+
var _a;
|
|
217
|
+
return !((_a = asset.chunkNames) === null || _a === void 0 ? void 0 : _a.some(name => name === 'runtime' ||
|
|
218
|
+
(typeof name === 'string' && name.startsWith('runtime~'))));
|
|
219
|
+
}).filter(asset => typeof asset.name === 'string' &&
|
|
220
|
+
!asset.name.endsWith('LICENSE.txt')).map(getAssetStats)) || [];
|
|
221
|
+
const assetStats = await Promise.all(assetStatsPromises);
|
|
222
|
+
Telemetry.assetsGZIPParseTime(name, performance.now());
|
|
223
|
+
let dependencySizeResults = {};
|
|
224
|
+
if (options.includeDependencySizes) {
|
|
225
|
+
const dependencySizes = await getDependencySizes(name, jsonStats);
|
|
226
|
+
dependencySizeResults = {
|
|
227
|
+
dependencySizes,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
assets: assetStats || [],
|
|
232
|
+
...dependencySizeResults,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
async buildPackageIgnoringMissingDeps({ name, externals, installPath, options, }) {
|
|
237
|
+
const buildStartTime = performance.now();
|
|
238
|
+
let buildIteration = 1;
|
|
239
|
+
try {
|
|
240
|
+
const buildResult = await BuildUtils.buildPackage({
|
|
241
|
+
name,
|
|
242
|
+
externals,
|
|
243
|
+
installPath,
|
|
244
|
+
options,
|
|
245
|
+
});
|
|
246
|
+
Telemetry.buildPackage(name, true, buildStartTime, {
|
|
247
|
+
...options,
|
|
248
|
+
buildIteration,
|
|
249
|
+
});
|
|
250
|
+
return buildResult;
|
|
251
|
+
}
|
|
252
|
+
catch (e) {
|
|
253
|
+
buildIteration++;
|
|
254
|
+
if (e instanceof MissingDependencyError &&
|
|
255
|
+
e.missingModules.length <= 6 &&
|
|
256
|
+
e.missingModules.every(mod => isValidNPMName(mod))) {
|
|
257
|
+
const { missingModules } = e.extra;
|
|
258
|
+
const newExternals = {
|
|
259
|
+
...externals,
|
|
260
|
+
externalPackages: externals.externalPackages.concat(missingModules),
|
|
261
|
+
};
|
|
262
|
+
const rebuiltResult = await BuildUtils.buildPackage({
|
|
263
|
+
name,
|
|
264
|
+
externals: newExternals,
|
|
265
|
+
installPath,
|
|
266
|
+
options,
|
|
267
|
+
});
|
|
268
|
+
Telemetry.buildPackage(name, true, buildStartTime, {
|
|
269
|
+
...options,
|
|
270
|
+
buildIteration,
|
|
271
|
+
missingModules,
|
|
272
|
+
});
|
|
273
|
+
return {
|
|
274
|
+
ignoredMissingDependencies: missingModules,
|
|
275
|
+
...rebuiltResult,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
Telemetry.buildPackage(name, false, buildStartTime, {
|
|
280
|
+
...options,
|
|
281
|
+
buildIteration,
|
|
282
|
+
}, e);
|
|
283
|
+
throw e;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
export default BuildUtils;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const getBuiltInModules: () => string[];
|
|
2
|
+
export declare function exec(command: string, options: any, timeout?: number): Promise<unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* Gets external peerDeps that shouldn't be a
|
|
5
|
+
* part of the build in a regex format -
|
|
6
|
+
* /(^dep-a$|^dep-a\/|^dep-b$|^dep-b\/)\//
|
|
7
|
+
*/
|
|
8
|
+
export declare function getExternals(packageName: string, installPath: string): {
|
|
9
|
+
externalPackages: string[];
|
|
10
|
+
externalBuiltIns: string[];
|
|
11
|
+
};
|
|
12
|
+
type ParsePackageResult = {
|
|
13
|
+
name: string;
|
|
14
|
+
version: string | null;
|
|
15
|
+
scoped: boolean;
|
|
16
|
+
isLocal?: boolean;
|
|
17
|
+
normalPath?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function parsePackageString(packageString: string): ParsePackageResult;
|
|
20
|
+
export {};
|