Skip to content

Commit

Permalink
Merge pull request #13 from vio/exclude-entries
Browse files Browse the repository at this point in the history
feat: Add support for excludeAssets/excludeModules
  • Loading branch information
vio authored Dec 23, 2024
2 parents ce0493e + d3772aa commit e530e13
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 17 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ module.exports = {
- `fileName` - the JSON filename relative to the build folder, default: `stats.json`
- `stats`
- `source` - output asset/chunk/module source (default `false`)
- `excludeAssets` - exclude matching assets: `string | RegExp | ((filepath: string) => boolean) | Array<string | RegExp | ((filepath: string) => boolean)>`
- `excludeModules` - exclude matching modules: `string | RegExp | ((filepath: string) => boolean) | Array<string | RegExp | ((filepath: string) => boolean)>`
58 changes: 41 additions & 17 deletions src/extract.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { OutputAsset, OutputBundle, OutputChunk, RenderedModule } from 'rollup';
import omit from 'lodash/omit.js';
import { type ExcludeFilepathPatterns, checkExcludeFilepath } from './utils/check-exclude-filepath';

export type AssetStats = Omit<OutputAsset, 'source'> & {
source?: OutputAsset['source'];
Expand All @@ -22,47 +23,70 @@ export type StatsOptions = {
* @default false
*/
source?: boolean;
/**
* Exclude matching assets
*/
excludeAssets?: ExcludeFilepathPatterns;
/**
* Exclude matching modules
*/
excludeModules?: ExcludeFilepathPatterns;
}

export default function extractRollupStats(bundle: OutputBundle, options: StatsOptions = {}): Stats {
const { source = false } = options;
const { source = false, excludeAssets, excludeModules } = options;

const output: Stats = {};

Object.entries(bundle).forEach(([key, entry]) => {
if (entry.type === "asset") {
let entryAsset = structuredClone(entry) as AssetStats;
Object.entries(bundle).forEach(([bundleEntryFilepath, bundleEntryStats]) => {
// Skip extraction if the entry filepath matches the exclude assets pattern
if (checkExcludeFilepath(bundleEntryFilepath, excludeAssets)) {
return;
}

// Skip asset source if options.source is false
if (bundleEntryStats.type === "asset") {
let assetStats = structuredClone(bundleEntryStats) as AssetStats;

// Skip asset source if options source is false
if (!source) {
entryAsset = omit(entryAsset, 'source');
assetStats = omit(assetStats, 'source');
}

output[key] = entryAsset;
output[bundleEntryFilepath] = assetStats;

return;
}

if (entry.type === "chunk") {
let entryChunk = structuredClone(entry) as ChunkStats;
if (bundleEntryStats.type === "chunk") {
let chunkStats = structuredClone(bundleEntryStats) as ChunkStats;

// Skip chunk code if options.source is false
// Skip chunk source if options source is false
if (!source) {
entryChunk = omit(entryChunk, 'code');
chunkStats = omit(chunkStats, 'code');
}

Object.entries(entryChunk.modules).forEach(([moduleKey, moduleEntry]) => {
let entryChunkModule = structuredClone(moduleEntry) as ModuleStats;
// Extract chunk modules stats
const chunkModulesStats: ChunkStats['modules'] = {};

Object.entries(chunkStats.modules).forEach(([bundleModuleFilepath, bundleModuleStats]) => {
// Skip module extraction if the filepath matches the exclude modules pattern
if (checkExcludeFilepath(bundleModuleFilepath, excludeModules)) {
return;
}

// Skip module source if source is false
let moduleStats = structuredClone(bundleModuleStats) as ModuleStats;

// Skip module source if options source is false
if (!source) {
entryChunkModule = omit(entryChunkModule, 'code');
moduleStats = omit(moduleStats, 'code');
}

entryChunk.modules[moduleKey] = entryChunkModule;
chunkModulesStats[bundleModuleFilepath] = moduleStats;
});

output[key] = entryChunk;
chunkStats.modules = chunkModulesStats;

output[bundleEntryFilepath] = chunkStats;

return;
}
Expand Down
39 changes: 39 additions & 0 deletions src/utils/check-exclude-filepath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
type ExcludeFilepathParam = string | RegExp | ((filepath: string) => boolean);

export type ExcludeFilepathPatterns = ExcludeFilepathParam | Array<ExcludeFilepathParam>;

/**
* Check if filepath should be excluded based on patterns
*/
export function checkExcludeFilepath(
filepath: string,
patterns?: ExcludeFilepathPatterns,
): boolean {
if (!patterns) {
return false;
}

if (Array.isArray(patterns)) {
let res = false;

for (let i = 0; i <= patterns.length - 1 && res === false; i++) {
res = checkExcludeFilepath(filepath, patterns[i]);
}

return res;
}

if (typeof patterns === 'function') {
return patterns(filepath);
}

if (typeof patterns === 'string') {
return Boolean(filepath.match(patterns));
}

if ('test' in patterns) {
return patterns.test(filepath);
}

return false;
}
41 changes: 41 additions & 0 deletions test/unit/__snapshots__/extract.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,47 @@ exports[`extract > should extract rollup stats 1`] = `
}
`;

exports[`extract > should extract rollup stats with excluded assets 1`] = `
{
"assets/logo.abcd1234.svg": {
"fileName": "assets/logo.abcd1234.svg",
"type": "asset",
},
"assets/main.abcd1234.js": {
"fileName": "assets/main.abcd1234.js",
"modules": {
"/home/user/project/src/main.js": {},
"/home/user/project/src/utils.js": {},
},
"type": "chunk",
},
}
`;

exports[`extract > should extract rollup stats with excluded modules 1`] = `
{
"assets/logo.abcd1234.svg": {
"fileName": "assets/logo.abcd1234.svg",
"type": "asset",
},
"assets/main.abcd1234.js": {
"fileName": "assets/main.abcd1234.js",
"modules": {
"/home/user/project/src/main.js": {},
},
"type": "chunk",
},
"assets/vendors.abcd1234.js": {
"fileName": "assets/vendors.abcd1234.js",
"modules": {
"/home/user/project/node_modules/package-a/index.js": {},
"/home/user/project/node_modules/package-b/index.js": {},
},
"type": "chunk",
},
}
`;

exports[`extract > should extract rollup stats with sources 1`] = `
{
"assets/logo.abcd1234.svg": {
Expand Down
10 changes: 10 additions & 0 deletions test/unit/extract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,14 @@ describe('extract', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect(extract(rollupStats.stats as any, { source: true })).toMatchSnapshot();
});

test('should extract rollup stats with excluded assets', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect(extract(rollupStats.stats as any, { excludeAssets : /vendors/ })).toMatchSnapshot();
});

test('should extract rollup stats with excluded modules', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expect(extract(rollupStats.stats as any, { excludeModules : /utils.js/ })).toMatchSnapshot();
});
});
44 changes: 44 additions & 0 deletions test/unit/utils/check-exclude-filepath.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, test, expect } from 'vitest';

import { checkExcludeFilepath } from '../../../src/utils/check-exclude-filepath';

describe('utils', () => {
describe('checkExcludeFilepath', () => {
const testCases: Array<{ input: Parameters<typeof checkExcludeFilepath>; output: ReturnType<typeof checkExcludeFilepath>}> = [
{
input: ['./assets/vendor.js'],
output: false,
},
{
input: ['./assets/vendor.js', 'vendor'],
output: true,
},
{
input: ['./assets/vendor.js', 'unknown'],
output: false,
},
{
input: ['./assets/vendor.js', /vendor/],
output: true,
},
{
input: ['./assets/vendor.js', () => true],
output: true,
},
{
input: ['./assets/vendor.js', ['main', /vendor/]],
output: true,
},
{
input: ['./assets/vendor.js', ['main', /unknown/, () => false]],
output: false,
},
];

testCases.forEach(({ input, output }) => {
test(`Should return "${output}" when called with: "${input.join('", "')}"`, () => {
expect(checkExcludeFilepath(...input)).toEqual(output);
});
});
});
});

0 comments on commit e530e13

Please sign in to comment.