Skip to content

Conversation

@cernymatej
Copy link
Member

@cernymatej cernymatej commented Sep 6, 2025

🔗 Linked issue

fix #33151

📚 Description

This fixes an issue where the same chunk could get edited more times, if there were tree-shakable composables within a tree-shakable composable.

It should also bring a very slight performance improvement, since we're not walking the body of the composable once we determine that it should be tree-shaken.

⚠️ This requires a new version of oxc-walker

🚧 TODO

  • update test snapshot once oxc-walker is updated

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@cernymatej
Copy link
Member Author

Coincidentally, the recent changes came in handy right away. 😅

@cernymatej
Copy link
Member Author

Pesky autofix... wouldn't it be possible to prevent it from updating inline snapshots? I feel like it might be quite easy to miss that a snapshot was updated in a larger PR.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 6, 2025

Open in StackBlitz

@nuxt/kit

npm i https://pkg.pr.new/@nuxt/kit@33153

nuxt

npm i https://pkg.pr.new/nuxt@33153

@nuxt/rspack-builder

npm i https://pkg.pr.new/@nuxt/rspack-builder@33153

@nuxt/schema

npm i https://pkg.pr.new/@nuxt/schema@33153

@nuxt/vite-builder

npm i https://pkg.pr.new/@nuxt/vite-builder@33153

@nuxt/webpack-builder

npm i https://pkg.pr.new/@nuxt/webpack-builder@33153

commit: 582cb43

@codspeed-hq
Copy link

codspeed-hq bot commented Sep 6, 2025

CodSpeed Performance Report

Merging #33153 will not alter performance

Comparing cernymatej:fix/composable-treeshake (582cb43) with main (ceff3aa)1

Summary

✅ 10 untouched benchmarks

Footnotes

  1. No successful run was found on main (c9d9868) during the generation of this report, so ceff3aa was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@danielroe
Copy link
Member

