Skip to content

Commit 872c543

Browse files
authored
Update size analysis cli to support analyzing default export, side effect export and namespace export (#4349)
* support default imports, side effect imports and namespace imports * add import path * fix * make size analysis self contained * build size analysis tool * copy dependencies to report
1 parent a67d320 commit 872c543

File tree

5 files changed

+147
-8
lines changed

5 files changed

+147
-8
lines changed

repo-scripts/size-analysis/bundle-analysis.ts

+77-4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ interface DebugOptions {
4646

4747
interface BundleDefinition {
4848
name: string;
49+
description?: string;
4950
dependencies: BundleDependency[];
5051
}
5152

@@ -74,6 +75,12 @@ enum Mode {
7475
Local = 'local'
7576
}
7677

78+
enum SpecialImport {
79+
Default = 'default import',
80+
Sizeeffect = 'side effect import',
81+
Namespace = 'namespace import'
82+
}
83+
7784
export async function run({
7885
input,
7986
bundler,
@@ -247,7 +254,9 @@ async function analyzeBundle(
247254
): Promise<BundleAnalysis> {
248255
const analysis: BundleAnalysis = {
249256
name: bundleDefinition.name,
250-
results: []
257+
description: bundleDefinition.description ?? '',
258+
results: [],
259+
dependencies: bundleDefinition.dependencies
251260
};
252261

253262
let moduleDirectory: string | undefined;
@@ -392,15 +401,23 @@ async function analyzeBundleWithBundler(
392401

393402
function createEntryFileContent(bundleDefinition: BundleDefinition): string {
394403
const contentArray = [];
404+
// cache used symbols. Used to avoid symbol collision when multiple modules export symbols with the same name.
405+
const symbolsCache = new Set<string>();
395406
for (const dep of bundleDefinition.dependencies) {
396407
for (const imp of dep.imports) {
397408
if (typeof imp === 'string') {
398-
contentArray.push(`export {${imp}} from '${dep.packageName}';`);
409+
contentArray.push(
410+
...createImportExport(imp, dep.packageName, symbolsCache)
411+
);
399412
} else {
400-
// Import object
413+
// submodule imports
401414
for (const subImp of imp.imports) {
402415
contentArray.push(
403-
`export {${subImp}} from '${dep.packageName}/${imp.path}';`
416+
...createImportExport(
417+
subImp,
418+
`${dep.packageName}/${imp.path}`,
419+
symbolsCache
420+
)
404421
);
405422
}
406423
}
@@ -410,8 +427,64 @@ function createEntryFileContent(bundleDefinition: BundleDefinition): string {
410427
return contentArray.join('\n');
411428
}
412429

430+
function createImportExport(
431+
symbol: string,
432+
modulePath: string,
433+
symbolsCache: Set<string>
434+
): string[] {
435+
const contentArray = [];
436+
437+
switch (symbol) {
438+
case SpecialImport.Default: {
439+
const nameToUse = createSymbolName('default_import', symbolsCache);
440+
contentArray.push(`import ${nameToUse} from '${modulePath}';`);
441+
contentArray.push(`console.log(${nameToUse})`); // prevent import from being tree shaken
442+
break;
443+
}
444+
case SpecialImport.Namespace: {
445+
const nameToUse = createSymbolName('namespace', symbolsCache);
446+
contentArray.push(`import * as ${nameToUse} from '${modulePath}';`);
447+
contentArray.push(`console.log(${nameToUse})`); // prevent import from being tree shaken
448+
break;
449+
}
450+
case SpecialImport.Sizeeffect:
451+
contentArray.push(`import '${modulePath}';`);
452+
break;
453+
default:
454+
// named imports
455+
const nameToUse = createSymbolName(symbol, symbolsCache);
456+
457+
if (nameToUse !== symbol) {
458+
contentArray.push(
459+
`export {${symbol} as ${nameToUse}} from '${modulePath}';`
460+
);
461+
} else {
462+
contentArray.push(`export {${symbol}} from '${modulePath}';`);
463+
}
464+
}
465+
466+
return contentArray;
467+
}
468+
469+
/**
470+
* In case a symbol with the same name is already imported from another module, we need to give this symbol another name
471+
* using "originalname as anothername" syntax, otherwise it returns the original symbol name.
472+
*/
473+
function createSymbolName(symbol: string, symbolsCache: Set<string>): string {
474+
let nameToUse = symbol;
475+
const max = 100;
476+
while (symbolsCache.has(nameToUse)) {
477+
nameToUse = `${symbol}_${Math.floor(Math.random() * max)}`;
478+
}
479+
480+
symbolsCache.add(nameToUse);
481+
return nameToUse;
482+
}
483+
413484
interface BundleAnalysis {
414485
name: string; // the bundle name defined in the bundle definition
486+
description: string;
487+
dependencies: BundleDependency[];
415488
results: BundleAnalysisResult[];
416489
}
417490

repo-scripts/size-analysis/bundle-definition-examples/bundle-definition-1.json

+21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[
22
{
33
"name": "test",
4+
"desecription": "",
45
"dependencies": [
56
{
67
"packageName": "@firebase/app",
@@ -19,5 +20,25 @@
1920
]
2021
}
2122
]
23+
},
24+
{
25+
"name": "test2",
26+
"description": "default imports and side effect imports",
27+
"dependencies": [
28+
{
29+
"packageName": "@firebase/app",
30+
"versionOrTag": "latest",
31+
"imports": [
32+
"default import"
33+
]
34+
},
35+
{
36+
"packageName": "@firebase/firestore",
37+
"versionOrTag": "latest",
38+
"imports": [
39+
"side effect import"
40+
]
41+
}
42+
]
2243
}
2344
]

repo-scripts/size-analysis/package-analysis.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { resolve, basename } from 'path';
18+
import { resolve, basename, dirname } from 'path';
1919
import {
2020
generateReport,
2121
generateReportForModules,
@@ -24,10 +24,10 @@ import {
2424
ErrorCode,
2525
writeReportToDirectory
2626
} from './analysis-helper';
27-
import { mapWorkspaceToPackages } from '../../scripts/release/utils/workspace';
28-
import { projectRoot } from '../../scripts/utils';
27+
import glob from 'glob';
2928
import * as fs from 'fs';
3029

30+
const projectRoot = dirname(resolve(__dirname, '../package.json'));
3131
/**
3232
* Support Command Line Options
3333
* -- inputModule (optional) : can be left unspecified which results in running analysis on all exp modules.
@@ -112,3 +112,17 @@ export async function analyzePackageSize(
112112
throw new Error(ErrorCode.INVALID_FLAG_COMBINATION);
113113
}
114114
}
115+
116+
function mapWorkspaceToPackages(workspaces: string[]): Promise<string[]> {
117+
return Promise.all<string[]>(
118+
workspaces.map(
119+
workspace =>
120+
new Promise(resolve => {
121+
glob(workspace, (err, paths) => {
122+
if (err) throw err;
123+
resolve(paths);
124+
});
125+
})
126+
)
127+
).then(paths => paths.reduce((arr, val) => arr.concat(val), []));
128+
}

repo-scripts/size-analysis/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"test": "run-p lint test:node",
1414
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:node",
1515
"pretest:node": "tsc -p test/test-inputs && rollup -c",
16-
"test:node": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha **/*.test.ts --config ../../config/mocharc.node.js --timeout 60000"
16+
"test:node": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha **/*.test.ts --config ../../config/mocharc.node.js --timeout 60000",
17+
"build": "rollup -c"
1718
},
1819
"dependencies": {
1920
"rollup": "2.35.1",

repo-scripts/size-analysis/rollup.config.js

+30
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const deps = Object.keys(
2424
Object.assign({}, pkg.peerDependencies, pkg.dependencies)
2525
);
2626

27+
const nodeInternals = ['fs', 'path'];
28+
2729
export default [
2830
{
2931
input: 'test/test-inputs/subsetExports.ts',
@@ -49,5 +51,33 @@ export default [
4951
})
5052
],
5153
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`))
54+
},
55+
{
56+
input: 'cli.ts',
57+
output: [
58+
{
59+
file: 'dist/cli.js',
60+
format: 'cjs',
61+
sourcemap: false
62+
}
63+
],
64+
plugins: [
65+
typescriptPlugin({
66+
typescript,
67+
tsconfigOverride: {
68+
compilerOptions: {
69+
target: 'es2017',
70+
module: 'es2015'
71+
}
72+
}
73+
}),
74+
json({
75+
preferConst: true
76+
})
77+
],
78+
external: id =>
79+
[...deps, ...nodeInternals].some(
80+
dep => id === dep || id.startsWith(`${dep}/`)
81+
)
5282
}
5383
];

0 commit comments

Comments
 (0)