Skip to content

refactor(reactivity): add __NO_SIDE_EFFECTS__ comments#14308

Merged
edison1105 merged 2 commits intovuejs:mainfrom
skirtles-code:reactivity-no-side-effects
Jan 19, 2026
Merged

refactor(reactivity): add __NO_SIDE_EFFECTS__ comments#14308
edison1105 merged 2 commits intovuejs:mainfrom
skirtles-code:reactivity-no-side-effects

Conversation

@skirtles-code
Copy link
Contributor

@skirtles-code skirtles-code commented Jan 13, 2026

This PR adds /*@__NO_SIDE_EFFECTS__*/ for the following functions:

  • computed
  • reactive
  • shallowReactive
  • readonly
  • shallowReadonly
  • isReactive
  • isReadonly
  • isShallow
  • isProxy
  • toRaw
  • isRef
  • ref
  • shallowRef
  • toRefs
  • toRef

This allows for better tree-shaking, though the benefit is only likely to be small in most cases.

The motivation here comes from some code in Pinia:

const hotState = ref({} as S)

This initial creation is not inside a __DEV__ check (for scoping reasons), but all other uses of hotState are. The variable hotState is removed from production builds, but the call to ref({}) is retained.

Adding /*@__NO_SIDE_EFFECTS__*/ should allow these function calls to be removed in use cases like this, without needing the consuming application/library to add /*#__PURE__*/ annotations.

I'm not sure exactly which build tools support /*@__NO_SIDE_EFFECTS__*/, but I tested using pkg-pr-new for this PR and a default create-vue project and it did seem to work there.

I think the biggest risk here is if I've incorrectly annotated a function. Some of these functions do have side-effects, such as populating the proxyMap in createReactiveObject, but I believe those side-effects can be ignored if the return value is unused.

I should also note that accessing a property of the return value is enough to prevent the code being removed. So something like computed(() => {}) will be removed, but computed(() => {}).value will not.

I'm not sure how to classify this change. I've gone with refactor, but I can see an argument for either fix or perf.

Summary by CodeRabbit

  • Chores
    • Added no-side-effects annotations across the reactivity module to improve compiler/tree-shaking effectiveness. No public API signatures or runtime behavior were changed; this yields smaller bundles and better build-time optimizations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

📝 Walkthrough

Walkthrough

Adds /*@__NO_SIDE_EFFECTS__*/ annotations before multiple exported functions across three files in the reactivity package; no signatures or runtime behavior were changed. (49 words)

Changes

Cohort / File(s) Summary
Computed functions
packages/reactivity/src/computed.ts
Inserted /*@__NO_SIDE_EFFECTS__*/ immediately before the overloadedComputed implementation.
Reactive API functions
packages/reactivity/src/reactive.ts
Inserted /*@__NO_SIDE_EFFECTS__*/ annotations before exported functions: reactive, shallowReactive, readonly, shallowReadonly, isReactive, isReadonly, isShallow, isProxy, toRaw.
Ref API functions
packages/reactivity/src/ref.ts
Inserted /*@__NO_SIDE_EFFECTS__*/ annotations before exported declarations/implementations: isRef (overloads), ref (overloads/impl), shallowRef, toRefs, toRef.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

broom: p1-chore

Suggested reviewers

  • edison1105

Poem

🐰 I hopped through lines with a careful nose,

Left tiny notes where the side-effect wind blows.
Pure little marks, neat as a seed,
For bundlers to prune and keep builds speed.
Hooray — annotations snug in their rows!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding __NO_SIDE_EFFECTS__ comments to the reactivity package. It clearly and concisely summarizes the primary modification across all affected files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@github-actions
Copy link

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 103 kB 39.1 kB 35.2 kB
vue.global.prod.js 161 kB 59.1 kB 52.6 kB

Usages

Name Size Gzip Brotli
createApp (CAPI only) 47 kB 18.4 kB 16.8 kB
createApp 55.2 kB 21.4 kB 19.6 kB
createSSRApp 59.4 kB 23.2 kB 21.1 kB
defineCustomElement 60.7 kB 23.1 kB 21.1 kB
overall 69.5 kB 26.7 kB 24.3 kB

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 13, 2026

Open in StackBlitz

@vue/compiler-core

pnpm add https://pkg.pr.new/@vue/compiler-core@14308
npm i https://pkg.pr.new/@vue/compiler-core@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-dom

pnpm add https://pkg.pr.new/@vue/compiler-dom@14308
npm i https://pkg.pr.new/@vue/compiler-dom@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-sfc

pnpm add https://pkg.pr.new/@vue/compiler-sfc@14308
npm i https://pkg.pr.new/@vue/compiler-sfc@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/compiler-ssr

