From 2a9c89cab1e8d64a822afec286a63109400faeba Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 16 Sep 2025 19:40:21 +0200 Subject: [PATCH 1/5] chore: add tsdown build --- package-lock.json | 358 ++++++++++++++++++ package.json | 2 + packages/models/project.json | 34 +- packages/models/rolldown.config.mjs | 26 ++ .../scripts/generate-dist-package-json.mjs | 141 +++++++ 5 files changed, 556 insertions(+), 5 deletions(-) create mode 100644 packages/models/rolldown.config.mjs create mode 100755 packages/models/scripts/generate-dist-package-json.mjs diff --git a/package-lock.json b/package-lock.json index 6b81834f4..786ce986c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,6 +101,7 @@ "prettier": "^3.4.1", "react": "18.3.1", "react-dom": "18.3.1", + "rolldown": "^1.0.0-beta.38", "ts-patch": "^3.3.0", "tsconfig-paths": "^4.2.0", "tsx": "^4.19.0", @@ -120,6 +121,7 @@ "@nx/nx-darwin-arm64": "^21.4.1", "@nx/nx-darwin-x64": "^21.4.1", "@nx/nx-linux-x64-gnu": "^21.4.1", + "@rolldown/binding-darwin-arm64": "^1.0.0-beta.38", "@rollup/rollup-darwin-arm64": "^4.0.0", "@rollup/rollup-darwin-x64": "^4.0.0", "@rollup/rollup-linux-x64-gnu": "^4.0.0", @@ -6639,6 +6641,16 @@ "@octokit/openapi-types": "^20.0.0" } }, + "node_modules/@oxc-project/types": { + "version": "0.89.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.89.0.tgz", + "integrity": "sha512-yuo+ECPIW5Q9mSeNmCDC2im33bfKuwW18mwkaHMQh8KakHYDzj4ci/q7wxf2qS3dMlVVCIyrs3kFtH5LmnlYnw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@paulirish/trace_engine": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/@paulirish/trace_engine/-/trace_engine-0.0.32.tgz", @@ -6804,6 +6816,301 @@ "tslib": "2.8.1" } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.38.tgz", + "integrity": "sha512-AE3HFQrjWCKLFZD1Vpiy+qsqTRwwoil1oM5WsKPSmfQ5fif/A+ZtOZetF32erZdsR7qyvns6qHEteEsF6g6rsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.38.tgz", + "integrity": "sha512-RaoWOKc0rrFsVmKOjQpebMY6c6/I7GR1FBc25v7L/R7NlM0166mUotwGEv7vxu7ruXH4SJcFeVrfADFUUXUmmQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.38.tgz", + "integrity": "sha512-Ymojqc2U35iUc8NFU2XX1WQPfBRRHN6xHcrxAf9WS8BFFBn8pDrH5QPvH1tYs3lDkw6UGGbanr1RGzARqdUp1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.38.tgz", + "integrity": "sha512-0ermTQ//WzSI0nOL3z/LUWMNiE9xeM5cLGxjewPFEexqxV/0uM8/lNp9QageQ8jfc/VO1OURsGw34HYO5PaL8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.38.tgz", + "integrity": "sha512-GADxzVUTCTp6EWI52831A29Tt7PukFe94nhg/SUsfkI33oTiNQtPxyLIT/3oRegizGuPSZSlrdBurkjDwxyEUQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.38.tgz", + "integrity": "sha512-SKO7Exl5Yem/OSNoA5uLHzyrptUQ8Hg70kHDxuwEaH0+GUg+SQe9/7PWmc4hFKBMrJGdQtii8WZ0uIz9Dofg5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.38.tgz", + "integrity": "sha512-SOo6+WqhXPBaShLxLT0eCgH17d3Yu1lMAe4mFP0M9Bvr/kfMSOPQXuLxBcbBU9IFM9w3N6qP9xWOHO+oUJvi8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.38.tgz", + "integrity": "sha512-yvsQ3CyrodOX+lcoi+lejZGCOvJZa9xTsNB8OzpMDmHeZq3QzJfpYjXSAS6vie70fOkLVJb77UqYO193Cl8XBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.38.tgz", + "integrity": "sha512-84qzKMwUwikfYeOuJ4Kxm/3z15rt0nFGGQArHYIQQNSTiQdxGHxOkqXtzPFqrVfBJUdxBAf+jYzR1pttFJuWyg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.38.tgz", + "integrity": "sha512-QrNiWlce01DYH0rL8K3yUBu+lNzY+B0DyCbIc2Atan6/S6flxOL0ow5DLQvMamOI/oKhrJ4xG+9MkMb9dDHbLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.38.tgz", + "integrity": "sha512-fnLtHyjwEsG4/aNV3Uv3Qd1ZbdH+CopwJNoV0RgBqrcQB8V6/Qdikd5JKvnO23kb3QvIpP+dAMGZMv1c2PJMzw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.5" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.5.tgz", + "integrity": "sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.38.tgz", + "integrity": "sha512-19cTfnGedem+RY+znA9J6ARBOCEFD4YSjnx0p5jiTm9tR6pHafRfFIfKlTXhun+NL0WWM/M0eb2IfPPYUa8+wg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.38.tgz", + "integrity": "sha512-HcICm4YzFJZV+fI0O0bFLVVlsWvRNo/AB9EfUXvNYbtAxakCnQZ15oq22deFdz6sfi9Y4/SagH2kPU723dhCFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.38.tgz", + "integrity": "sha512-4Qx6cgEPXLb0XsCyLoQcUgYBpfL0sjugftob+zhUH0EOk/NVCAIT+h0NJhY+jn7pFpeKxhNMqhvTNx3AesxIAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.32", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.32.tgz", @@ -26693,6 +27000,57 @@ "node": ">=10.0.0" } }, + "node_modules/rolldown": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.38.tgz", + "integrity": "sha512-58frPNX55Je1YsyrtPJv9rOSR3G5efUZpRqok94Efsj0EUa8dnqJV3BldShyI7A+bVPleucOtzXHwVpJRcR0kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.89.0", + "@rolldown/pluginutils": "1.0.0-beta.38", + "ansis": "^4.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-beta.38", + "@rolldown/binding-darwin-arm64": "1.0.0-beta.38", + "@rolldown/binding-darwin-x64": "1.0.0-beta.38", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.38", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.38", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.38", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.38", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.38", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.38", + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.38", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.38", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.38", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.38", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.38" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", + "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/rolldown/node_modules/ansis": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", + "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/rollup": { "version": "4.48.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.48.0.tgz", diff --git a/package.json b/package.json index 385e84c8c..7188b3d2d 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,7 @@ "prettier": "^3.4.1", "react": "18.3.1", "react-dom": "18.3.1", + "rolldown": "^1.0.0-beta.38", "ts-patch": "^3.3.0", "tsconfig-paths": "^4.2.0", "tsx": "^4.19.0", @@ -126,6 +127,7 @@ "zod2md": "^0.2.4" }, "optionalDependencies": { + "@rolldown/binding-darwin-arm64": "^1.0.0-beta.38", "@esbuild/darwin-arm64": "^0.25.9", "@nx/nx-darwin-arm64": "^21.4.1", "@nx/nx-darwin-x64": "^21.4.1", diff --git a/packages/models/project.json b/packages/models/project.json index 58a71cd27..34c427370 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -11,11 +11,35 @@ "outputs": ["{projectRoot}/docs/models-reference.md"] }, "build": { - "dependsOn": [ - "^build", - "generate-docs", - { "projects": "models-transformers", "target": "build" } - ] + "executor": "nx:run-commands", + "options": { + "command": "npx --yes rolldown -c rolldown.config.mjs", + "cwd": "packages/models" + }, + "inputs": [ + "production", + "^production", + "{projectRoot}/rolldown.config.mjs" + ], + "outputs": ["{projectRoot}/dist"], + "cache": true, + "dependsOn": ["generate-docs", "types"] + }, + "types": { + "executor": "@nx/js:tsc", + "options": { + "outputPath": "{projectRoot}/dist", + "main": "{projectRoot}/src/index.ts", + "tsConfig": "{projectRoot}/tsconfig.lib.json", + "assets": [] + }, + "inputs": [ + "production", + "^production", + "{projectRoot}/tsconfig.lib.json" + ], + "outputs": ["{projectRoot}/dist"], + "cache": true }, "lint": {}, "lint-report": {}, diff --git a/packages/models/rolldown.config.mjs b/packages/models/rolldown.config.mjs new file mode 100644 index 000000000..4fd9a995e --- /dev/null +++ b/packages/models/rolldown.config.mjs @@ -0,0 +1,26 @@ +import { defineConfig } from 'rolldown'; + +export default defineConfig({ + input: 'src/index.ts', + output: [ + { + dir: 'dist', + format: 'es', + sourcemap: true, + preserveModules: true, + preserveModulesRoot: 'src/lib', + entryFileNames: '[name].js', + chunkFileNames: '[name].js', + }, + { + dir: 'dist', + format: 'cjs', + sourcemap: true, + preserveModules: true, + preserveModulesRoot: 'src/lib', + entryFileNames: '[name].cjs', + chunkFileNames: '[name].cjs', + }, + ], + external: ['zod', 'vscode-material-icons'], +}); diff --git a/packages/models/scripts/generate-dist-package-json.mjs b/packages/models/scripts/generate-dist-package-json.mjs new file mode 100755 index 000000000..46f4c1267 --- /dev/null +++ b/packages/models/scripts/generate-dist-package-json.mjs @@ -0,0 +1,141 @@ +#!/usr/bin/env node +import { copyFileSync, readFileSync, writeFileSync } from 'fs'; +import { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const packageJsonPath = join(__dirname, '..', 'package.json'); +const distPackageJsonPath = join(__dirname, '..', 'dist', 'package.json'); +const readmePath = join(__dirname, '..', 'README.md'); +const distReadmePath = join(__dirname, '..', 'dist', 'README.md'); + +// Read the main package.json +const mainPackageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')); + +// Create a simplified package.json for the dist folder +const distPackageJson = { + name: mainPackageJson.name, + version: mainPackageJson.version, + license: mainPackageJson.license, + description: mainPackageJson.description, + homepage: mainPackageJson.homepage, + bugs: mainPackageJson.bugs, + repository: mainPackageJson.repository, + keywords: mainPackageJson.keywords, + publishConfig: mainPackageJson.publishConfig, + type: mainPackageJson.type, + main: './index.cjs', + module: './index.js', + types: './index.d.ts', + exports: { + '.': { + types: './index.d.ts', + import: './index.js', + require: './index.cjs', + }, + './audit': { + types: './audit.d.ts', + import: './audit.js', + require: './audit.cjs', + }, + './audit-output': { + types: './audit-output.d.ts', + import: './audit-output.js', + require: './audit-output.cjs', + }, + './cache-config': { + types: './cache-config.d.ts', + import: './cache-config.js', + require: './cache-config.cjs', + }, + './category-config': { + types: './category-config.d.ts', + import: './category-config.js', + require: './category-config.cjs', + }, + './commit': { + types: './commit.d.ts', + import: './commit.js', + require: './commit.cjs', + }, + './configuration': { + types: './configuration.d.ts', + import: './configuration.js', + require: './configuration.cjs', + }, + './core-config': { + types: './core-config.d.ts', + import: './core-config.js', + require: './core-config.cjs', + }, + './group': { + types: './group.d.ts', + import: './group.js', + require: './group.cjs', + }, + './issue': { + types: './issue.d.ts', + import: './issue.js', + require: './issue.cjs', + }, + './persist-config': { + types: './persist-config.d.ts', + import: './persist-config.js', + require: './persist-config.cjs', + }, + './plugin-config': { + types: './plugin-config.d.ts', + import: './plugin-config.js', + require: './plugin-config.cjs', + }, + './report': { + types: './report.d.ts', + import: './report.js', + require: './report.cjs', + }, + './reports-diff': { + types: './reports-diff.d.ts', + import: './reports-diff.js', + require: './reports-diff.cjs', + }, + './runner-config': { + types: './runner-config.d.ts', + import: './runner-config.js', + require: './runner-config.cjs', + }, + './source': { + types: './source.d.ts', + import: './source.js', + require: './source.cjs', + }, + './table': { + types: './table.d.ts', + import: './table.js', + require: './table.cjs', + }, + './tree': { + types: './tree.d.ts', + import: './tree.js', + require: './tree.cjs', + }, + './upload-config': { + types: './upload-config.d.ts', + import: './upload-config.js', + require: './upload-config.cjs', + }, + }, + sideEffects: false, + dependencies: mainPackageJson.dependencies, +}; + +// Write the dist package.json +writeFileSync( + distPackageJsonPath, + JSON.stringify(distPackageJson, null, 2) + '\n', +); + +// Copy README.md to dist +copyFileSync(readmePath, distReadmePath); + +console.log('✅ Generated dist/package.json successfully'); +console.log('✅ Copied README.md to dist/ successfully'); From 7c118b2fa0cbfd17770d4463cdd65b83b6f8a0c5 Mon Sep 17 00:00:00 2001 From: John Doe Date: Sun, 5 Oct 2025 18:36:32 +0200 Subject: [PATCH 2/5] refactor: add rolldown to all projects --- nx.json | 21 +- packages/ci/rolldown.config.mjs | 7 + packages/cli/rolldown.config.mjs | 7 + packages/core/rolldown.config.mjs | 7 + packages/create-cli/rolldown.config.mjs | 7 + packages/models/project.json | 16 +- packages/models/rolldown.config.mjs | 29 +- packages/nx-plugin/rolldown.config.mjs | 7 + packages/plugin-coverage/rolldown.config.mjs | 7 + packages/plugin-eslint/rolldown.config.mjs | 7 + .../plugin-js-packages/rolldown.config.mjs | 7 + packages/plugin-jsdocs/rolldown.config.mjs | 7 + .../plugin-lighthouse/rolldown.config.mjs | 7 + .../plugin-typescript/rolldown.config.mjs | 7 + packages/utils/rolldown.config.mjs | 7 + rolldown.base.ts | 335 ++++++++++++++++++ testing/test-utils/rolldown.config.mjs | 7 + .../rolldown.config.mjs | 7 + tools/src/rolldown.plugin.md | 107 ++++++ tools/src/rolldown.plugin.mjs | 90 +++++ 20 files changed, 646 insertions(+), 50 deletions(-) create mode 100644 packages/ci/rolldown.config.mjs create mode 100644 packages/cli/rolldown.config.mjs create mode 100644 packages/core/rolldown.config.mjs create mode 100644 packages/create-cli/rolldown.config.mjs create mode 100644 packages/nx-plugin/rolldown.config.mjs create mode 100644 packages/plugin-coverage/rolldown.config.mjs create mode 100644 packages/plugin-eslint/rolldown.config.mjs create mode 100644 packages/plugin-js-packages/rolldown.config.mjs create mode 100644 packages/plugin-jsdocs/rolldown.config.mjs create mode 100644 packages/plugin-lighthouse/rolldown.config.mjs create mode 100644 packages/plugin-typescript/rolldown.config.mjs create mode 100644 packages/utils/rolldown.config.mjs create mode 100644 rolldown.base.ts create mode 100644 testing/test-utils/rolldown.config.mjs create mode 100644 tools/eslint-formatter-multi/rolldown.config.mjs create mode 100644 tools/src/rolldown.plugin.md create mode 100644 tools/src/rolldown.plugin.mjs diff --git a/nx.json b/nx.json index 5f3c675ac..f0bcd1e6c 100644 --- a/nx.json +++ b/nx.json @@ -83,17 +83,15 @@ } }, "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"], "cache": true, - "executor": "@nx/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "{projectRoot}/dist", - "main": "{projectRoot}/src/index.ts", - "tsConfig": "{projectRoot}/tsconfig.lib.json", - "assets": ["{projectRoot}/*.md"] - } + "inputs": [ + "production", + "^production", + { + "externalDependencies": ["rolldown"] + } + ], + "outputs": ["{projectRoot}/dist"] }, "unit-test": { "cache": true, @@ -358,7 +356,8 @@ "filterByTags": ["publishable"] } } - } + }, + "./tools/src/rolldown.plugin.mjs" ], "nxCloudId": "65d4d862d2adb16a45a4bc7c" } diff --git a/packages/ci/rolldown.config.mjs b/packages/ci/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/ci/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/cli/rolldown.config.mjs b/packages/cli/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/cli/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/core/rolldown.config.mjs b/packages/core/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/core/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/create-cli/rolldown.config.mjs b/packages/create-cli/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/create-cli/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/models/project.json b/packages/models/project.json index 34c427370..5c3325f71 100644 --- a/packages/models/project.json +++ b/packages/models/project.json @@ -10,21 +10,7 @@ "inputs": ["production", "^production", "{projectRoot}/zod2md.config.ts"], "outputs": ["{projectRoot}/docs/models-reference.md"] }, - "build": { - "executor": "nx:run-commands", - "options": { - "command": "npx --yes rolldown -c rolldown.config.mjs", - "cwd": "packages/models" - }, - "inputs": [ - "production", - "^production", - "{projectRoot}/rolldown.config.mjs" - ], - "outputs": ["{projectRoot}/dist"], - "cache": true, - "dependsOn": ["generate-docs", "types"] - }, + "build": {}, "types": { "executor": "@nx/js:tsc", "options": { diff --git a/packages/models/rolldown.config.mjs b/packages/models/rolldown.config.mjs index 4fd9a995e..9543b71b9 100644 --- a/packages/models/rolldown.config.mjs +++ b/packages/models/rolldown.config.mjs @@ -1,26 +1,7 @@ -import { defineConfig } from 'rolldown'; +import { baseConfig } from '../../rolldown.base.ts'; -export default defineConfig({ - input: 'src/index.ts', - output: [ - { - dir: 'dist', - format: 'es', - sourcemap: true, - preserveModules: true, - preserveModulesRoot: 'src/lib', - entryFileNames: '[name].js', - chunkFileNames: '[name].js', - }, - { - dir: 'dist', - format: 'cjs', - sourcemap: true, - preserveModules: true, - preserveModulesRoot: 'src/lib', - entryFileNames: '[name].cjs', - chunkFileNames: '[name].cjs', - }, - ], - external: ['zod', 'vscode-material-icons'], +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, }); diff --git a/packages/nx-plugin/rolldown.config.mjs b/packages/nx-plugin/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/nx-plugin/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/plugin-coverage/rolldown.config.mjs b/packages/plugin-coverage/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/plugin-coverage/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/plugin-eslint/rolldown.config.mjs b/packages/plugin-eslint/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/plugin-eslint/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/plugin-js-packages/rolldown.config.mjs b/packages/plugin-js-packages/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/plugin-js-packages/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/plugin-jsdocs/rolldown.config.mjs b/packages/plugin-jsdocs/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/plugin-jsdocs/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/plugin-lighthouse/rolldown.config.mjs b/packages/plugin-lighthouse/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/plugin-lighthouse/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/plugin-typescript/rolldown.config.mjs b/packages/plugin-typescript/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/plugin-typescript/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/packages/utils/rolldown.config.mjs b/packages/utils/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/packages/utils/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/rolldown.base.ts b/rolldown.base.ts new file mode 100644 index 000000000..fb275f856 --- /dev/null +++ b/rolldown.base.ts @@ -0,0 +1,335 @@ +import { readFileSync } from 'node:fs'; +import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { + type OutputOptions, + type RolldownOptions, + defineConfig, +} from 'rolldown'; + +/** + * Reads and parses package.json from a given path + */ +function readPackageJson(packageJsonPath: string): Record | null { + try { + return JSON.parse(readFileSync(packageJsonPath, 'utf8')); + } catch (error) { + return null; + } +} + +/** + * Extracts all dependencies from package.json to use as external dependencies + */ +function getExternalDependenciesFromPackageJson( + packageJson: Record | null, +): string[] { + if (!packageJson) return []; + + const dependencyTypes = [ + 'dependencies', + 'devDependencies', + 'optionalDependencies', + 'peerDependencies', + ] as const; + + return dependencyTypes.flatMap(type => Object.keys(packageJson[type] || {})); +} + +/** + * Gets additional files to copy from package.json files field + */ +function getAdditionalFilesToCopy( + packageJson: Record | null, +): string[] { + if (!packageJson?.files || !Array.isArray(packageJson.files)) { + return []; + } + + return packageJson.files.filter((file: string) => { + // Skip negation patterns (starting with !) + if (file.startsWith('!')) return false; + // Skip 'src' as it's already handled by the build output + if (file === 'src') return false; + // Include specific files (README, LICENSE, etc.) + return !file.includes('*') && !file.includes('/'); + }); +} + +/** + * Copies a file, creating directories as needed + */ +async function safeCopyFile( + sourcePath: string, + destPath: string, + fileName: string, +): Promise { + try { + await mkdir(dirname(destPath), { recursive: true }); + await copyFile(sourcePath, destPath); + } catch (error) { + console.warn(`Failed to copy ${fileName}:`, error); + } +} + +/** + * Updates package.json paths by removing the dist/ prefix + */ +function updatePackageJsonPaths( + packageJson: Record, + hasEsm: boolean, + hasCjs: boolean, +): void { + const pathFields = ['main', 'module', 'types', 'typings'] as const; + + for (const field of pathFields) { + if (packageJson[field]) { + packageJson[field] = packageJson[field].replace(/^dist\//, ''); + // Only adjust main to .cjs for CJS-only builds + if (field === 'main' && hasCjs && !hasEsm) { + packageJson[field] = packageJson[field].replace(/\.js$/, '.cjs'); + } + } + } +} + +/** + * Updates bin field with correct extensions + */ +function updateBinField( + packageJson: Record, + hasEsm: boolean, +): void { + if (!packageJson.bin) return; + + if (typeof packageJson.bin === 'string') { + packageJson.bin = packageJson.bin + .replace(/^dist\//, '') + .replace(/\.js$/, hasEsm ? '.js' : '.cjs'); + } else { + packageJson.bin = Object.fromEntries( + Object.entries(packageJson.bin).map(([name, path]) => [ + name, + (path as string) + .replace(/^dist\//, '') + .replace(/\.js$/, hasEsm ? '.js' : '.cjs'), + ]), + ); + } +} + +/** + * Creates an export entry with the appropriate import/require/types fields + */ +function createExportEntry( + path: string, + hasEsm: boolean, + hasCjs: boolean, +): Record { + const entry: Record = {}; + + if (hasEsm) { + entry.import = path.replace(/\.(cjs|mjs)$/, '.js'); + } + if (hasCjs) { + entry.require = path.replace(/\.(js|mjs)$/, '.cjs'); + } + entry.types = path.replace(/\.(c|m)?js$/, '.d.ts'); + + return entry; +} + +/** + * Generates exports field based on build format + */ +function generateExportsField( + hasEsm: boolean, + hasCjs: boolean, +): Record { + const exportPatterns = { + '.': './src/index.js', + './*': './src/*/index.js', + './*/': './src/*/index.js', + './*.js': './src/*.js', + }; + + return Object.fromEntries( + Object.entries(exportPatterns).map(([key, path]) => [ + key, + createExportEntry(path, hasEsm, hasCjs), + ]), + ); +} + +export interface BaseConfigOptions { + projectRoot: string; + /** + * Entry point pattern or file path + * @default `${projectRoot}/src/index.ts` + */ + entry?: string; + /** + * Root directory for preserving module structure + * @default 'src' + */ + preserveModulesRoot?: string; + /** + * Output directory + * @default `${projectRoot}/dist/src` + */ + outDir?: string; + /** + * Additional external dependencies beyond those in package.json + * @default [] + */ + additionalExternals?: string[]; + /** + * Build formats + * @default ['es'] + */ + formats?: Array<'es' | 'cjs'>; + /** + * Enable sourcemaps + * @default true + */ + sourcemap?: boolean; +} + +export function baseConfig(options: BaseConfigOptions): RolldownOptions { + const { + projectRoot, + entry = `${projectRoot}/src/index.ts`, + preserveModulesRoot = 'src', + outDir = `${projectRoot}/dist/src`, + additionalExternals = [], + formats = ['es'], + sourcemap = true, + } = options; + + // Read package.json to get dependencies and additional files to copy + const packageJsonPath = join(projectRoot, 'package.json'); + const packageJson = readPackageJson(packageJsonPath); + + const externalDeps = getExternalDependenciesFromPackageJson(packageJson); + const additionalCopyFiles = getAdditionalFilesToCopy(packageJson); + + // Always mark node_modules as external to avoid bundling dependencies + const external = [ + ...new Set([...externalDeps, ...additionalExternals]), + /node_modules/, + ]; + + // Create output configurations for each format + const formatExtensions = { es: '.js', cjs: '.cjs' } as const; + + const outputs: OutputOptions[] = formats.map(format => { + const ext = formatExtensions[format]; + return { + dir: outDir, + format, + sourcemap, + preserveModules: true, + preserveModulesRoot, + entryFileNames: `[name]${ext}`, + chunkFileNames: `[name]${ext}`, + }; + }); + + return defineConfig({ + input: entry, + output: outputs.length > 0 ? outputs : undefined, + external, + plugins: [ + // Custom plugin to copy files and modify package.json after build + { + name: 'copy-files-and-update-package-json', + async closeBundle() { + const distRoot = join(projectRoot, 'dist'); + + // Ensure output directories exist + await mkdir(outDir, { recursive: true }); + await mkdir(distRoot, { recursive: true }); + + // Copy standard files and additional files + // For package.json, copy to the dist root for npm publishing compatibility + const filesToCopy = [ + { file: 'package.json', dest: distRoot }, + { file: 'README.md', dest: distRoot }, + ...additionalCopyFiles.map(file => ({ file, dest: distRoot })), + ]; + + await Promise.all( + filesToCopy.map(({ file, dest }) => + safeCopyFile(join(projectRoot, file), join(dest, file), file), + ), + ); + + // Update package.json in dist root + const distPackageJsonPath = join(distRoot, 'package.json'); + try { + const packageJson = JSON.parse( + await readFile(distPackageJsonPath, 'utf8'), + ); + + // Remove fields not needed in published package + const fieldsToRemove = [ + 'devDependencies', + 'scripts', + 'nx', + ] as const; + fieldsToRemove.forEach(field => delete packageJson[field]); + + // Update files field to include built output + if (packageJson.files) { + packageJson.files = packageJson.files.map((file: string) => + file === 'src' ? 'src' : file, + ); + } + + // Detect which formats were built + const hasEsm = formats.includes('es'); + const hasCjs = formats.includes('cjs'); + + // Update paths, bin field, and exports + updatePackageJsonPaths(packageJson, hasEsm, hasCjs); + updateBinField(packageJson, hasEsm); + packageJson.exports = generateExportsField(hasEsm, hasCjs); + + await writeFile( + distPackageJsonPath, + JSON.stringify(packageJson, null, 2) + '\n', + 'utf8', + ); + } catch (error) { + // If package.json doesn't exist in dist, skip modification + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { + console.error('Failed to update package.json:', error); + } + } + }, + }, + ], + }); +} + +export function getProjectNameFromActiveTask(): string { + const projectName = process.env['NX_TASK_TARGET_PROJECT']; + + if (!projectName || typeof projectName !== 'string') { + throw new Error('NX_TASK_TARGET_PROJECT is not set'); + } + + return projectName; +} + +export async function getExternalDependencies(cwd: string): Promise { + try { + const packageJson = JSON.parse( + await readFile(join(cwd, 'package.json'), 'utf8'), + ); + return getExternalDependenciesFromPackageJson(packageJson); + } catch { + // No package.json or unable to read it - return empty array + return []; + } +} diff --git a/testing/test-utils/rolldown.config.mjs b/testing/test-utils/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/testing/test-utils/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/tools/eslint-formatter-multi/rolldown.config.mjs b/tools/eslint-formatter-multi/rolldown.config.mjs new file mode 100644 index 000000000..9543b71b9 --- /dev/null +++ b/tools/eslint-formatter-multi/rolldown.config.mjs @@ -0,0 +1,7 @@ +import { baseConfig } from '../../rolldown.base.ts'; + +const projectRoot = import.meta.dirname; + +export default baseConfig({ + projectRoot, +}); diff --git a/tools/src/rolldown.plugin.md b/tools/src/rolldown.plugin.md new file mode 100644 index 000000000..18da7b13d --- /dev/null +++ b/tools/src/rolldown.plugin.md @@ -0,0 +1,107 @@ +# Rolldown Nx Plugin + +An Nx plugin that automatically integrates Rolldown into your build process. + +## Features + +- **Auto-discovery**: Automatically detects projects with `rolldown.config.ts`, `rolldown.config.js`, or `rolldown.config.mjs` files +- **Caching**: Full support for Nx caching to speed up builds +- **Project validation**: Only adds build targets to valid projects (with `package.json` or `project.json`) +- **Dependency tracking**: Properly tracks Rolldown and tsx as external dependencies + +## Installation + +Add the plugin to your `nx.json`: + +```json +{ + "plugins": ["./tools/src/rolldown.plugin.ts"] +} +``` + +Or with custom options: + +```json +{ + "plugins": [ + { + "plugin": "./tools/src/rolldown.plugin.ts", + "options": { + "targetName": "build" + } + } + ] +} +``` + +## Options + +| Option | Type | Default | Description | +| ------------ | -------- | ------- | ---------------------------------- | +| `targetName` | `string` | `build` | Name of the build target to create | + +## Usage + +Once configured, the plugin will automatically create build targets for any project containing a Rolldown config file. + +### Running builds + +```bash +# Build a specific project +nx build my-package + +# Build all projects with Rolldown configs +nx run-many --target=build --all +``` + +### Example project structure + +``` +packages/ + my-package/ + src/ + index.ts + rolldown.config.mjs + package.json +``` + +With the plugin configured, you can run: + +```bash +nx build my-package +``` + +## How it works + +The plugin: + +1. Scans your workspace for `rolldown.config.{ts,js,mjs}` files +2. Validates that the directory contains a valid project +3. Creates a build target using Rolldown's native CLI +4. Configures caching with appropriate inputs and outputs + +The plugin uses the Rolldown CLI directly with the `-c` flag to specify the config file, as documented in the [Rolldown Getting Started guide](https://rolldown.rs/guide/getting-started) + +## Integration with base config + +Works seamlessly with the `rolldown.base.ts` configuration: + +```javascript +// packages/my-package/rolldown.config.mjs +import { baseConfig } from '../../rolldown.base.ts'; + +export default baseConfig({ + projectRoot: import.meta.dirname, + preserveModulesRoot: 'src/lib', +}); +``` + +## Caching + +The plugin is configured with: + +- **Inputs**: `production` files and dependencies +- **Outputs**: `{projectRoot}/dist` directory +- **External dependencies**: `rolldown` and `tsx` + +This ensures that builds are only re-run when source files or dependencies change. diff --git a/tools/src/rolldown.plugin.mjs b/tools/src/rolldown.plugin.mjs new file mode 100644 index 000000000..6113b5398 --- /dev/null +++ b/tools/src/rolldown.plugin.mjs @@ -0,0 +1,90 @@ +import { existsSync } from 'node:fs'; +import { dirname, join } from 'node:path'; + +const ROLLDOWN_CONFIG_GLOB = '**/rolldown.config.{ts,js,mjs}'; + +/** + * Nx plugin to integrate Rolldown into the build process. + * + * @example + * ```json + * { + * "plugins": ["./tools/src/rolldown.plugin.mjs"] + * } + * ``` + * This will automatically add a build target to any project containing a `rolldown.config.ts`, `rolldown.config.js`, or `rolldown.config.mjs` file. + */ +const createNodesV2 = [ + ROLLDOWN_CONFIG_GLOB, + async (configFiles, options, context) => { + return await Promise.all( + configFiles.map(async configFile => { + const projectRoot = dirname(configFile); + const normalizedProjectRoot = projectRoot === '.' ? '' : projectRoot; + + // Check if this is a valid project (has package.json or project.json) + const hasPackageJson = existsSync( + join(context.workspaceRoot, projectRoot, 'package.json'), + ); + const hasProjectJson = existsSync( + join(context.workspaceRoot, projectRoot, 'project.json'), + ); + + if (!hasPackageJson && !hasProjectJson) { + return [configFile, { projects: {} }]; + } + + const targetName = options?.targetName ?? 'build'; + + const targets = { + [targetName]: createRolldownBuildTarget({ projectRoot }), + }; + + const result = { + projects: { + [normalizedProjectRoot]: { + targets, + }, + }, + }; + + return [configFile, result]; + }), + ); + }, +]; + +function createRolldownBuildTarget(options) { + const { projectRoot } = options; + + return { + dependsOn: ['^build'], + executor: 'nx:run-commands', + options: { + command: 'rolldown -c rolldown.config.mjs', + cwd: projectRoot, + outputPath: '{projectRoot}/dist', + }, + cache: true, + inputs: [ + 'production', + '^production', + { + externalDependencies: ['rolldown'], + }, + ], + outputs: ['{projectRoot}/dist'], + metadata: { + description: 'Build the project using Rolldown', + technologies: ['rolldown'], + }, + }; +} + +// Default export for nx.json plugins +const plugin = { + name: '@code-pushup/rolldown-plugin', + createNodesV2, +}; + +export default plugin; From 5c60ec8d5db5957ee9245a977a463c5b96a42cba Mon Sep 17 00:00:00 2001 From: John Doe Date: Sun, 5 Oct 2025 21:22:00 +0200 Subject: [PATCH 3/5] refactor: cfg rolldown --- rolldown.base.ts | 77 ++++++++++++++++++------------ tools/src/rolldown.plugin.ts | 92 ++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 tools/src/rolldown.plugin.ts diff --git a/rolldown.base.ts b/rolldown.base.ts index fb275f856..de9484a17 100644 --- a/rolldown.base.ts +++ b/rolldown.base.ts @@ -73,7 +73,7 @@ async function safeCopyFile( } /** - * Updates package.json paths by removing the dist/ prefix + * Updates package.json paths by removing the dist/ and src/ prefixes */ function updatePackageJsonPaths( packageJson: Record, @@ -84,7 +84,9 @@ function updatePackageJsonPaths( for (const field of pathFields) { if (packageJson[field]) { - packageJson[field] = packageJson[field].replace(/^dist\//, ''); + packageJson[field] = packageJson[field] + .replace(/^(\.\/)?dist\//, './') + .replace(/^(\.\/)?src\//, './'); // Only adjust main to .cjs for CJS-only builds if (field === 'main' && hasCjs && !hasEsm) { packageJson[field] = packageJson[field].replace(/\.js$/, '.cjs'); @@ -94,7 +96,7 @@ function updatePackageJsonPaths( } /** - * Updates bin field with correct extensions + * Updates bin field with correct extensions and paths */ function updateBinField( packageJson: Record, @@ -104,14 +106,16 @@ function updateBinField( if (typeof packageJson.bin === 'string') { packageJson.bin = packageJson.bin - .replace(/^dist\//, '') + .replace(/^(\.\/)?dist\//, './') + .replace(/^(\.\/)?src\//, './') .replace(/\.js$/, hasEsm ? '.js' : '.cjs'); } else { packageJson.bin = Object.fromEntries( Object.entries(packageJson.bin).map(([name, path]) => [ name, (path as string) - .replace(/^dist\//, '') + .replace(/^(\.\/)?dist\//, './') + .replace(/^(\.\/)?src\//, './') .replace(/\.js$/, hasEsm ? '.js' : '.cjs'), ]), ); @@ -147,10 +151,10 @@ function generateExportsField( hasCjs: boolean, ): Record { const exportPatterns = { - '.': './src/index.js', - './*': './src/*/index.js', - './*/': './src/*/index.js', - './*.js': './src/*.js', + '.': './index.js', + './*': './*/index.js', + './*/': './*/index.js', + './*.js': './*.js', }; return Object.fromEntries( @@ -175,7 +179,7 @@ export interface BaseConfigOptions { preserveModulesRoot?: string; /** * Output directory - * @default `${projectRoot}/dist/src` + * @default `${projectRoot}/dist` */ outDir?: string; /** @@ -200,7 +204,7 @@ export function baseConfig(options: BaseConfigOptions): RolldownOptions { projectRoot, entry = `${projectRoot}/src/index.ts`, preserveModulesRoot = 'src', - outDir = `${projectRoot}/dist/src`, + outDir = `${projectRoot}/dist`, additionalExternals = [], formats = ['es'], sourcemap = true, @@ -240,32 +244,48 @@ export function baseConfig(options: BaseConfigOptions): RolldownOptions { output: outputs.length > 0 ? outputs : undefined, external, plugins: [ + // Plugin to transform relative paths to package.json + { + name: 'transform-package-json-paths', + transform(code, id) { + // Transform relative paths to package.json by removing one ../ level + // This is needed because we build to dist/ instead of dist/src/ + if (code.includes('package.json')) { + // Match any number of ../ and reduce by one level + return code.replace( + /(['"`])((?:\.\.\/)+)(package\.json)\1/g, + (match, quote, dots, file) => { + // Remove one ../ from the path + const newDots = dots.replace(/\.\.\//, ''); + return `${quote}${newDots}${file}${quote}`; + }, + ); + } + return null; + }, + }, // Custom plugin to copy files and modify package.json after build { name: 'copy-files-and-update-package-json', async closeBundle() { - const distRoot = join(projectRoot, 'dist'); - - // Ensure output directories exist + // Ensure output directory exists await mkdir(outDir, { recursive: true }); - await mkdir(distRoot, { recursive: true }); - // Copy standard files and additional files - // For package.json, copy to the dist root for npm publishing compatibility + // Copy standard files and additional files to dist root const filesToCopy = [ - { file: 'package.json', dest: distRoot }, - { file: 'README.md', dest: distRoot }, - ...additionalCopyFiles.map(file => ({ file, dest: distRoot })), + 'package.json', + 'README.md', + ...additionalCopyFiles, ]; await Promise.all( - filesToCopy.map(({ file, dest }) => - safeCopyFile(join(projectRoot, file), join(dest, file), file), + filesToCopy.map(file => + safeCopyFile(join(projectRoot, file), join(outDir, file), file), ), ); - // Update package.json in dist root - const distPackageJsonPath = join(distRoot, 'package.json'); + // Update package.json in dist + const distPackageJsonPath = join(outDir, 'package.json'); try { const packageJson = JSON.parse( await readFile(distPackageJsonPath, 'utf8'), @@ -279,12 +299,9 @@ export function baseConfig(options: BaseConfigOptions): RolldownOptions { ] as const; fieldsToRemove.forEach(field => delete packageJson[field]); - // Update files field to include built output - if (packageJson.files) { - packageJson.files = packageJson.files.map((file: string) => - file === 'src' ? 'src' : file, - ); - } + // Remove files field to include all built output + // (npm will include everything in dist except what's in .npmignore) + delete packageJson.files; // Detect which formats were built const hasEsm = formats.includes('es'); diff --git a/tools/src/rolldown.plugin.ts b/tools/src/rolldown.plugin.ts new file mode 100644 index 000000000..0533b088d --- /dev/null +++ b/tools/src/rolldown.plugin.ts @@ -0,0 +1,92 @@ +import { existsSync } from 'node:fs'; +import { dirname, join } from 'node:path'; + +const ROLLDOWN_CONFIG_GLOB = '**/rolldown.config.{ts,js,mjs}'; + +/** + * Nx plugin to integrate Rolldown into the build process. + * + * @example + * ```json + * { + * "plugins": ["./tools/src/rolldown.plugin.ts"] + * } + * ``` + * This will automatically add a build target to any project containing a `rolldown.config.ts`, `rolldown.config.js`, or `rolldown.config.mjs` file. + */ +const createNodesV2 = [ + ROLLDOWN_CONFIG_GLOB, + async (configFiles, options, context) => { + return await Promise.all( + configFiles.map(async configFile => { + const projectRoot = dirname(configFile); + const normalizedProjectRoot = projectRoot === '.' ? '' : projectRoot; + + // Check if this is a valid project (has package.json or project.json) + const hasPackageJson = existsSync( + join(context.workspaceRoot, projectRoot, 'package.json'), + ); + const hasProjectJson = existsSync( + join(context.workspaceRoot, projectRoot, 'project.json'), + ); + + if (!hasPackageJson && !hasProjectJson) { + return [configFile, { projects: {} }]; + } + + const targetName = options?.targetName ?? 'build'; + + const targets = { + [targetName]: createRolldownBuildTarget(configFile, projectRoot), + }; + + const result = { + projects: { + [normalizedProjectRoot]: { + targets, + }, + }, + }; + + return [configFile, result]; + }), + ); + }, +]; + +function createRolldownBuildTarget(configFile, projectRoot) { + // Extract just the config filename from the path + const configFileName = configFile.split('/').pop(); + + return { + dependsOn: ['^build'], + executor: 'nx:run-commands', + options: { + command: `rolldown -c ${configFileName}`, + cwd: projectRoot, + // needed for nx-verdaccio + outputPath: '{projectRoot}/dist', + }, + cache: true, + inputs: [ + 'production', + '^production', + { + externalDependencies: ['rolldown'], + }, + ], + outputs: ['{projectRoot}/dist'], + metadata: { + description: 'Build the project using Rolldown', + technologies: ['rolldown'], + }, + }; +} + +// Default export for nx.json plugins +const plugin = { + name: '@code-pushup/rolldown-plugin', + createNodesV2, +}; + +export default plugin; From c68258a6cedcc0f62a3d96342078296d0c73140c Mon Sep 17 00:00:00 2001 From: John Doe Date: Sun, 5 Oct 2025 21:34:00 +0200 Subject: [PATCH 4/5] refactor: cfg rolldown 2 --- eslint.config.js | 1 + nx.json | 2 +- packages/plugin-coverage/package.json | 2 +- packages/plugin-coverage/rolldown.config.mjs | 1 + packages/plugin-js-packages/package.json | 2 +- packages/plugin-js-packages/rolldown.config.mjs | 1 + packages/utils/src/lib/file-system.ts | 11 ++++++++++- rolldown.base.ts | 7 +++++-- 8 files changed, 21 insertions(+), 6 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index c25afb9dc..f1cd3104e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -27,6 +27,7 @@ export default tseslint.config( allow: [ String.raw`^.*/eslint(\.base)?\.config\.[cm]?js$`, String.raw`^.*/code-pushup\.(config|preset)(\.m?[jt]s)?$`, + String.raw`^.*/rolldown(\.base)?\.config\.[cm]?js$`, '^[./]+/tools/.*$', ], depConstraints: [ diff --git a/nx.json b/nx.json index 97f79115e..9b708339d 100644 --- a/nx.json +++ b/nx.json @@ -75,7 +75,7 @@ "--max-warnings=0", "--no-warn-ignored", "--error-on-unmatched-pattern=false", - "--format=./tools/eslint-formatter-multi/dist/src/index.js" + "--format=./tools/eslint-formatter-multi/dist/index.js" ], "env": { "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" diff --git a/packages/plugin-coverage/package.json b/packages/plugin-coverage/package.json index 2eb258029..9fc78f6ad 100644 --- a/packages/plugin-coverage/package.json +++ b/packages/plugin-coverage/package.json @@ -58,7 +58,7 @@ } }, "files": [ - "src", + "dist", "!**/*.tsbuildinfo" ] } diff --git a/packages/plugin-coverage/rolldown.config.mjs b/packages/plugin-coverage/rolldown.config.mjs index 9543b71b9..c8aae84c5 100644 --- a/packages/plugin-coverage/rolldown.config.mjs +++ b/packages/plugin-coverage/rolldown.config.mjs @@ -4,4 +4,5 @@ const projectRoot = import.meta.dirname; export default baseConfig({ projectRoot, + entry: [`${projectRoot}/src/index.ts`, `${projectRoot}/src/bin.ts`], }); diff --git a/packages/plugin-js-packages/package.json b/packages/plugin-js-packages/package.json index da7008b30..0c2ae29c9 100644 --- a/packages/plugin-js-packages/package.json +++ b/packages/plugin-js-packages/package.json @@ -45,7 +45,7 @@ "zod": "^4.0.5" }, "files": [ - "src", + "dist", "!**/*.tsbuildinfo" ] } diff --git a/packages/plugin-js-packages/rolldown.config.mjs b/packages/plugin-js-packages/rolldown.config.mjs index 9543b71b9..c8aae84c5 100644 --- a/packages/plugin-js-packages/rolldown.config.mjs +++ b/packages/plugin-js-packages/rolldown.config.mjs @@ -4,4 +4,5 @@ const projectRoot = import.meta.dirname; export default baseConfig({ projectRoot, + entry: [`${projectRoot}/src/index.ts`, `${projectRoot}/src/bin.ts`], }); diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index 268eed737..ffb2e17a6 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -2,6 +2,7 @@ import { bold, gray } from 'ansis'; import { type Options, bundleRequire } from 'bundle-require'; import { mkdir, readFile, readdir, rm, stat } from 'node:fs/promises'; import path from 'node:path'; +import { pathToFileURL } from 'node:url'; import type { Format, PersistConfig } from '@code-pushup/models'; import { formatBytes } from './formatting.js'; import { logMultipleResults } from './log-results.js'; @@ -77,7 +78,15 @@ export function logMultipleFileResults( } export async function importModule(options: Options): Promise { - const { mod } = await bundleRequire(options); + // Convert filepath to URL for proper ESM loading on Windows + const filepath = path.isAbsolute(options.filepath) + ? pathToFileURL(options.filepath).toString() + : options.filepath; + + const { mod } = await bundleRequire({ + ...options, + filepath, + }); if (typeof mod === 'object' && 'default' in mod) { return mod.default as T; diff --git a/rolldown.base.ts b/rolldown.base.ts index de9484a17..8cc110fd1 100644 --- a/rolldown.base.ts +++ b/rolldown.base.ts @@ -168,10 +168,13 @@ function generateExportsField( export interface BaseConfigOptions { projectRoot: string; /** - * Entry point pattern or file path + * Entry point pattern or file path. Can be: + * - A string for a single entry point + * - An array of strings for multiple entry points + * - An object mapping entry names to file paths * @default `${projectRoot}/src/index.ts` */ - entry?: string; + entry?: string | string[] | Record; /** * Root directory for preserving module structure * @default 'src' From 87adb1c8dc51b08d0a8940950712a32f6b76c621 Mon Sep 17 00:00:00 2001 From: John Doe Date: Sun, 5 Oct 2025 21:53:37 +0200 Subject: [PATCH 5/5] refactor: cfg rolldown 3 --- packages/utils/src/lib/file-system.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index ffb2e17a6..268eed737 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -2,7 +2,6 @@ import { bold, gray } from 'ansis'; import { type Options, bundleRequire } from 'bundle-require'; import { mkdir, readFile, readdir, rm, stat } from 'node:fs/promises'; import path from 'node:path'; -import { pathToFileURL } from 'node:url'; import type { Format, PersistConfig } from '@code-pushup/models'; import { formatBytes } from './formatting.js'; import { logMultipleResults } from './log-results.js'; @@ -78,15 +77,7 @@ export function logMultipleFileResults( } export async function importModule(options: Options): Promise { - // Convert filepath to URL for proper ESM loading on Windows - const filepath = path.isAbsolute(options.filepath) - ? pathToFileURL(options.filepath).toString() - : options.filepath; - - const { mod } = await bundleRequire({ - ...options, - filepath, - }); + const { mod } = await bundleRequire(options); if (typeof mod === 'object' && 'default' in mod) { return mod.default as T;