Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix chunk initial flag #403

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,54 @@ export interface WebpackStatsFiltered {
modules: Array<WebpackStatsFilteredRootModule>;
}

export type ChunksIssuers = Record<string, Array<OutputChunk>>;

/**
* Recursivily check if a chunk is async based on the chunks issuers
*/
export const lookupChunkAsync = (chunk: OutputChunk, chunksIssuers: ChunksIssuers):boolean => {
if (chunk.isDynamicEntry) {
return true;
}

if (chunk.isEntry) {
return false;
}

const chunkIssuers = chunksIssuers[chunk.fileName];

/**
* A sync chunk without issuer chunks, is sync
*/
if (!chunkIssuers) {
return false;
}

const syncChunksIssuers = chunkIssuers.filter((chunkIssuer) => {
return chunkIssuer.isDynamicEntry === false;
});

/**
* A sync chunk with all the chunk issuer async, is async
*/
if (syncChunksIssuers.length === 0) {
return true;
}

/**
* Recursively lookup for sync loads on the 2nd level issuers
* - if at least one issuer is sync, the chunk is sync
* - if none of the issuers are sync, the chunk is async
*/
let isAsync = true;

for (let i = 0; i < syncChunksIssuers.length && isAsync; i++) {
isAsync = lookupChunkAsync(syncChunksIssuers[i], chunksIssuers);
}

return isAsync;
}

type AssetSource = OutputChunk | OutputAsset;
type ChunkSource = OutputChunk;
type ModuleSource = { fileName: string } & RenderedModule;
Expand Down Expand Up @@ -108,9 +156,24 @@ export const bundleToWebpackStats = (
const chunks: Array<WebpackStatsFilteredChunk> = [];
const moduleByFileName: Record<string, WebpackStatsFilteredModule> = {};
const sources = new TransformSources();
const chunksIssuers: ChunksIssuers = {};

const entries = Object.values(bundle);

// Collect metadata
entries.forEach((entry) => {
if (entry.type === 'chunk') {
entry.imports?.forEach((chunkDependency) => {
if (!chunksIssuers[chunkDependency]) {
chunksIssuers[chunkDependency] = [];
}

chunksIssuers[chunkDependency].push(entry);
});
}
});

// Process data
entries.forEach((entry) => {
if (entry.type === 'chunk') {
assets.push({
Expand All @@ -120,11 +183,12 @@ export const bundleToWebpackStats = (
sources.push(entry.fileName, entry);

const chunkId = getChunkId(entry);
const chunkAsync = lookupChunkAsync(entry, chunksIssuers);

chunks.push({
id: chunkId,
entry: entry.isEntry,
initial: !entry.isDynamicEntry,
initial: !chunkAsync,
files: [entry.fileName],
names: [entry.name],
});
Expand Down
121 changes: 42 additions & 79 deletions test/unit/fixtures/rollup-bundle-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import type { OutputBundle } from 'rollup';

export const ROOT_DIR = path.join(__dirname, '../../../');

export const stats = {
export const statsFixtures = {
'assets/logo-abcd1234.svg': {
name: undefined,
fileName: 'assets/logo-abcd1234.svg',
type: 'asset',
source: '<svg></svg>',
needsCodeReference: true,
originalFileName: 'assets/logo.svg',
originalFileNames: ['assets/logo.svg'],
names: ['assets/logo.svg'],
},
'assets/main-abcd1234.js': {
name: 'main',
fileName: 'assets/main-abcd1234.js',
preliminaryFileName: 'assets/main-abcd1234.js',
sourcemapFileName: 'assets/main-abcd1234.js.map',
'assets/vendors-abcd1234.js': {
name: 'vendors',
fileName: 'assets/vendors-abcd1234.js',
preliminaryFileName: 'assets/vendors-abcd1234.js',
sourcemapFileName: 'assets/vendors-abcd1234.js.map',
type: 'chunk',
code: 'export default function () {}',
isEntry: true,
Expand All @@ -27,18 +30,28 @@ export const stats = {
importedBindings: {},
referencedFiles: [],
moduleIds: [
path.join(ROOT_DIR, 'src/component-a.js'),
path.join(ROOT_DIR, 'src/index.js'),
path.join(ROOT_DIR, 'node_modules', 'package-a', 'index.js'),
path.join(ROOT_DIR, 'node_modules', 'package-b', 'index.js'),
],
modules: {
[path.join(ROOT_DIR, 'src/component-a.js')]: {
code: 'export default A = 1;',
originalLength: 10,
[path.join(
ROOT_DIR,
'node_modules',
'package-a',
'index.js'
)]: {
code: '',
originalLength: 10,
renderedLength: 8,
removedExports: [],
renderedExports: [],
},
[path.join(ROOT_DIR, 'src/index.js')]: {
[path.join(
ROOT_DIR,
'node_modules',
'package-b',
'index.js'
)]: {
code: '',
originalLength: 100,
renderedLength: 80,
Expand All @@ -50,11 +63,11 @@ export const stats = {
exports: [],
dynamicImports: [],
},
'assets/vendors-abcd1234.js': {
name: 'vendors',
fileName: 'assets/vendors-abcd1234.js',
preliminaryFileName: 'assets/vendors-abcd1234.js',
sourcemapFileName: 'assets/vendors-abcd1234.js.map',
'assets/main-abcd1234.js': {
name: 'main',
fileName: 'assets/main-abcd1234.js',
preliminaryFileName: 'assets/main-abcd1234.js',
sourcemapFileName: 'assets/main-abcd1234.js.map',
type: 'chunk',
code: 'export default function () {}',
isEntry: true,
Expand All @@ -66,36 +79,26 @@ export const stats = {
importedBindings: {},
referencedFiles: [],
moduleIds: [
path.join(ROOT_DIR, 'node_modules', 'package-a', 'index.js'),
path.join(ROOT_DIR, 'node_modules', 'package-b', 'index.js'),
path.join(ROOT_DIR, 'src/component-a.js'),
path.join(ROOT_DIR, 'src/index.js'),
],
modules: {
[path.join(
ROOT_DIR,
'node_modules',
'package-a',
'index.js'
)]: {
code: '',
originalLength: 10,
[path.join(ROOT_DIR, 'src/component-a.js')]: {
code: 'export default A = 1;',
originalLength: 10,
renderedLength: 8,
removedExports: [],
renderedExports: [],
},
[path.join(
ROOT_DIR,
'node_modules',
'package-b',
'index.js'
)]: {
[path.join(ROOT_DIR, 'src/index.js')]: {
code: '',
originalLength: 100,
renderedLength: 80,
removedExports: [],
renderedExports: [],
},
},
imports: [],
imports: ['assets/vendors-abcd1234.js'],
exports: [],
dynamicImports: [],
},
Expand Down Expand Up @@ -132,7 +135,10 @@ export const stats = {
renderedExports: [],
},
},
imports: [],
imports: [
'assets/index-abcd1234.js',
'assets/index-efab5678.js',
],
exports: [],
dynamicImports: [],
},
Expand All @@ -144,7 +150,7 @@ export const stats = {
type: 'chunk',
code: 'export default function () {}',
isEntry: false,
isDynamicEntry: true,
isDynamicEntry: false,
facadeModuleId: null,
map: null,
isImplicitEntry: false,
Expand All @@ -169,49 +175,6 @@ export const stats = {
renderedExports: [],
},
},
imports: [],
exports: [],
dynamicImports: [],
},
} satisfies OutputBundle;

export const statsWithDynamicEntry = {
'assets/main-abcd1234.js': {
name: 'main',
fileName: 'assets/main-abcd1234.js',
preliminaryFileName: 'assets/main-abcd1234.js',
sourcemapFileName: 'assets/main-abcd1234.js.map',
type: 'chunk',
code: 'export default function () {}',
isEntry: true,
isDynamicEntry: true,
facadeModuleId: null,
map: null,
isImplicitEntry: false,
implicitlyLoadedBefore: [],
importedBindings: {},
referencedFiles: [],
moduleIds: [
path.join(ROOT_DIR, 'src/component-a.js'),
path.join(ROOT_DIR, 'src/index.js'),
],
modules: {
[path.join(ROOT_DIR, 'src/component-a.js')]: {
code: 'export default A = 1;',
originalLength: 10,
renderedLength: 8,
removedExports: [],
renderedExports: [],
},
[path.join(ROOT_DIR, 'src/index.js')]: {
code: '',
originalLength: 100,
renderedLength: 80,
removedExports: [],
renderedExports: [],
},
},
imports: [],
exports: [],
dynamicImports: [],
},
Expand Down
Loading
Loading