pnpm add https://pkg.pr.new/@vue/compiler-ssr@14308
npm i https://pkg.pr.new/@vue/compiler-ssr@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/reactivity

pnpm add https://pkg.pr.new/@vue/reactivity@14308
npm i https://pkg.pr.new/@vue/reactivity@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/runtime-core

pnpm add https://pkg.pr.new/@vue/runtime-core@14308
npm i https://pkg.pr.new/@vue/runtime-core@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/runtime-dom

pnpm add https://pkg.pr.new/@vue/runtime-dom@14308
npm i https://pkg.pr.new/@vue/runtime-dom@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/server-renderer

pnpm add https://pkg.pr.new/@vue/server-renderer@14308
npm i https://pkg.pr.new/@vue/server-renderer@14308
yarn add https://pkg.pr.new/@vue/[email protected]

@vue/shared

pnpm add https://pkg.pr.new/@vue/shared@14308
npm i https://pkg.pr.new/@vue/shared@14308
yarn add https://pkg.pr.new/@vue/[email protected]

vue

pnpm add https://pkg.pr.new/vue@14308
npm i https://pkg.pr.new/vue@14308
yarn add https://pkg.pr.new/[email protected]

@vue/compat

pnpm add https://pkg.pr.new/@vue/compat@14308
npm i https://pkg.pr.new/@vue/compat@14308
yarn add https://pkg.pr.new/@vue/[email protected]

commit: 7cb93ff

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 (1)
packages/reactivity/src/ref.ts (1)

58-64: Consider adding annotation to ref() as well.

The ref() function follows the same pattern as shallowRef() (which is annotated)—it delegates to createRef() and returns a RefImpl. For consistency, it could also receive the /*@__NO_SIDE_EFFECTS__*/ annotation.

Suggested change
 export function ref<T = any>(): Ref<T | undefined>
+/*@__NO_SIDE_EFFECTS__*/
 export function ref(value?: unknown) {
   return createRef(value, false)
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 623bfb2 and 7a4d072.

📒 Files selected for processing (3)
  • packages/reactivity/src/computed.ts
  • packages/reactivity/src/reactive.ts
  • packages/reactivity/src/ref.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: test / e2e-test
🔇 Additional comments (8)
packages/reactivity/src/reactive.ts (3)

91-105: Annotation placement looks correct for TypeScript overloads.

Placing /*@__NO_SIDE_EFFECTS__*/ between the overload signature and implementation ensures it appears directly before the function in compiled JavaScript output (since overloads are erased). The reactive() function stores the proxy in a WeakMap, but this is not an observable side effect for tree-shaking purposes—if the return value is unused, the call can be safely eliminated.

Since this is a WIP and you're planning to test with pkg-pr-new, verify the annotations are preserved through Vue's build pipeline and that bundlers (esbuild, Rollup, Terser) correctly tree-shake unused calls.


141-152: LGTM for factory function annotations.

shallowReactive, readonly, and shallowReadonly follow the same pattern as reactive—they create proxies stored in WeakMaps but have no external observable side effects.

Also applies to: 207-218, 250-259


322-328: LGTM for predicate and utility function annotations.

isReactive, isReadonly, isShallow, isProxy, and toRaw are pure functions that only read properties without mutation—ideal candidates for /*@__NO_SIDE_EFFECTS__*/.

Also applies to: 341-344, 346-349, 358-361, 386-390

packages/reactivity/src/ref.ts (4)

45-49: LGTM for isRef annotation.

Pure predicate function that only checks a flag property.


97-100: LGTM for shallowRef annotation.

Creates a RefImpl instance without external side effects.


343-353: LGTM for toRefs annotation.

The dev-mode warning is acceptable for tree-shaking purposes since __DEV__ is typically stripped in production builds.


480-495: LGTM for toRef annotation.

All branches either return existing refs or create new ref objects without external side effects.

packages/reactivity/src/computed.ts (1)

197-221: LGTM for computed annotation.

The computed() function creates a ComputedRefImpl whose constructor only initializes internal state. The dev-only debug callback assignments don't affect tree-shaking in production builds.

@absidue
Copy link

absidue commented Jan 13, 2026

I'm not sure exactly which build tools support /*@__NO_SIDE_EFFECTS__*/, but I tested using pkg-pr-new for this PR and a default create-vue project and it did seem to work there.

Found a list here: https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-compatibility.md

@edison1105 edison1105 added ready to merge The PR is ready to be merged. scope: reactivity labels Jan 14, 2026
@edison1105 edison1105 merged commit cde5d8f into vuejs:main Jan 19, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready to merge The PR is ready to be merged. scope: reactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants