Skip to content

Commit 4dd23fd

Browse files
committed
roldown(migration): Solving errors form tests
1 parent ac279fd commit 4dd23fd

File tree

2 files changed

+142
-66
lines changed

2 files changed

+142
-66
lines changed

__tests__/helpers/index.ts

Lines changed: 126 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/* eslint-disable jest/no-export */
2+
// eslint-disable @typescript-eslint/no-unsafe-call
23
import path from "path";
34
import fs from "fs-extra";
4-
import { InputOptions, OutputOptions } from "rollup";
5+
import { InputOptions, OutputOptions, rolldown } from "rolldown";
56

67
import { Options } from "../../src/types";
78

8-
import { rolldown } from 'rolldown'
9-
import nodePolyfills from '@rolldown/plugin-node-polyfills'
9+
import nodePolyfills from "@rolldown/plugin-node-polyfills";
10+
import type { OutputChunk, OutputAsset } from "rolldown";
1011

1112
export interface WriteData {
1213
input: string | string[];
@@ -17,77 +18,140 @@ export interface WriteData {
1718
outputOpts?: OutputOptions;
1819
}
1920

20-
export interface WriteResult {
21+
interface WriteResult {
2122
js: () => Promise<string[]>;
2223
css: () => Promise<string[]>;
23-
isCss: () => Promise<boolean>;
24+
isCss: () => Promise<boolean[]>;
2425
map: () => Promise<string[]>;
25-
isMap: () => Promise<boolean>;
26+
isMap: () => Promise<boolean[]>;
2627
isFile: (file: string) => Promise<boolean>;
2728
}
2829

29-
async function pathExistsAll(files: string[]): Promise<boolean> {
30-
if (files.length === 0) return false;
31-
for await (const file of files) {
32-
const exists = await fs.pathExists(file);
33-
if (!exists) return false;
34-
}
35-
return true;
30+
async function pathExistsAll(paths: string[]): Promise<boolean[]> {
31+
return Promise.all(
32+
paths.map(async p =>
33+
fs
34+
.access(p)
35+
.then(() => true)
36+
.catch(() => false),
37+
),
38+
);
39+
}
40+
// Process output files
41+
function isChunk(f: OutputChunk | OutputAsset): f is OutputChunk {
42+
return f.type === "chunk";
3643
}
3744

38-
export const fixture = (...args: string[]): string =>
39-
path.normalize(path.join(__dirname, "..", "fixtures", ...args));
45+
function isCssAsset(f: OutputAsset): boolean {
46+
return f.fileName.endsWith(".css");
47+
}
4048

41-
export async function write(data: WriteData): Promise<WriteResult> {
42-
const outDir = fixture("dist", data.outDir ?? data.title ?? "");
43-
const input = Array.isArray(data.input) ? data.input.map(i => fixture(i)) : fixture(data.input);
49+
function isSourceMap(f: OutputAsset): boolean {
50+
return f.fileName.endsWith(".css.map");
51+
}
4452

53+
export async function write(data: {
54+
input: string | string[];
55+
outDir?: string;
56+
title?: string;
57+
inputOpts?: Partial<InputOptions>;
58+
outputOpts?: Partial<OutputOptions>;
59+
}): Promise<WriteResult> {
60+
const outDir = path.join("dist", data.outDir ?? data.title ?? "");
61+
const input = Array.isArray(data.input)
62+
? data.input.map(i => path.join(i))
63+
: path.join(data.input);
64+
65+
// Rolldown-specific configuration
4566
const bundle = await rolldown({
46-
// ... other config
4767
input,
68+
platform: "node",
69+
// Merged configuration
70+
...data.inputOpts,
71+
// Rolldown-native options
72+
resolve: {
73+
mainFields: ["module", "main"],
74+
extensions: [".mjs", ".js", ".ts", ".json", ".node"],
75+
},
4876
plugins: [
49-
nodePolyfills({
50-
// Optional configuration
51-
include: ['fs', 'path'], // Only polyfill specific modules
52-
exclude: ['crypto'], // Exclude modules from polyfilling
53-
}),
54-
// ... other plugins
77+
{
78+
name: "json-handler",
79+
transform(code: string, id: string) {
80+
if (id.endsWith(".json")) {
81+
return `export default ${code}`;
82+
}
83+
},
84+
},
85+
{
86+
name: "node-resolve",
87+
resolveId(source: string) {
88+
if (source === "vue" || source.startsWith("@vue/")) {
89+
return { id: source, external: true };
90+
}
91+
},
92+
},
93+
{
94+
name: "css-extract",
95+
transform(code: string, id: string) {
96+
if (id.endsWith(".css")) {
97+
return `export default ${JSON.stringify(code)}`;
98+
}
99+
},
100+
},
101+
nodePolyfills(),
55102
],
56-
platform: 'node' // Important for Node.js polyfilling
57-
})
58-
const { output } = await bundle.write({
59-
...data.outputOpts,
60-
dir: data.outputOpts?.file ? undefined : outDir,
61-
file: data.outputOpts?.file && path.join(outDir, data.outputOpts.file),
103+
104+
treeshake: {
105+
moduleSideEffects: (id: string) =>
106+
id.includes(".css") || id.includes(".vue") || id.includes(".json"),
107+
},
62108
});
63109

64-
const js = output
65-
.filter(f => f.type === "chunk")
110+
// Output handling
111+
const outputConfig = {
112+
dir: outDir,
113+
format: "es" as const,
114+
...(data.outputOpts ?? {}),
115+
};
116+
117+
if (data.outputOpts?.file) {
118+
const { ...rest } = outputConfig;
119+
outputConfig.file = path.join(outDir, data.outputOpts.file);
120+
Object.assign(outputConfig, rest);
121+
}
122+
123+
const { output } = await bundle.write(outputConfig);
124+
125+
const jsFiles = output
126+
.filter((f): f is OutputChunk => isChunk(f))
66127
.map(f => path.join(outDir, f.fileName))
67128
.sort();
68129

69-
const css = output
70-
.filter(f => f.type === "asset" && f.fileName.endsWith(".css"))
130+
const cssFiles = output
131+
.filter((f): f is OutputAsset => !isChunk(f) && isCssAsset(f))
71132
.map(f => path.join(outDir, f.fileName))
72133
.sort();
73134

74-
const map = output
75-
.filter(f => f.type === "asset" && f.fileName.endsWith(".css.map"))
135+
const mapFiles = output
136+
.filter((f): f is OutputAsset => !isChunk(f) && isSourceMap(f))
76137
.map(f => path.join(outDir, f.fileName))
77138
.sort();
78139

79-
const res: WriteResult = {
80-
js: async () => Promise.all(js.map(async f => fs.readFile(f, "utf8"))),
81-
css: async () => Promise.all(css.map(async f => fs.readFile(f, "utf8"))),
82-
isCss: async () => pathExistsAll(css),
83-
map: async () => Promise.all(map.map(async f => fs.readFile(f, "utf8"))),
84-
isMap: async () => pathExistsAll(map),
85-
isFile: async file => fs.pathExists(path.join(outDir, file)),
140+
return {
141+
js: async () => Promise.all(jsFiles.map(async f => fs.readFile(f, "utf8"))),
142+
css: async () => Promise.all(cssFiles.map(async f => fs.readFile(f, "utf8"))),
143+
isCss: async () => pathExistsAll(cssFiles),
144+
map: async () => Promise.all(mapFiles.map(async f => fs.readFile(f, "utf8"))),
145+
isMap: async () => pathExistsAll(mapFiles),
146+
isFile: async (file: string) =>
147+
fs
148+
.access(path.join(outDir, file))
149+
.then(() => true)
150+
.catch(() => false),
86151
};
87-
88-
return res;
89152
}
90153

154+
/////
91155
export interface TestData extends WriteData {
92156
title: string;
93157
files?: string[];
@@ -99,11 +163,25 @@ export function validate(data: TestData): void {
99163
test(data.title, async () => {
100164
if (data.shouldFail) {
101165
// eslint-disable-next-line jest/no-conditional-expect -- helper utility
102-
await expect(write(data)).rejects.toThrowErrorMatchingSnapshot();
166+
await expect(
167+
write({
168+
input: data.input,
169+
outDir: data.outDir,
170+
title: data.title,
171+
inputOpts: data.inputOpts as Partial<InputOptions>,
172+
outputOpts: data.outputOpts as Partial<OutputOptions>,
173+
}),
174+
).rejects.toThrowErrorMatchingSnapshot();
103175
return;
104176
}
105177

106-
const res = await write(data);
178+
const res = await write({
179+
input: data.input,
180+
outDir: data.outDir,
181+
title: data.title,
182+
inputOpts: data.inputOpts as Partial<InputOptions>,
183+
outputOpts: data.outputOpts as Partial<OutputOptions>,
184+
});
107185

108186
for (const f of await res.js()) expect(f).toMatchSnapshot("js");
109187

rolldown.config.js

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
1-
import { rolldown } from 'rolldown'
2-
import nodePolyfills from '@rolldown/plugin-node-polyfills'
3-
// import vue from "rollup-plugin-vue";
4-
5-
export default {
1+
/* eslint node/no-unsupported-features/es-syntax: ["error", { ignores: ["modules"] }] */
2+
// eslint-disable-next-line import/no-named-as-default
3+
export default [
4+
{
65
input: "src/index.ts",
76
output: {
8-
format: 'esm',
9-
dir: 'dist'
10-
// file: 'bundle.js'
7+
format: "esm",
8+
dir: "dist",
119
},
1210
plugins: [
1311
{
14-
name: 'patch-path-imports',
12+
name: "patch-path-imports",
1513
transform(code) {
1614
return code.replace(
17-
/import\s*\{([^}]*)(win32|posix)([^}]*)\}\s*from\s*['"]path['"]/g,
18-
'import { $1 } from "path"'
19-
)
20-
}
21-
}
15+
/import\s*{([^}]*)(win32|posix)([^}]*)}\s*from\s*["']path["']/g,
16+
'import { $1 } from "path"',
17+
);
18+
},
19+
},
2220
],
23-
platform: 'node',
21+
platform: "node",
2422
define: {
25-
'process.env.NODE_ENV': JSON.stringify('production')
23+
"process.env.NODE_ENV": JSON.stringify("production"),
2624
},
27-
}
28-
25+
},
26+
];

0 commit comments

Comments
 (0)