(in the interim I've ignored errors when calling s.overwrite. we can rebase this PR once oxc-walker is updated - or possibly once we update to https://github.com/rich-harris/zimmerframe.)

@cernymatej cernymatej marked this pull request as ready for review September 8, 2025 17:08
Copy link
Member

@danielroe danielroe left a comment

Choose a reason for hiding this comment

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

one thought - now that we are using AST-aware parsing, could we safely remove the composable entirely rather than adding false && /*@__PURE__*/?

@coderabbitai
Copy link

coderabbitai bot commented Sep 8, 2025

Walkthrough

The AST walker’s enter callback now performs the AST overwrite without a surrounding try/catch: it calls overwrite(...) directly and immediately invokes this.skip(). The unconditional replacement string remains false && /*@__PURE__*/ ... (no change to the gating logic). Tests were updated to use direct import { onMounted } from 'vue' (and #imports) and expanded with additional contexts (function args, assignments, conditionals, logical/sequence expressions, and shadowing scenarios). No exported/public signatures were changed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks (4 passed, 1 warning)

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly and accurately summarises the pull request’s key change, which is to prevent tree-shaking of composables within other composables. It follows conventional commit formatting, remains concise, and focuses on the primary functionality modification without extraneous detail. This makes the intent clear to reviewers scanning the commit history.
Linked Issues Check ✅ Passed The implementation stops the AST walker from editing nested composables after the first tree-shake decision, directly addressing the ‘already edited’ chunk error described in issue #33151. It also adds comprehensive tests covering various onMounted usage patterns to ensure the fix works across contexts. These changes collectively fulfil the coding objectives outlined in the linked issue.
Out of Scope Changes Check ✅ Passed The modifications are confined to the tree-shake plugin logic and its related test suite, which aligns precisely with the issue’s scope. No other parts of the codebase are affected, and there are no unrelated features or modules changed. Therefore, there are no out-of-scope changes present.
Description Check ✅ Passed The description directly references the linked issue and clearly explains the change by noting the repeated chunk-editing problem and its resolution. It highlights the performance benefit of skipping further AST traversal and specifies the required dependency update. All details are relevant and focused on the changeset.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 154e38a and 582cb43.

⛔ Files ignored due to path filters (2)
  • packages/nuxt/package.json is excluded by !**/package.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (2)
  • packages/nuxt/src/core/plugins/tree-shake.ts (1 hunks)
  • packages/nuxt/test/tree-shake.test.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/nuxt/src/core/plugins/tree-shake.ts
  • packages/nuxt/test/tree-shake.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
  • GitHub Check: test-fixtures (windows-latest, built, webpack, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, webpack, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (windows-latest, built, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, webpack, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-on, js, lts/-1)
  • GitHub Check: release-pkg-pr-new
  • GitHub Check: test-benchmark
  • GitHub Check: test-size
  • GitHub Check: typecheck (ubuntu-latest, bundler)
  • GitHub Check: typecheck (windows-latest, bundler)
  • GitHub Check: code
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

@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: 0

🧹 Nitpick comments (3)
packages/nuxt/src/core/plugins/tree-shake.ts (2)

86-86: Wrap the replacement in parentheses to preserve operator precedence in all contexts.

Helps when the transformed call appears inside larger expressions (arguments, logical chains, ternaries).

Apply:

-            s.overwrite(node.start, node.end, ` false && /*@__PURE__*/ ${functionName}${code.slice(node.callee.end, node.end)}`)
+            s.overwrite(node.start, node.end, `(false && /*@__PURE__*/ ${functionName}${code.slice(node.callee.end, node.end)})`)

85-85: Follow-through on the TODO: consult the real auto-imports registry.

Wire an optional predicate into plugin options so we don’t rely solely on name heuristics.

Example API shape:

interface TreeShakeComposablesPluginOptions {
  sourcemap?: boolean
  composables: Record<ImportPath, string[]>
  isAutoImported?: (name: string) => boolean
}

And in the guard (near Line 81):

if (!scopeTrackerNode && !(allComposableNames.has(functionName) || options.isAutoImported?.(functionName))) {
  return
}
packages/nuxt/test/tree-shake.test.ts (1)

71-94: Great regression test for nested composables — confirms new skip behaviour.

Consider adding an async-nested variant to cover the reported pattern with async arrows.

You could duplicate this case with:

onMounted(async () => {
  onMounted(() => {})
})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7db8275 and 1ec29f1.

⛔ Files ignored due to path filters (2)
  • packages/nuxt/package.json is excluded by !**/package.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (2)
  • packages/nuxt/src/core/plugins/tree-shake.ts (1 hunks)
  • packages/nuxt/test/tree-shake.test.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Follow standard TypeScript conventions and best practices

Files:

  • packages/nuxt/src/core/plugins/tree-shake.ts
  • packages/nuxt/test/tree-shake.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Write unit tests for core functionality using vitest

Files:

  • packages/nuxt/test/tree-shake.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: typecheck (windows-latest, bundler)
🔇 Additional comments (4)
packages/nuxt/src/core/plugins/tree-shake.ts (1)

85-87: Skipping children after overwrite prevents overlapping edits — good fix.

Calling this.skip() right after s.overwrite() cleanly avoids re-walking nested nodes and the “Cannot split a chunk that has already been edited” error path.

packages/nuxt/test/tree-shake.test.ts (3)

95-119: Shadowing tests: formatting-only changes look fine.

Assertions still validate correct non-shaking of locally shadowed identifiers.


135-141: Variable shadowing test updates look good.

Behavioural expectations unchanged; snapshot still exercises the guard.


71-94: Drop oxc-walker dependency bump check
Repository contains no direct “oxc-walker” dependency in any package.json; this verification isn’t applicable.

Likely an incorrect or invalid review comment.

Copy link

@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: 0

🧹 Nitpick comments (2)
packages/nuxt/src/core/plugins/tree-shake.ts (1)

47-52: Guard against non-statement contexts (potential syntax break).

If a tree-shakable composable were ever used in a non-statement position (e.g., as an argument, in a sequence, or assigned), a raw s.remove(node.start, node.end) could yield invalid JS (e.g., foo(, 1) or const x = ;). Today you only include lifecycle composables, so this is unlikely, but worth hardening.

Suggested approach (optional):

  • Operate at ExpressionStatement level: only remove when the parent is an ExpressionStatement whose expression is the target CallExpression.
  • Otherwise, neutralise with a benign expression (e.g., void 0) to keep syntax valid.

I can send a follow-up PR to reframe the visitor to match ExpressionStatement and handle the fallback path if you’d like.

Would you confirm that options.composables is guaranteed to list only lifecycle-style, statement-only calls in Nuxt 4.x?

Also applies to: 85-87

packages/nuxt/test/tree-shake.test.ts (1)

5-10: Add a few safety tests for non-statement contexts (optional).

To guard against future additions to composables, consider adding cases like:

  • foo(onMounted(() => {}))
  • const x = onMounted(() => {})
  • [onMounted(() => {}), 1]

These will catch accidental invalid code generation if the plugin ever targets non-statement usages.

Happy to draft these tests if you want.

Also applies to: 66-81

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ec29f1 and 75e6226.

📒 Files selected for processing (2)
  • packages/nuxt/src/core/plugins/tree-shake.ts (1 hunks)
  • packages/nuxt/test/tree-shake.test.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Follow standard TypeScript conventions and best practices

Files:

  • packages/nuxt/src/core/plugins/tree-shake.ts
  • packages/nuxt/test/tree-shake.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Write unit tests for core functionality using vitest

Files:

  • packages/nuxt/test/tree-shake.test.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: GalacticHypernova
PR: nuxt/nuxt#26468
File: packages/nuxt/src/components/plugins/loader.ts:24-24
Timestamp: 2024-11-05T15:22:54.759Z
Learning: In `packages/nuxt/src/components/plugins/loader.ts`, the references to `resolve` and `distDir` are legacy code from before Nuxt used the new unplugin VFS and will be removed.
📚 Learning: 2024-11-05T15:22:54.759Z
Learnt from: GalacticHypernova
PR: nuxt/nuxt#26468
File: packages/nuxt/src/components/plugins/loader.ts:24-24
Timestamp: 2024-11-05T15:22:54.759Z
Learning: In `packages/nuxt/src/components/plugins/loader.ts`, the references to `resolve` and `distDir` are legacy code from before Nuxt used the new unplugin VFS and will be removed.

Applied to files:

  • packages/nuxt/src/core/plugins/tree-shake.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: test-fixtures (windows-latest, dev, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, webpack, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-on, js, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, default, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, built, vite, async, manifest-off, json, lts/-1)
  • GitHub Check: test-fixtures (ubuntu-latest, dev, vite, default, manifest-on, json, lts/-1)
  • GitHub Check: release-pkg-pr-new
  • GitHub Check: test-size
  • GitHub Check: test-benchmark
  • GitHub Check: typecheck (ubuntu-latest, bundler)
  • GitHub Check: code
🔇 Additional comments (6)
packages/nuxt/src/core/plugins/tree-shake.ts (1)

85-87: Good fix: remove and skip to avoid double edits.

Directly removing the node and calling this.skip() prevents nested composables from being traversed and re-edited, addressing the “already been edited” error and matching the new tests.

packages/nuxt/test/tree-shake.test.ts (5)

17-17: Snapshot update aligns with new removal strategy.

Expecting only console.log('Hello World') is consistent with direct removal of the call expression.


66-81: Nice regression test for nested composables.

This accurately protects against double-editing by ensuring we stop walking once the outer call is removed.


82-106: Whitespace-only churn.

Looks like minor formatting; no action needed.


108-127: Whitespace-only churn.

Looks like minor formatting; no action needed.


1-10: Pin oxc-walker and re-run snapshots
No references to oxc-walker found in any package.json; ensure you add the required version to dependencies and regenerate snapshots.

@cernymatej
Copy link
Member Author

@danielroe I pushed some changes based on coderabbit's comment

If a tree-shakable composable were ever used in a non-statement position (e.g., as an argument, in a sequence, or assigned), a raw s.remove(node.start, node.end) could yield invalid JS (e.g., foo(, 1) or const x = ;)

Can you think of any problems with this implementation?

Copy link

@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: 1

🧹 Nitpick comments (6)
packages/nuxt/src/core/plugins/tree-shake.ts (2)

86-90: Remove the entire statement to avoid stray semicolons/artefacts

When the parent is an ExpressionStatement, removing only the CallExpression can leave a dangling “;” or whitespace. Remove the whole statement.

-            if (parent?.type === 'ExpressionStatement') {
-              s.remove(node.start, node.end)
+            if (parent?.type === 'ExpressionStatement') {
+              s.remove(parent.start, parent.end)
             } else {
               s.overwrite(node.start, node.end, 'void 0')
             }

91-91: Early return after mutation for clarity

After mutation + this.skip(), return to make intent explicit and avoid any accidental fallthrough in future edits.

-            this.skip()
+            this.skip()
+            return
packages/nuxt/test/tree-shake.test.ts (4)

66-79: Good coverage for nested composables

This reproduces the original failure mode and verifies no double-edit; looks solid. Consider also a variant where the inner call uses auto-imports from '#imports' (not via alias) to widen coverage.


140-155: Assignment neutralisation verified

a = void 0 maintains runtime shape. Consider adding a semicolon-style variant to ensure no stray “;” when statements end with semicolons.


157-173: Logical/conditional contexts covered well

These cases are easy to get wrong; snapshots look right. Please add:

  • return onMounted() → return void 0
  • await onMounted() → await void 0

11-18: Add tests for optional chaining and parenthesised statements

Two extra edge cases frequently appear in user code:

  • onMounted?.(() => {}) in expression/argument positions.
  • (onMounted()) as a standalone parenthesised expression statement.

These ensure the callee-detection and ExpressionStatement removal behave as intended.

Proposed additions (append near related blocks):

+  it('should handle optional chaining calls', () => {
+    const code = `
+      import { onMounted } from '#imports'
+      onMounted?.()
+      test(onMounted?.())
+    `
+    const { code: result } = transformPlugin.transform.handler(code, 'test.js')
+    expect(clean(result)).toMatchInlineSnapshot(`
+      "import { onMounted } from '#imports'
+      test(void 0)"
+    `)
+  })
+
+  it('should handle parenthesised expression statements', () => {
+    const code = `
+      import { onMounted } from 'vue'
+      (onMounted())
+    `
+    const { code: result } = transformPlugin.transform.handler(code, 'test.js')
+    expect(clean(result)).toMatchInlineSnapshot(`
+      "import { onMounted } from 'vue'"
+    `)
+  })
+
+  it('should handle return/await contexts', () => {
+    const code = `
+      import { onMounted } from 'vue'
+      async function f () {
+        return onMounted()
+      }
+      async function g () {
+        await onMounted()
+      }
+    `
+    const { code: result } = transformPlugin.transform.handler(code, 'test.js')
+    expect(clean(result)).toMatchInlineSnapshot(`
+      "import { onMounted } from 'vue'
+      async function f() {
+        return void 0
+      }
+      async function g() {
+        await void 0
+      }"
+    `)
+  })

Also applies to: 128-137, 140-155, 157-173, 175-185

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7db8275 and 154e38a.

⛔ Files ignored due to path filters (2)
  • packages/nuxt/package.json is excluded by !**/package.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (2)
  • packages/nuxt/src/core/plugins/tree-shake.ts (2 hunks)
  • packages/nuxt/test/tree-shake.test.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Follow standard TypeScript conventions and best practices

Files:

  • packages/nuxt/test/tree-shake.test.ts
  • packages/nuxt/src/core/plugins/tree-shake.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Write unit tests for core functionality using vitest

Files:

  • packages/nuxt/test/tree-shake.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: code
🔇 Additional comments (5)
packages/nuxt/test/tree-shake.test.ts (5)

17-17: Snapshot update looks correct

Result no longer includes the previous false && wrapper; matches new transform.


81-105: Shadowing test reads well

Confirms local declaration prevents tree-shake; behaviour matches plugin logic.


128-137: Argument-position neutralisation verified

Using void 0 in parameter position is correct and avoids syntax traps.


175-185: Sequence expression case is correct

Replacing the inner element with void 0 preserves evaluation order.


5-10: Pin oxc-walker ≥0.4.0
Tests rely on enter(node, parent), added in oxc-walker 0.4.0 (PR #126 merged 8 Sep 2025). Verify your package.json and lockfiles contain "oxc-walker": "^0.4.0", adding or bumping if missing.

@cernymatej cernymatej marked this pull request as draft September 9, 2025 00:48
@cernymatej cernymatej marked this pull request as ready for review September 9, 2025 22:39
@cernymatej cernymatej requested a review from danielroe September 9, 2025 22:40
@danielroe danielroe merged commit 8d11d08 into nuxt:main Sep 10, 2025
47 of 48 checks passed
@github-actions github-actions bot mentioned this pull request Sep 10, 2025
@cernymatej cernymatej deleted the fix/composable-treeshake branch September 10, 2025 09:19
@github-actions github-actions bot mentioned this pull request Sep 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nuxt 4.1.1: Nuxt Build Error: [nuxt:tree-shake-composables:transform] Cannot split a chunk that has already been edited

2 participants