Skip to content

Commit 8786ec2

Browse files
authored
feat: Add Rollup Version of the Plugin (#6)
Add in initial support for generating stats json for rollup.
1 parent ef3d6fc commit 8786ec2

File tree

7 files changed

+164
-135
lines changed

7 files changed

+164
-135
lines changed

bundlers/rollup/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"author": "",
1414
"license": "ISC",
1515
"dependencies": {
16+
"@codecov/rollup-plugin": "workspace:^",
1617
"date-fns": "^2.16.1"
1718
},
1819
"devDependencies": {
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
import resolve from "@rollup/plugin-node-resolve";
22
import commonjs from "@rollup/plugin-commonjs";
33
import { terser } from "rollup-plugin-terser";
4+
import { codecovRollupPlugin } from "@codecov/rollup-plugin";
5+
import { defineConfig } from "rollup";
46

57
// `npm run build` -> `production` is true
68
// `npm run dev` -> `production` is false
79
const production = !process.env.ROLLUP_WATCH;
810

9-
export default {
11+
export default defineConfig({
1012
input: "src/main.js",
1113
output: {
12-
dir: 'dist',
14+
dir: "dist",
1315
format: "iife", // immediately-invoked function expression — suitable for <script> tags
1416
sourcemap: true,
15-
1617
},
1718
plugins: [
1819
resolve(), // tells Rollup how to find date-fns in node_modules
1920
commonjs(), // converts date-fns to ES modules
2021
production && terser(), // minify, but only in production
22+
codecovRollupPlugin({ enableBundleAnalysis: true }),
2123
],
22-
};
24+
});

packages/bundler-plugin-core/src/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface Asset {
1313

1414
export interface Chunk {
1515
id: string;
16-
preliminaryFileName: string;
16+
uniqueId: string;
1717
entry: boolean;
1818
initial: boolean;
1919
files: string[];
@@ -24,7 +24,7 @@ export interface Module {
2424
name: string;
2525
size?: number;
2626
chunks: (string | number)[];
27-
chunkPreliminaryFileNames: string[];
27+
chunkUniqueIds: string[];
2828
}
2929

3030
export interface Output {

packages/rollup-plugin/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,8 @@
4545
},
4646
"engines": {
4747
"node": ">=20.0.0"
48+
},
49+
"dependencies": {
50+
"@codecov/bundler-plugin-core": "workspace:^"
4851
}
4952
}

packages/rollup-plugin/src/index.ts

Lines changed: 137 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,149 @@
1-
import { type Plugin } from "rollup";
21
import path from "node:path";
3-
4-
export interface Asset {
5-
name: string;
6-
size: number;
7-
}
8-
9-
export interface Chunk {
10-
id: string;
11-
entry: boolean;
12-
initial: boolean;
13-
files: string[];
14-
names: string[];
15-
}
16-
17-
export interface Module {
18-
name: string;
19-
size?: number;
20-
chunks: (string | number)[];
21-
}
2+
import {
3+
codecovUnpluginFactory,
4+
type Asset,
5+
type Chunk,
6+
type Module,
7+
type Options,
8+
} from "@codecov/bundler-plugin-core";
229

2310
export interface BundleTransformOptions {
2411
fileName?: string;
2512
moduleOriginalSize?: boolean;
2613
}
2714

28-
export const rollupStatsPlugin = (
29-
customOptions: BundleTransformOptions = {},
30-
): Plugin => ({
31-
name: "rollup-stats-plugin",
32-
generateBundle(_, bundle) {
33-
const options = {
34-
moduleOriginalSize: false,
35-
...customOptions,
36-
};
37-
38-
const assets: Asset[] = [];
39-
const chunks: Chunk[] = [];
40-
41-
const items = Object.values(bundle);
42-
43-
const moduleByFileName = new Map<string, Module>();
44-
45-
for (const item of items) {
46-
if (item?.type === "asset") {
47-
if (typeof item.source === "string") {
48-
const fileName = item?.fileName ?? "";
49-
const size = Buffer.from(item.source).byteLength;
50-
51-
assets.push({
52-
name: fileName,
53-
size: size,
54-
});
55-
} else {
56-
const fileName = item?.fileName ?? "";
57-
const size = item?.source.byteLength;
15+
const codecovUnplugin = codecovUnpluginFactory({
16+
bundleAnalysisUploadPlugin: ({ output, statsFileName }) => {
17+
return {
18+
version: "1",
19+
name: "codecov-rollup-bundle-analysis-plugin",
20+
pluginVersion: "1.0.0",
21+
rollup: {
22+
generateBundle(this, options, bundle) {
23+
const customOptions = {
24+
moduleOriginalSize: false,
25+
...options,
26+
};
27+
28+
const assets: Asset[] = [];
29+
const chunks: Chunk[] = [];
30+
const moduleByFileName = new Map<string, Module>();
31+
const items = Object.values(bundle);
32+
33+
const cwd = process.cwd();
34+
35+
let counter = 0;
36+
for (const item of items) {
37+
if (item?.type === "asset") {
38+
if (typeof item.source === "string") {
39+
const name = item?.name ?? "";
40+
const fileName = item?.fileName ?? "";
41+
const size = Buffer.from(item.source).byteLength;
42+
43+
assets.push({
44+
name: fileName,
45+
size: size,
46+
fileName: name,
47+
});
48+
} else {
49+
const name = item?.name ?? "";
50+
const fileName = item?.fileName ?? "";
51+
const size = item?.source?.byteLength;
52+
53+
assets.push({
54+
name: fileName,
55+
size: size,
56+
fileName: name,
57+
});
58+
}
59+
}
60+
61+
if (item?.type === "chunk") {
62+
const chunkId = item?.name ?? "";
63+
const fileName = item?.fileName ?? "";
64+
const moduleEntries = Object.entries(item?.modules ?? {});
65+
const size = item?.code?.length;
66+
const uniqueId = `${counter}-${chunkId}`;
67+
68+
assets.push({
69+
name: fileName,
70+
size: size,
71+
fileName: chunkId,
72+
});
73+
74+
chunks.push({
75+
id: chunkId,
76+
uniqueId: uniqueId,
77+
entry: item?.isEntry,
78+
initial: item?.isDynamicEntry,
79+
files: [item?.fileName],
80+
names: [item?.name],
81+
});
82+
83+
for (const [modulePath, moduleInfo] of moduleEntries) {
84+
const normalizedModulePath = modulePath.replace("\u0000", "");
85+
const relativeModulePath = path.relative(
86+
cwd,
87+
normalizedModulePath,
88+
);
89+
const relativeModulePathWithPrefix = relativeModulePath.match(
90+
/^\.\./,
91+
)
92+
? relativeModulePath
93+
: `.${path.sep}${relativeModulePath}`;
94+
95+
// try to grab module already set in map
96+
const moduleEntry = moduleByFileName.get(
97+
relativeModulePathWithPrefix,
98+
);
99+
100+
// if the modules exists append chunk ids to the grabbed module
101+
// else create a new module and create a new entry in the map
102+
if (moduleEntry) {
103+
moduleEntry.chunks.push(chunkId);
104+
moduleEntry.chunkUniqueIds.push(uniqueId);
105+
} else {
106+
const size = customOptions.moduleOriginalSize
107+
? moduleInfo.originalLength
108+
: moduleInfo.renderedLength;
109+
110+
const module = {
111+
name: relativeModulePathWithPrefix,
112+
size: size,
113+
chunks: [chunkId],
114+
chunkUniqueIds: [uniqueId],
115+
};
116+
117+
moduleByFileName.set(relativeModulePathWithPrefix, module);
118+
}
119+
}
120+
counter += 1;
121+
}
122+
}
58123

59-
assets.push({
60-
name: fileName,
61-
size: size,
124+
// grab the modules from the map and convert it to an array
125+
const modules = Array.from(moduleByFileName.values());
126+
127+
output.bundler = {
128+
name: "rollup",
129+
version: this.meta.rollupVersion,
130+
};
131+
output.assets = assets;
132+
output.chunks = chunks;
133+
output.modules = modules;
134+
135+
// need to emit the file here as buildEnd is called before generateBundle
136+
this.emitFile({
137+
type: "asset",
138+
fileName: statsFileName ?? "codecov-bundle-stats.json",
139+
source: JSON.stringify(output),
62140
});
63-
}
64-
}
65-
66-
if (item?.type === "chunk") {
67-
const cwd = process.cwd();
68-
const chunkId = item?.name;
69-
const fileName = item?.fileName ?? "";
70-
const moduleEntries = Object.entries(item?.modules ?? {});
71-
const size = Buffer.from(item?.code).byteLength;
72-
73-
assets.push({
74-
name: fileName,
75-
size: size,
76-
});
77-
78-
chunks.push({
79-
id: chunkId,
80-
entry: item?.isEntry,
81-
initial: item?.isDynamicEntry,
82-
files: [item?.fileName],
83-
names: [item?.name],
84-
});
85-
86-
for (const [modulePath, moduleInfo] of moduleEntries) {
87-
const normalizedModulePath = modulePath.replace("\u0000", "");
88-
const relativeModulePath = path.relative(cwd, normalizedModulePath);
89-
const relativeModulePathWithPrefix = relativeModulePath.match(/^\.\./)
90-
? relativeModulePath
91-
: `.${path.sep}${relativeModulePath}`;
92-
93-
const moduleEntry = moduleByFileName.get(
94-
relativeModulePathWithPrefix,
95-
);
96-
97-
if (moduleEntry) {
98-
moduleEntry.chunks.push(chunkId);
99-
} else {
100-
const size = options.moduleOriginalSize
101-
? moduleInfo.originalLength
102-
: moduleInfo.renderedLength;
103-
104-
moduleByFileName.set(relativeModulePathWithPrefix, {
105-
name: relativeModulePathWithPrefix,
106-
size: size,
107-
chunks: [chunkId],
108-
});
109-
}
110-
}
111-
}
112-
}
113-
114-
const modules = Object.values(
115-
Object.fromEntries(moduleByFileName.entries()),
116-
);
117-
118-
const output = {
119-
builtAt: Date.now(),
120-
assets,
121-
chunks,
122-
modules,
141+
},
142+
},
123143
};
124-
125-
this.emitFile({
126-
type: "asset",
127-
fileName: options?.fileName ?? "stats.json",
128-
source: JSON.stringify(output),
129-
});
130144
},
131145
});
146+
147+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
148+
export const codecovRollupPlugin: (options: Options) => any =
149+
codecovUnplugin.rollup;

packages/vite-plugin/src/index.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const codecovUnplugin = codecovUnpluginFactory({
3232

3333
const cwd = process.cwd();
3434

35+
let counter = 0;
3536
for (const item of items) {
3637
if (item?.type === "asset") {
3738
if (typeof item.source === "string") {
@@ -58,23 +59,21 @@ const codecovUnplugin = codecovUnpluginFactory({
5859
}
5960

6061
if (item?.type === "chunk") {
61-
const chunkId = item?.name;
62+
const chunkId = item?.name ?? "";
6263
const fileName = item?.fileName ?? "";
6364
const moduleEntries = Object.entries(item?.modules ?? {});
6465
const size = Buffer.from(item?.code).byteLength;
65-
66-
console.debug("\n");
67-
console.debug(item.preliminaryFileName);
66+
const uniqueId = `${counter}-${chunkId}`;
6867

6968
assets.push({
7069
name: fileName,
7170
size: size,
72-
fileName: item?.name ?? "",
71+
fileName: chunkId,
7372
});
7473

7574
chunks.push({
7675
id: chunkId,
77-
preliminaryFileName: item?.preliminaryFileName,
76+
uniqueId: uniqueId,
7877
entry: item?.isEntry,
7978
initial: item?.isDynamicEntry,
8079
files: [item?.fileName],
@@ -102,9 +101,7 @@ const codecovUnplugin = codecovUnpluginFactory({
102101
// else create a new module and create a new entry in the map
103102
if (moduleEntry) {
104103
moduleEntry.chunks.push(chunkId);
105-
moduleEntry.chunkPreliminaryFileNames.push(
106-
item?.preliminaryFileName,
107-
);
104+
moduleEntry.chunkUniqueIds.push(uniqueId);
108105
} else {
109106
const size = customOptions.moduleOriginalSize
110107
? moduleInfo.originalLength
@@ -114,12 +111,13 @@ const codecovUnplugin = codecovUnpluginFactory({
114111
name: relativeModulePathWithPrefix,
115112
size: size,
116113
chunks: [chunkId],
117-
chunkPreliminaryFileNames: [item?.preliminaryFileName],
114+
chunkUniqueIds: [uniqueId],
118115
};
119116

120117
moduleByFileName.set(relativeModulePathWithPrefix, module);
121118
}
122119
}
120+
counter += 1;
123121
}
124122
}
125123

0 commit comments

Comments
 (0)