Skip to content

feat!: migrate from unbuild to rolldown#751

Open
DamianGlowala wants to merge 9 commits into
mainfrom
feat/unbuild-to-rolldown
Open

feat!: migrate from unbuild to rolldown#751
DamianGlowala wants to merge 9 commits into
mainfrom
feat/unbuild-to-rolldown

Conversation

@DamianGlowala
Copy link
Copy Markdown
Member

@DamianGlowala DamianGlowala commented Jun 4, 2026

🔗 Linked issue

resolves #726

📚 Description

This is an initial attempt (WIP) to migrate from unbuild to rolldown (both for building this module and userland ones), so that the modules ecosystem can start preparing for Nuxt 5.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates the module-builder project from unbuild to rolldown. It removes the unbuild build config, adds rolldown.config.ts, updates package.json scripts and dependencies (including Node engine bump), and replaces the build command with a rolldown-based pipeline that infers entries, compiles runtime assets, emits .mjs bundles and DTS, and writes module metadata. Tests and snapshots were updated to reflect new export shapes, Vue type import paths, and builder metadata/versioning.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description is related to the changeset, referencing the linked issue #726 and explaining the migration from unbuild to rolldown as preparation for Nuxt 5.
Linked Issues check ✅ Passed Issue #726 requested migration of module-builder to newer tooling. This PR implements a migration from unbuild to rolldown, which addresses the core request in the issue.
Out of Scope Changes check ✅ Passed All changes are scoped to the unbuild-to-rolldown migration: configuration files (build.config.ts→rolldown.config.ts), package.json dependencies/scripts, build command implementation, and test snapshots reflecting new output format.
Title check ✅ Passed The title clearly and specifically describes the main change: migrating the build system from unbuild to rolldown, which is the central objective across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/unbuild-to-rolldown

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/commands/build.ts`:
- Around line 54-56: The early returns in the stub-path (calls to buildStub)
skip the dist cleanup and type-shim generation; remove the immediate returns
after buildStub calls (e.g., the if (context.args.stub) { await buildStub(cwd,
distDir, moduleEntries); return } blocks) and instead let execution continue so
the existing dist cleanup logic and writeTypes(distDir, true) run; ensure every
place that calls buildStub (referenced by buildStub, context.args.stub, distDir,
writeTypes) does not short-circuit the flow and still triggers the cleanup and
writeTypes invocation (apply the same change to the other stub occurrences
mentioned).
- Around line 110-112: The current logic that builds moduleInput from
moduleEntries uses basename(filename) and drops the export subpath, causing
collisions (e.g., ./dist/utils/index.mjs → dist/index.mjs); update the mapping
in inferModuleEntries (and the other similar spots noted) so the entry name
preserves the export subpath by extracting and using the capture group
(match[1]) from the path pattern (e.g., from "./dist/<subpath>.mjs") when
present, falling back to basename(filename(e), extname(e)) only if match[1] is
undefined; apply the same change where module entries are collected so
functions/variables like moduleEntries, moduleInput, filename(), basename(),
extname(), and any regex match usage consistently use the preserved subpath as
the key.
- Around line 79-83: The runtime file discovery currently only searches for .ts
and .tsx via the glob call that sets runtimeTsFiles; update that glob pattern to
include .mts (e.g. '**/*.{ts,tsx,mts}') and also extend the ignore patterns to
exclude stories/tests for .mts (e.g. add .mts to '**/*.stories.{ts,tsx}' and
'**/*.{spec,test}.{ts,tsx}'), so runtime .mts sources are discovered and the
test/story exclusions still apply.

In `@test/build.spec.ts`:
- Line 139: The inline snapshot assertion on runtimeImport!.code.trim() contains
unnecessary escaped quotes (\"), triggering no-useless-escape; update the
snapshot string so it contains normal double quotes without backslashes (e.g.,
import { SharedTypeFromRuntime } from "./runtime/plugins/plugin.js";) so the
inline snapshot matches the actual trimmed code and removes the redundant
escapes in the expect(...).toMatchInlineSnapshot call.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 74208684-8aeb-4ba3-879b-a88e1f323d35

📥 Commits

Reviewing files that changed from the base of the PR and between 1e58fb0 and bbddc12.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • build.config.ts
  • package.json
  • rolldown.config.ts
  • src/commands/build.ts
  • test/__snapshots__/JsxComponent.d.ts
  • test/__snapshots__/JsxComponent.js
  • test/__snapshots__/TestMe.vue
  • test/__snapshots__/TestMe.vue.d.ts
  • test/__snapshots__/TestMeSetup.d.vue.ts
  • test/__snapshots__/TestMeSetup.vue
  • test/__snapshots__/TestMeSetup.vue.d.ts
  • test/build.spec.ts
💤 Files with no reviewable changes (1)
  • build.config.ts

Comment thread src/commands/build.ts
Comment thread src/commands/build.ts
Comment on lines +79 to +83
const runtimeTsFiles = await glob('**/*.{ts,tsx}', {
cwd: srcRuntimeDir,
absolute: true,
ignore: ['**/*.stories.{ts,tsx}', '**/*.{spec,test}.{ts,tsx}'],
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Runtime discovery skips .mts files.

The runtime glob only includes .ts and .tsx, so src/runtime/**/*.mts sources are never built even though the rest of the command already supports .mts elsewhere.

💡 Suggested fix
-      const runtimeTsFiles = await glob('**/*.{ts,tsx}', {
+      const runtimeTsFiles = await glob('**/*.{ts,tsx,mts}', {
         cwd: srcRuntimeDir,
         absolute: true,
-        ignore: ['**/*.stories.{ts,tsx}', '**/*.{spec,test}.{ts,tsx}'],
+        ignore: ['**/*.stories.{ts,tsx,mts}', '**/*.{spec,test}.{ts,tsx,mts}'],
       })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const runtimeTsFiles = await glob('**/*.{ts,tsx}', {
cwd: srcRuntimeDir,
absolute: true,
ignore: ['**/*.stories.{ts,tsx}', '**/*.{spec,test}.{ts,tsx}'],
})
const runtimeTsFiles = await glob('**/*.{ts,tsx,mts}', {
cwd: srcRuntimeDir,
absolute: true,
ignore: ['**/*.stories.{ts,tsx,mts}', '**/*.{spec,test}.{ts,tsx,mts}'],
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/build.ts` around lines 79 - 83, The runtime file discovery
currently only searches for .ts and .tsx via the glob call that sets
runtimeTsFiles; update that glob pattern to include .mts (e.g.
'**/*.{ts,tsx,mts}') and also extend the ignore patterns to exclude
stories/tests for .mts (e.g. add .mts to '**/*.stories.{ts,tsx}' and
'**/*.{spec,test}.{ts,tsx}'), so runtime .mts sources are discovered and the
test/story exclusions still apply.

