-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(angular-rollup): add min chunk imp
- Loading branch information
1 parent
0eaa034
commit 9645838
Showing
10 changed files
with
575 additions
and
405 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 5 additions & 2 deletions
7
packages/angular-rollup/src/executors/bundle/executor.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
packages/angular-rollup/src/executors/bundle/rollup-stats.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { balanceOutputSizes, importsInEntryPoint } from './rollup-stats'; | ||
import { Metafile } from 'esbuild'; | ||
|
||
describe('importsInEntryPoint', () => { | ||
const outputs = { | ||
'main-X.js': { | ||
imports: [ | ||
{ kind: 'import-statement', path: 'chunk-A.js' }, | ||
{ kind: 'dynamic-import', path: 'chunk-B.js' }, | ||
], | ||
}, | ||
'chunk-A.js': { imports: [{ kind: 'import-statement', path: 'chunk-B.js' }] }, | ||
'chunk-B.js': { imports: [{ kind: 'dynamic-import', path: 'chunk-C.js' }] }, | ||
'chunk-C.js': { imports: [{ kind: 'import-statement', path: 'chunk-C.js' }] }, | ||
} as unknown as Metafile['outputs']; | ||
|
||
it('should return chunks imported in entry point', () => { | ||
expect(importsInEntryPoint('main-X.js', outputs)).toEqual( | ||
['main-X.js', 'chunk-A.js', 'chunk-B.js'] | ||
) | ||
}); | ||
}); | ||
|
||
describe('balanceOutputSizes', () => { | ||
|
||
const inputChunks = [ | ||
{ name: 'a', size: 1 }, | ||
{ name: 'b', size: 3 }, | ||
{ name: 'c', size: 7 }, | ||
{ name: 'd', size: 4 }, | ||
{ name: 'e', size: 1 }, | ||
{ name: 'f', size: 11 }, | ||
]; | ||
|
||
it('should return new array of balanced output sizes', () => { | ||
expect(balanceOutputSizes(3, inputChunks)).toEqual([ | ||
{ name: '252F10C8', imports: ['f'], size: 11}, | ||
{ name: '69590970', imports: ["c", "a"], size: 8}, | ||
{ name: '7C088BD4', imports: ["d", "b", "e"], size: 8} | ||
]); | ||
}); | ||
}) |
74 changes: 74 additions & 0 deletions
74
packages/angular-rollup/src/executors/bundle/rollup-stats.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { ImportKind, Metafile } from 'esbuild'; | ||
import { createHash } from 'crypto' | ||
|
||
type ReadonlyDeep<T> = T extends (...args: ReadonlyArray<never>) => never | ||
? T | ||
: T extends never[] | ||
? ReadonlyArray<ReadonlyDeep<T[number]>> | ||
: T extends object | ||
? { readonly [K in keyof T]: ReadonlyDeep<T[K]> } | ||
: T; | ||
|
||
type MetafileOutputs = ReadonlyDeep<Metafile['outputs']>; | ||
|
||
type OutputImport = { | ||
readonly path: string; | ||
readonly kind: ImportKind | 'file-loader'; | ||
readonly external?: boolean | undefined; | ||
}; | ||
|
||
const isNotImportKind = (excludedKind: ImportKind) => ({kind}: OutputImport): boolean => kind !== excludedKind; | ||
const isNotDynamicImport = isNotImportKind("dynamic-import"); | ||
const importNotTraversed = (traversedImports: ReadonlyArray<string>) => ({path}: OutputImport): boolean => !traversedImports.includes(path); | ||
const importsInSubEntryPoint = (metaFileOutputs: MetafileOutputs, traversedImports: ReadonlyArray<string>) => (path: string) => importsInEntryPoint(path, metaFileOutputs, traversedImports.concat(path)); | ||
|
||
export function importsInEntryPoint(entryPoint: string, metaFileOutputs: MetafileOutputs, traversedImports: ReadonlyArray<string> = [entryPoint]): ReadonlyArray<string> { | ||
const staticImports = metaFileOutputs[entryPoint].imports.filter(isNotDynamicImport).filter(importNotTraversed(traversedImports)).map(({path}) => path); | ||
return staticImports.length ? staticImports.flatMap(importsInSubEntryPoint(metaFileOutputs, traversedImports)) : traversedImports; | ||
} | ||
|
||
interface OutputSize { | ||
readonly name: string; | ||
readonly size: number; | ||
readonly imports?: ReadonlyArray<string>; | ||
} | ||
|
||
const comparedBySize = (a: OutputSize, b: OutputSize) => b.size - a.size; | ||
const outputSizeMapFn = (name: string, size: number, imports: ReadonlyArray<string>): OutputSize => ({ name, size, imports }) | ||
const emptyBalancedOutputSizes = (targetChunkCount: number): OutputSize[] => Array.from({ length: targetChunkCount }, (_, i) => outputSizeMapFn(i.toString(), 0, [])); | ||
const indexOfSmallestOutput = (prev: number, curr: OutputSize, index: number, array: ReadonlyArray<OutputSize>): number => curr.size < array[prev].size ? index : prev; | ||
|
||
const hashFromOutputPaths = (paths: ReadonlyArray<string>) => createHash('sha256').update(paths.join('')).digest('hex').substring(0, 8).toUpperCase(); | ||
|
||
const greedyBalanceOutputSize = (previousOutputs: ReadonlyArray<OutputSize>, currentOutput: OutputSize): OutputSize[] => { | ||
const smallestBinIndex = previousOutputs.reduce<number>(indexOfSmallestOutput, 0); | ||
return previousOutputs.map((output, index) => { | ||
return index === smallestBinIndex | ||
? { name: output.name, size: output.size + currentOutput.size, imports: [...output.imports ?? [], currentOutput.name] } | ||
: output | ||
}) | ||
} | ||
|
||
export function balanceOutputSizes(targetChunkCount: number, sizedChunks: ReadonlyArray<OutputSize>): OutputSize[] { | ||
return sizedChunks | ||
.toSorted(comparedBySize) | ||
.reduce(greedyBalanceOutputSize, emptyBalancedOutputSizes(targetChunkCount)) | ||
.filter(({size}) => size !== 0) | ||
.map((output: OutputSize) => ({ ...output, name: hashFromOutputPaths(output.imports!) })); | ||
} | ||
|
||
export function balanceMetaOutputs(targetChunkCount: number, entry: string, outputs: MetafileOutputs): Readonly<Record<string, string>> { | ||
const imports = importsInEntryPoint(entry, outputs); | ||
const outputEntries = Object.entries(outputs); | ||
|
||
const initialOutputSizes = outputEntries.filter(([path]) => imports.includes(path)).map(([path, details]) => outputSizeMapFn(path, details.bytes, details.imports.map(({path}) => path))); | ||
|
||
const balancedOutputs = balanceOutputSizes(targetChunkCount, initialOutputSizes); | ||
|
||
return balancedOutputs.reduce((previousValue, currentValue) => { | ||
const chunkMaps = currentValue.imports?.reduce((prev, curr) => { | ||
return { ...prev, [curr]: currentValue.name } | ||
}, {}) ; | ||
return { ...previousValue, ...chunkMaps }; | ||
}, {}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
export interface BundleExecutorSchema { | ||
main: string; | ||
outputPath: string; | ||
} // eslint-disable-line | ||
maxChunks: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters