rollup-plugin-webpack-stats
Version:
Rollup/Vite/Rolldown plugin to generate a stats JSON file with a bundle-stats webpack-compatible structure
149 lines (147 loc) • 4.6 kB
JavaScript
import { getByteSize, getChunkId } from "./utils.mjs";
import path from "path";
//#region src/transform.ts
/**
* Recursivily check if a chunk is async based on the chunks issuers
*/
const lookupChunkAsync = (chunksIssuers, chunk, processedChunks = [], cache = /* @__PURE__ */ new Map()) => {
const cached = cache.get(chunk.fileName);
if (cached !== void 0) return cached;
const result = lookupChunkAsyncUncached(chunksIssuers, chunk, processedChunks, cache);
cache.set(chunk.fileName, result);
return result;
};
const lookupChunkAsyncUncached = (chunksIssuers, chunk, processedChunks, cache) => {
if (processedChunks.includes(chunk.fileName)) return true;
if (chunk.isEntry) return false;
if (chunk.isDynamicEntry) return true;
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
*/
const nextProcessed = [...processedChunks, chunk.fileName];
return syncChunksIssuers.every((issuer) => lookupChunkAsync(chunksIssuers, issuer, nextProcessed, cache));
};
/**
* Store transformed sources
*/
var TransformSources = class {
constructor() {
this.entries = {};
}
entries = {};
push(id, source) {
this.entries[id] = source;
}
/**
* Get asset source
*/
getByAsset = (asset) => {
return this.entries[asset.name];
};
/**
* Get chunk source
*/
getByChunk = (chunk) => {
return this.entries[chunk.id];
};
/**
* Get module source
*/
getByModule = (module) => {
return this.entries[module.name];
};
};
const defaultTransform = (stats) => stats;
const bundleToWebpackStats = (bundle, pluginOptions) => {
const { moduleOriginalSize, transform = defaultTransform } = {
moduleOriginalSize: false,
...pluginOptions
};
const assets = [];
const chunks = [];
const moduleByFileName = {};
const sources = new TransformSources();
const chunksIssuers = {};
const entries = Object.values(bundle);
entries.forEach((entry) => {
if (entry.type === "chunk") entry.imports?.forEach((chunkImportFileName) => {
if (chunksIssuers[entry.fileName]?.find((chunkIssuer) => chunkIssuer.fileName === chunkImportFileName)) return;
if (!chunksIssuers[chunkImportFileName]) chunksIssuers[chunkImportFileName] = [];
chunksIssuers[chunkImportFileName].push(entry);
});
});
entries.forEach((entry) => {
if (entry.type === "chunk") {
assets.push({
name: entry.fileName,
size: getByteSize(entry.code)
});
sources.push(entry.fileName, entry);
const chunkId = getChunkId(entry);
const chunkAsync = lookupChunkAsync(chunksIssuers, entry);
chunks.push({
id: chunkId,
entry: entry.isEntry,
initial: !chunkAsync,
files: [entry.fileName],
names: [entry.name]
});
sources.push(chunkId, entry);
Object.entries(entry.modules).forEach(([modulePath, moduleInfo]) => {
const normalizedModulePath = modulePath.replace("\0", "");
const relativeModulePath = path.relative(process.cwd(), normalizedModulePath);
const relativeModulePathWithPrefix = relativeModulePath.match(/^\.\./) ? relativeModulePath : `.${path.sep}${relativeModulePath}`;
const moduleEntry = moduleByFileName[relativeModulePathWithPrefix];
if (moduleEntry) moduleEntry.chunks.push(chunkId);
else {
moduleByFileName[relativeModulePathWithPrefix] = {
name: relativeModulePathWithPrefix,
size: moduleOriginalSize ? moduleInfo.originalLength : moduleInfo.renderedLength,
chunks: [chunkId]
};
sources.push(relativeModulePathWithPrefix, {
fileName: modulePath,
...moduleInfo
});
}
});
} else if (entry.type === "asset") {
assets.push({
name: entry.fileName,
size: getByteSize(entry.source)
});
sources.push(entry.fileName, entry);
}
});
const stats = {
builtAt: Date.now(),
assets,
chunks,
modules: Object.values(moduleByFileName)
};
let result;
try {
result = transform(stats, sources, bundle);
} catch (error) {
console.error("Custom transform failed! Returning stats without any transforms.", error);
result = stats;
}
return result;
};
//#endregion
export { bundleToWebpackStats, lookupChunkAsync };
//# sourceMappingURL=transform.mjs.map