Skip to content

Commit 5c60ec8

Browse files
author
John Doe
committed
refactor: cfg rolldown
1 parent 40c56ff commit 5c60ec8

File tree

2 files changed

+139
-30
lines changed

2 files changed

+139
-30
lines changed

rolldown.base.ts

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ async function safeCopyFile(
7373
}
7474

7575
/**
76-
* Updates package.json paths by removing the dist/ prefix
76+
* Updates package.json paths by removing the dist/ and src/ prefixes
7777
*/
7878
function updatePackageJsonPaths(
7979
packageJson: Record<string, any>,
@@ -84,7 +84,9 @@ function updatePackageJsonPaths(
8484

8585
for (const field of pathFields) {
8686
if (packageJson[field]) {
87-
packageJson[field] = packageJson[field].replace(/^dist\//, '');
87+
packageJson[field] = packageJson[field]
88+
.replace(/^(\.\/)?dist\//, './')
89+
.replace(/^(\.\/)?src\//, './');
8890
// Only adjust main to .cjs for CJS-only builds
8991
if (field === 'main' && hasCjs && !hasEsm) {
9092
packageJson[field] = packageJson[field].replace(/\.js$/, '.cjs');
@@ -94,7 +96,7 @@ function updatePackageJsonPaths(
9496
}
9597

9698
/**
97-
* Updates bin field with correct extensions
99+
* Updates bin field with correct extensions and paths
98100
*/
99101
function updateBinField(
100102
packageJson: Record<string, any>,
@@ -104,14 +106,16 @@ function updateBinField(
104106

105107
if (typeof packageJson.bin === 'string') {
106108
packageJson.bin = packageJson.bin
107-
.replace(/^dist\//, '')
109+
.replace(/^(\.\/)?dist\//, './')
110+
.replace(/^(\.\/)?src\//, './')
108111
.replace(/\.js$/, hasEsm ? '.js' : '.cjs');
109112
} else {
110113
packageJson.bin = Object.fromEntries(
111114
Object.entries(packageJson.bin).map(([name, path]) => [
112115
name,
113116
(path as string)
114-
.replace(/^dist\//, '')
117+
.replace(/^(\.\/)?dist\//, './')
118+
.replace(/^(\.\/)?src\//, './')
115119
.replace(/\.js$/, hasEsm ? '.js' : '.cjs'),
116120
]),
117121
);
@@ -147,10 +151,10 @@ function generateExportsField(
147151
hasCjs: boolean,
148152
): Record<string, any> {
149153
const exportPatterns = {
150-
'.': './src/index.js',
151-
'./*': './src/*/index.js',
152-
'./*/': './src/*/index.js',
153-
'./*.js': './src/*.js',
154+
'.': './index.js',
155+
'./*': './*/index.js',
156+
'./*/': './*/index.js',
157+
'./*.js': './*.js',
154158
};
155159

156160
return Object.fromEntries(
@@ -175,7 +179,7 @@ export interface BaseConfigOptions {
175179
preserveModulesRoot?: string;
176180
/**
177181
* Output directory
178-
* @default `${projectRoot}/dist/src`
182+
* @default `${projectRoot}/dist`
179183
*/
180184
outDir?: string;
181185
/**
@@ -200,7 +204,7 @@ export function baseConfig(options: BaseConfigOptions): RolldownOptions {
200204
projectRoot,
201205
entry = `${projectRoot}/src/index.ts`,
202206
preserveModulesRoot = 'src',
203-
outDir = `${projectRoot}/dist/src`,
207+
outDir = `${projectRoot}/dist`,
204208
additionalExternals = [],
205209
formats = ['es'],
206210
sourcemap = true,
@@ -240,32 +244,48 @@ export function baseConfig(options: BaseConfigOptions): RolldownOptions {
240244
output: outputs.length > 0 ? outputs : undefined,
241245
external,
242246
plugins: [
247+
// Plugin to transform relative paths to package.json
248+
{
249+
name: 'transform-package-json-paths',
250+
transform(code, id) {
251+
// Transform relative paths to package.json by removing one ../ level
252+
// This is needed because we build to dist/ instead of dist/src/
253+
if (code.includes('package.json')) {
254+
// Match any number of ../ and reduce by one level
255+
return code.replace(
256+
/(['"`])((?:\.\.\/)+)(package\.json)\1/g,
257+
(match, quote, dots, file) => {
258+
// Remove one ../ from the path
259+
const newDots = dots.replace(/\.\.\//, '');
260+
return `${quote}${newDots}${file}${quote}`;
261+
},
262+
);
263+
}
264+
return null;
265+
},
266+
},
243267
// Custom plugin to copy files and modify package.json after build
244268
{
245269
name: 'copy-files-and-update-package-json',
246270
async closeBundle() {
247-
const distRoot = join(projectRoot, 'dist');
248-
249-
// Ensure output directories exist
271+
// Ensure output directory exists
250272
await mkdir(outDir, { recursive: true });
251-
await mkdir(distRoot, { recursive: true });
252273

253-
// Copy standard files and additional files
254-
// For package.json, copy to the dist root for npm publishing compatibility
274+
// Copy standard files and additional files to dist root
255275
const filesToCopy = [
256-
{ file: 'package.json', dest: distRoot },
257-
{ file: 'README.md', dest: distRoot },
258-
...additionalCopyFiles.map(file => ({ file, dest: distRoot })),
276+
'package.json',
277+
'README.md',
278+
...additionalCopyFiles,
259279
];
260280

261281
await Promise.all(
262-
filesToCopy.map(({ file, dest }) =>
263-
safeCopyFile(join(projectRoot, file), join(dest, file), file),
282+
filesToCopy.map(file =>
283+
safeCopyFile(join(projectRoot, file), join(outDir, file), file),
264284
),
265285
);
266286

267-
// Update package.json in dist root
268-
const distPackageJsonPath = join(distRoot, 'package.json');
287+
// Update package.json in dist
288+
const distPackageJsonPath = join(outDir, 'package.json');
269289
try {
270290
const packageJson = JSON.parse(
271291
await readFile(distPackageJsonPath, 'utf8'),
@@ -279,12 +299,9 @@ export function baseConfig(options: BaseConfigOptions): RolldownOptions {
279299
] as const;
280300
fieldsToRemove.forEach(field => delete packageJson[field]);
281301

282-
// Update files field to include built output
283-
if (packageJson.files) {
284-
packageJson.files = packageJson.files.map((file: string) =>
285-
file === 'src' ? 'src' : file,
286-
);
287-
}
302+
// Remove files field to include all built output
303+
// (npm will include everything in dist except what's in .npmignore)
304+
delete packageJson.files;
288305

289306
// Detect which formats were built
290307
const hasEsm = formats.includes('es');

tools/src/rolldown.plugin.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { existsSync } from 'node:fs';
2+
import { dirname, join } from 'node:path';
3+
4+
const ROLLDOWN_CONFIG_GLOB = '**/rolldown.config.{ts,js,mjs}';
5+
6+
/**
7+
* Nx plugin to integrate Rolldown into the build process.
8+
*
9+
* @example
10+
* ```json
11+
* {
12+
* "plugins": ["./tools/src/rolldown.plugin.ts"]
13+
* }
14+
* ```
15+
* This will automatically add a build target to any project containing a `rolldown.config.ts`, `rolldown.config.js`, or `rolldown.config.mjs` file.
16+
*/
17+
const createNodesV2 = [
18+
ROLLDOWN_CONFIG_GLOB,
19+
async (configFiles, options, context) => {
20+
return await Promise.all(
21+
configFiles.map(async configFile => {
22+
const projectRoot = dirname(configFile);
23+
const normalizedProjectRoot = projectRoot === '.' ? '' : projectRoot;
24+
25+
// Check if this is a valid project (has package.json or project.json)
26+
const hasPackageJson = existsSync(
27+
join(context.workspaceRoot, projectRoot, 'package.json'),
28+
);
29+
const hasProjectJson = existsSync(
30+
join(context.workspaceRoot, projectRoot, 'project.json'),
31+
);
32+
33+
if (!hasPackageJson && !hasProjectJson) {
34+
return [configFile, { projects: {} }];
35+
}
36+
37+
const targetName = options?.targetName ?? 'build';
38+
39+
const targets = {
40+
[targetName]: createRolldownBuildTarget(configFile, projectRoot),
41+
};
42+
43+
const result = {
44+
projects: {
45+
[normalizedProjectRoot]: {
46+
targets,
47+
},
48+
},
49+
};
50+
51+
return [configFile, result];
52+
}),
53+
);
54+
},
55+
];
56+
57+
function createRolldownBuildTarget(configFile, projectRoot) {
58+
// Extract just the config filename from the path
59+
const configFileName = configFile.split('/').pop();
60+
61+
return {
62+
dependsOn: ['^build'],
63+
executor: 'nx:run-commands',
64+
options: {
65+
command: `rolldown -c ${configFileName}`,
66+
cwd: projectRoot,
67+
// needed for nx-verdaccio
68+
outputPath: '{projectRoot}/dist',
69+
},
70+
cache: true,
71+
inputs: [
72+
'production',
73+
'^production',
74+
{
75+
externalDependencies: ['rolldown'],
76+
},
77+
],
78+
outputs: ['{projectRoot}/dist'],
79+
metadata: {
80+
description: 'Build the project using Rolldown',
81+
technologies: ['rolldown'],
82+
},
83+
};
84+
}
85+
86+
// Default export for nx.json plugins
87+
const plugin = {
88+
name: '@code-pushup/rolldown-plugin',
89+
createNodesV2,
90+
};
91+
92+
export default plugin;

0 commit comments

Comments
 (0)