Comment thread src/commands/build.ts
Comment on lines +110 to +112
const moduleInput = Object.fromEntries(
moduleEntries.map(e => [filename(e) || basename(e, extname(e)), e]),
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Preserve the export subpath when deriving entry names.

inferModuleEntries() drops the ./dist/... portion and both build paths reconstruct names from basename(). An export like ./dist/utils/index.mjs will now emit dist/index.mjs, and two exports with the same leaf filename will collide. That breaks package.json#exports for nested subpaths.

💡 Suggested direction
-type ModuleEntry = string
+type ModuleEntry = { name: string, source: string }

-const moduleEntries = await inferModuleEntries(cwd)
+const moduleEntries = await inferModuleEntries(cwd)

 const moduleInput = Object.fromEntries(
-  moduleEntries.map(e => [filename(e) || basename(e, extname(e)), e]),
+  moduleEntries.map(e => [e.name, e.source]),
 )

-for (const resolvedEntry of entries) {
-  const entryName = filename(resolvedEntry) || basename(resolvedEntry, extname(resolvedEntry))
-  const outBase = resolve(distDir, entryName)
+for (const entry of entries) {
+  const outBase = resolve(distDir, entry.name)

and keep match[1] from ./dist/<subpath>.mjs as the name when collecting entries.

Also applies to: 246-258, 270-272

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/build.ts` around lines 110 - 112, The current logic that builds
moduleInput from moduleEntries uses basename(filename) and drops the export
subpath, causing collisions (e.g., ./dist/utils/index.mjs → dist/index.mjs);
update the mapping in inferModuleEntries (and the other similar spots noted) so
the entry name preserves the export subpath by extracting and using the capture
group (match[1]) from the path pattern (e.g., from "./dist/<subpath>.mjs") when
present, falling back to basename(filename(e), extname(e)) only if match[1] is
undefined; apply the same change where module entries are collected so
functions/variables like moduleEntries, moduleInput, filename(), basename(),
extname(), and any regex match usage consistently use the preserved subpath as
the key.

Comment thread test/build.spec.ts Outdated
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Jun 4, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/module-builder@751

commit: 59a5bd3

@socket-security
Copy link
Copy Markdown

socket-security Bot commented Jun 4, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedrolldown@​1.1.0951007899100
Addedtsconfck@​3.1.610010010080100
Addedtypescript@​5.9.3100100909590
Addedrolldown-plugin-dts@​0.25.29910010096100

View full report

@DamianGlowala DamianGlowala changed the title feat: migrate from unbuild to rolldown feat!: migrate from unbuild to rolldown Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tsdown/obuild migration

1 participant