When providing a Terser `nameCache` object to Vite's build minification (e.g., via `build.minify.terserOptions`), and simultaneously using property mangling (e.g., `mangle.properties`), the resulting cache is unreliable and often incomplete. Concretely, after a build with `compress: false, mangle: { properties: { keep_quoted: true } }` and a shared `nameCache`, entries for quoted properties appear or disappear unpredictably. This is because `nameCache` is a mutable, shared object that is not safe to access from parallel worker threads—each worker keeps its own internal state, and the object ends up corrupted or missing expected keys.

### Desired Behavior / Acceptance Criteria

- **Worker avoidance:** If `nameCache` is present in the Terser options object, Vite must **never** minify in worker threads for any chunk. All minification must happen on the main thread, regardless of the value of `maxWorkers` or the presence of other worker‑compatible options.
- **Correct cache population:** After the build, the `nameCache` object must accurately reflect the minification that occurred. For example, when `keep_quoted` is enabled, only unquoted property names should be mangled and cached; quoted property names must *not* appear in the cache.
- **Consistency with manual sequential runs:** The final `nameCache` should be identical to what one would obtain by running Terser synchronously on every chunk in a single‑threaded fashion, guaranteeing that reuse of the cache across builds yields deterministic results.
- **Existing incompatible‑option fallbacks:** The list of options that already force main‑thread execution (e.g., custom `nth_identifier.get`, `format.comments` as a function, `output.comments` as a function) must continue to work unchanged. `nameCache` is simply added to that exclusion set.
- **No regressions:** Builds that do not supply a `nameCache` must continue to use worker threads as before, with no impact on performance or output.

### Out of Scope

- Changes to how other `mangle` or `compress` options interact with workers.
- Any modification to the public API of the Terser plugin or its configuration shape.

fix: fallback terser to main thread when nameCache is provided (#20750)


## Bug Report: SSR-transformed modules break when user code defines a top-level `Object` variable

### Description
When a module intended for server‑side rendering (SSR) defines its own variable named `Object` (e.g., `const Object = "my-object"`) and exports it, the module cannot be loaded at runtime. The SSR transform injects property definitions that directly reference the global `Object` (`Object.defineProperty(...)`). However, because the transformed code runs in the context of the module itself, that reference resolves to the user’s own `Object` variable, which is not the expected built‑in constructor.

This leads to a runtime error along the lines of `TypeError: Object.defineProperty is not a function` when the module is evaluated by the SSR module runner.

### Steps to reproduce
A minimal module:
```js
const Object = "my-object";
export { Object };
```
When this module is imported via `ssrLoadModule` or the module runner, the transformed output contains:
```js
Object.defineProperty(__vite_ssr_exports__, "Object", { enumerable: true, configurable: true, get(){ try { return Object } catch {} }});
```
At runtime, `Object` inside the module refers to the string `"my-object"`, causing the evaluation to fail.

### Expected behavior
SSR‑transformed code should not be affected by user‑level shadowing of built‑in globals like `Object`. The property definition helpers used to set up live bindings for exports must use the real `Object` constructor irrespective of the module's own variable declarations.

### Impact
Any module that legitimately or accidentally reuses the identifier `Object` at the top level becomes broken when used in SSR. This prevents valid JavaScript patterns and is a source of confusion for developers, since the error is not in their own code but in the Vite‑injected transformation.

### Suggested direction
Instead of emitting `Object.defineProperty(...)` directly in the transformed code, provide a helper function through the SSR module context (e.g., a method like `__vite_ssr_exportName__`) that internally uses the correct `Object` reference. The transformed code would then call that helper, avoiding lookup of `Object` inside the module scope. This would isolate Vite’s internal machinery from user‑created bindings.

fix(ssr)!: don't access `Object` variable in ssr transformed code (#19996)


**Bug Report: Vite does not support `vite.config.cjs` for CommonJS config files**

When a project has `"type": "module"` in its `package.json`, using a CommonJS configuration file is only possible by explicitly naming it `vite.config.cjs` (the Node.js convention for CommonJS in an ES module package). However, Vite currently ignores `vite.config.cjs` and fails to load any configuration, falling back to defaults.

**Steps to reproduce**
1. Create a project with `package.json` containing `"type": "module"`.
2. Add a valid `vite.config.cjs` file that exports a configuration using `module.exports`.
3. Run `vite build` or `vite dev`.

**Observed behavior**
Vite does not find or load the `vite.config.cjs` file. The build/serve runs with the default configuration, ignoring the user’s settings. No error is thrown about the file itself—it is simply not detected.

**Expected behavior**
Vite should recognize `vite.config.cjs` as a valid configuration file and load it as CommonJS, just as it already does for `vite.config.js`, `vite.config.mjs`, and `vite.config.ts`. The `.cjs` extension is the standard way to opt into CommonJS in Node.js when the package type is module, and Vite’s config resolution should support it out of the box.

**Impact**
Users who need a CommonJS config (e.g., to use `require()` or certain CommonJS-only plugins) in a project with `"type": "module"` are unable to do so without renaming files and changing the package type, which can break other tooling. This missing support forces unnecessary workarounds and is inconsistent with Node.js module conventions that Vite otherwise respects (e.g., `.mjs` for ESM).

**Proposed resolution**
Extend the config file resolution order to include `vite.config.cjs` when the config file has not been explicitly provided via `--config`. If `vite.config.cjs` exists, it should be loaded as CommonJS regardless of `package.json` `"type"` field.


**Title:** Support Sass modern API (`compileStringAsync`) via `api` option in `preprocessorOptions.scss` / `preprocessorOptions.sass`

**Background**
Vite currently only uses the legacy Sass JS API (`sass.render`). Dart Sass has been promoting the new “modern” API (`sass.compileStringAsync`) which is more idiomatic and performant. We want to let users opt into the modern API without breaking existing projects.

**Request**
Add a new `api` field to the scss/sass preprocessor options:

```ts
// vite.config.js
css.preprocessorOptions.scss = {
  api: 'modern' | 'legacy',  // default 'legacy'
  // ... other sass options
}
```

When `api: 'modern'` is set, Vite must:
- Use `sass.compileStringAsync` and the modern `Importer<'async'>` interface.
- Translate the existing Vite Sass configuration (aliases, additionalData, sourcemaps, etc.) to the modern API.
- For `.sass` files, pass `syntax: 'indented'` instead of relying on `indentedSyntax`.
- Return a result with `css`, optional source map (as string), and a `stats.includedFiles` derived from `result.loadedUrls` (filtering file: URLs).
- Preserve the existing worker-fallback logic: custom `importer` functions (non-serializable) and custom `functions` should force execution on the main thread, even in the modern path.
- Work correctly with Vite’s internal URL rebasing and resolver logic (aliases, relative imports, etc.).

**Non‑obvious constraints / edge cases**
- The modern API’s importer has `canonicalize` and `load` methods, whereas our legacy worker uses a single `importer` function. The internal importer must bridge Vite’s resolver to these hooks.
- The `additionalData` option must still be prepended before passing content to `compileStringAsync`.
- Source maps returned by the modern API differ from the legacy `map` property; we need to JSON‑stringify `result.sourceMap` and attach it as `map`.
- The worker implementation must be compatible with the `WorkerWithFallback` pattern already used for preprocessors.
- The option should be documented with links to Sass’s legacy and modern API option references.

**Out of scope**
- Changing the default from `legacy` to `modern` (future consideration).
- Supporting the synchronous `compileString` API.

feat(css): support sass modern api (#17728)


Fix a TypeError when toggling between a Suspense-wrapped async component and a sync component inside a KeepAlive, where the async component has not yet resolved and the user switches to sync, back to async, then again to sync after the async resolves.

Steps:
1. Render a KeepAlive containing a Suspense. The default slot dynamically chooses between an async component (initially active, showing fallback) and a sync component.
2. Switch to the sync component (async component deactivated but kept alive).
3. Switch back to the async component (still unresolved; kept-alive instance reused).
4. Wait for the async component to resolve.
5. Switch to the sync component again.

Expected: no error; the sync component renders cleanly.
Actual: TypeError: Cannot read properties of null (reading 'parentNode').

The root cause is that Suspense’s internal pendingId is not unique enough and fails to account for the case where a kept-alive component is reused as the pending branch. When the kept-alive component is remounted, the existing component instance’s suspenseId must be preserved and used as the pendingId so that in‑flight async dependencies do not run stale branch-cleanup logic against a null parent node. The fix introduces a module‑level monotonic counter to guarantee globally unique pendingIds and special‑cases the kept-alive branch to reuse the component’s suspenseId.

fix(Suspense): handle switching away from kept-alive component before resolve


When a state change triggers both a `flush: 'pre'` watcher and the unmounting of its owner component (e.g., via `v-if`), the watcher callback should not fire. Currently it still executes, which can cause errors from accessing component state that no longer exists. The expected behavior is that `flush: 'pre'` watchers are skipped if the component is unmounted by the time pre-flush callbacks would run.

fix(watch): flush:pre watchers should not fire if state change causes


We need to finish the Vue 2 compat layer implementation for a number of features that are currently only partially wired up or are missing warning messages in the correct places. The following behaviors should be available when the compat build is used and the relevant deprecation flags are enabled (e.g., via `MODE: 2`).

**Targeted features and requirements**

1. **`WATCH_ARRAY`**
   When a watcher is defined on an array, Vue 2 performed deep watching automatically. The compat layer should emit a deprecation warning and still trigger the watcher on array mutation (e.g., `push`).

2. **`PROPS_DEFAULT_THIS`**
   In the `default` function of a prop, `this` must expose other props, `$options`, and injections just like in Vue 2. A deprecation message identifying the prop name must be emitted.

3. **`V_FOR_REF`**
   When `ref` is used together with `v-for`, an array of refs must be created. A deprecation warning must be emitted. The array must stay reactive to list changes (additions, removals, and v-if toggling).

4. **`V_ON_KEYCODE_MODIFIER`**
   The legacy keycode modifier syntax (e.g., `@keyup.1`) must be supported and emit a `V_ON_KEYCODE_MODIFIER` deprecation.

5. **`CUSTOM_DIR`**
   Legacy directive hooks (`bind`, `inserted`, `update`, `componentUpdated`, `unbind`) must be called at the appropriate lifecycle stage. A `CUSTOM_DIR` deprecation must be emitted for each hook that is invoked, including the legacy hook name and the corresponding Vue 3 lifecycle name. The current implementation appears to pass the mapped-name array instead of a single hook string to the deprecation helper; this must be fixed so the warning message references the specific legacy hook (e.g., `bind` → `beforeMount`).

6. **`ATTR_FALSE_VALUE` on attributes**
   When an attribute is bound to `false`, the attribute must be removed and a deprecation warning must be emitted. The warning must be associated with the owning component instance so that per-instance suppression works.

7. **`ATTR_FALSE_VALUE` on DOM properties**
   Vue 2 treated `false` for certain DOM properties differently: if the property is a string or number, the property value is set to `''` (string) or `0` (number) and the corresponding attribute is removed. The compat layer must replicate this behavior for string/number properties when the value is `false` and `ATTR_FALSE_VALUE` is enabled. A deprecation warning must be emitted, again with instance awareness.

8. **`ATTR_ENUMERATED_COERSION`**
   Enumerated attributes (e.g., `contenteditable`, `draggable`, `spellcheck`) must coerce values to `'true'`/`'false'` and emit a deprecation warning that includes the original value and the coerced value. Warnings must be tied to the component instance.

**Instance context for warnings**
All deprecation warnings that previously passed `null` as the component instance (notably those for `ATTR_FALSE_VALUE` and `ATTR_ENUMERATED_COERSION`) must be updated to receive the actual owning component, allowing individual components to suppress warnings via their compat config.

**Acceptance criteria**
- The features above behave as described when the compat flag is enabled.
- Deprecation warnings fire with the correct message arguments and, where applicable, respect the parent component’s compat configuration.
- Existing unrelated compat behaviors remain unchanged.


**Title:** Complete deprecation warnings for Vue 2 instance methods and options in compat build
**Area:** `packages/runtime-core/src/compat`
**Type:** feature / bugfix

The Vue 3 compat build aims to support Vue 2 APIs while emitting deprecation warnings to guide migration. Several instance methods and options are currently missing warnings, and a few emulated behaviors deviate from Vue 2 semantics. This needs to be addressed to make the compat build a reliable migration aid.

### Concrete behavioral changes needed

1. **Add missing deprecation warnings** for the following Vue 2 APIs when the compat build’s `MODE: 2` is active:
   - `$set` (`INSTANCE_SET`)
   - `$delete` (`INSTANCE_DELETE`)
   - `$destroy` (`INSTANCE_DESTROY`)
   - The full instance event emitter: `$on`, `$once`, `$off`, `$emit` (`INSTANCE_EVENT_EMITTER`)
   - `$children` (`INSTANCE_CHILDREN`)
   - `$listeners` (`INSTANCE_LISTENERS`)
   - `$scopedSlots` (`INSTANCE_SCOPED_SLOTS`)
   - `$attrs` class/style fallthrough when `inheritAttrs: false` (`INSTANCE_ATTRS_CLASS_STYLE`)
   - Root component `data` option as plain object (`OPTIONS_DATA_FN`)
   - Deep merge of `data` when merging mixins/extend (`OPTIONS_DATA_MERGE`)
   - `beforeDestroy` and `destroyed` options (`OPTIONS_BEFORE_DESTROY`, `OPTIONS_DESTROYED`)

2. **Fix `$destroy()` cleanup**
   The current `_compat_destroy` calls `app.unmount` but does not fully replicate Vue 2’s teardown. It must also:
   - invoke devtools’ app unmount notification
   - clear the `__vue_app__` reference on the container element
   This ensures that after `$destroy()` the instance is truly detached and devtools is updated.

3. **Make `$off` accept an array of event names**
   Vue 2’s `vm.$off(['eventA', 'eventB'])` is valid. Update the `$off` signature and implementation to handle `string[]` by removing handlers for each event in the array.

4. **Fix `$emit` handler context**
   In Vue 2, `$emit` calls each registered handler with `this` set to the Vue instance. The compat `emit` function must ensure handlers are called bound to `instance.proxy` (the public instance), matching the original behavior.

5. **Change `INSTANCE_EVENT_HOOKS` compat check from global to per‑instance**
   The current renderer caches a global `isHookEventCompatEnabled` flag at creation time. Because compat settings can be overridden per component, the lifecycle hook emits (`hook:beforeMount`, `hook:mounted`, etc.) must be guarded by `isCompatEnabled(INSTANCE_EVENT_HOOKS, instance)` on every relevant lifecycle stage, not just once globally.

6. **Handle anonymous components in `INSTANCE_ATTR_CLASS_STYLE` warning**
   When a component has no name, the deprecation message formats `<undefined>`. Fall back to `'Anonymous'` so the warning reads ``Component <Anonymous> has `inheritAttrs: false` …`` instead of showing `undefined`.

### Acceptance criteria
- All listed API usages log a deprecation warning exactly once (controlled via `warnDeprecation`).
- Instance event emitters work with correct `this` context and support array events for `$off`.
- `$destroy()` fully unmounts the app without leaving stale container references or devtools state.
- Lifecycle hook events obey per‑component compat configuration, not a static global flag.
- The warnings contain valid component names (or `'Anonymous'`) in all cases.
- Existing compat behavior for non‑listed APIs remains unaffected.

wip: test for instance and options compat


### Feature Request: Provide TypeScript typings for `<script setup>` ref sugar macros

**Context**
The ref sugar compile-time transform (enabled via `refSugar: true` in `<script setup>`) introduces the following globally available macros:

- `$ref()` — declare a reactive ref with automatic unwrapping
- `$computed()` — declare a computed property whose value carries a hidden marker
- `$fromRefs()` — destructure a composable return value while shallow‑unwrapping refs
- `$raw()` — extract the underlying `Ref<T>` or `ComputedRef<T>` from a variable created by a macro

These macros are handled by the compiler (`packages/compiler-sfc/src/compileScript.ts`) but currently lack runtime type definitions. Without proper typings, TypeScript users see implicit `any` types and lose the benefits of the transform’s intended type‑safety.

**Desired behavior**

1. **New typing module**
   Create `packages/runtime-core/src/helpers/refMacros.ts` with type‑only overloads (runtime stubs that return `null as any` are acceptable). Export the functions from `runtime-core/src/index.ts`.

2. **Global declarations**
   Augment the global scope in `packages/runtime-core/types/scriptSetupHelpers.d.ts` so that `$ref`, `$computed`, `$fromRefs`, and `$raw` are recognized without explicit imports, just like `defineProps` and `defineEmits`.

3. **Specific type contracts**
   - `$ref<T>(arg: T | Ref<T>): UnwrapRef<T>`
     When passed a plain value, return the value type. When passed a `Ref<T>`, return the fully unwrapped type (including nested refs), using the existing `UnwrapRef` utility.
   - `$computed<T>(getter: () => T): ComputedRefValue<T>`
     The result must *look like* `T` but carry a unique marker type so that `$raw()` can later detect it. Define a helper `ComputedRefValue<T>` as `T & { [ComputedRefMarker]?: any }` (marker is not exposed).
   - `$fromRefs<T>(source: T): ShallowUnwrapRef<T>`
     Given an object (e.g., the return of a composable), produce a type where properties that are `Ref<V>` become `V`, and non‑ref properties remain unchanged. Use the existing `ShallowUnwrapRef` utility.
   - `$raw<T>` overloads:
     - `$raw(value: ComputedRefValue<T>): ComputedRef<T>` – when the input was produced by `$computed()`, recover the `ComputedRef<T>`.
     - `$raw(value: T): Ref<T>` – for any other value (including results of `$fromRefs`), return `Ref<T>`.

4. **No runtime logic changes**
   The actual ref‑sugar transformation remains entirely in the compiler. The typing module only provides the TypeScript surface; the runtime functions are not expected to be invoked at runtime (they exist purely to satisfy the type system).

**Acceptance criteria**
- In a TypeScript `<script setup>` project with `refSugar: true`, all four macros are globally available with the described types.
- Standard type‑level tests confirm that:
  - `$ref(1)` resolves to `number`
  - `$ref(ref(1))` resolves to `number`
  - `$ref({ foo: ref(1) })` resolves to `{ foo: number }`
  - `$computed(() => 1)` gives a type assignable to `number` but distinguishable for `$raw`
  - `$fromRefs(useFoo())` unwraps `ref` properties while leaving non‑refs as‑is
  - `$raw(x)` returns `Ref<number>` for a `$fromRefs` unwrapped `x`, and `$raw(c)` returns `ComputedRef<number>` for a `$computed` result `c`.
- The typed module is re‑exported from `runtime-core` and the global augmentations are concatenated into the final `.d.ts` bundle.


**Bug: Crash during slot update after hydration in production (optimized) mode**

When an application is built for production (optimized compilation mode) and relies on server-side rendering with client-side hydration, a component that receives a `stable` slot (compiler-flagged as `optimized` / `STABLE`) may crash with `TypeError: Cannot read properties of null (reading 'insertBefore')` if the slot content initially contains a `v-if` that evaluates to `false` and later flips to `true` after mount.

The crash occurs during the client-side update when Vue attempts to replace the initial placeholder comment node with the newly created element, but an internal reference to a parent node is `null`.

**Expected behavior**
- The update should succeed without throwing an error.
- The rendered DOM should reflect the new element in place of the comment node.
- No hydration mismatch warnings or DOM inconsistencies should arise.

**Steps to reproduce**
1. Use a production build of Vue (optimized, with block tracking and patch flags enabled).
2. Create a wrapper component that renders its default slot.
3. Use that wrapper in a parent component that provides a **stable** slot containing a `v-if` whose initial value is `false` (producing a comment node) and later becomes `true` (producing an actual element).
4. Server-render the whole tree and perform client-side hydration.
5. After mount, change the `v-if` condition to `true`, triggering the slot update.

**Observed result**
A runtime error is thrown: `TypeError: Cannot read properties of null (reading 'insertBefore')`.

**Additional notes**
- The issue is specific to slots marked as stable by the compiler.
- The presence of a `dynamicChildren` array on the slot’s block should force the hydration logic to treat it as optimized even when the top-level call might not. The current code fails to override the `optimized` flag when the vnode contains dynamic children, leading to incorrect patch behavior.

fix(hydration): properly handle optimized mode during hydrate node (#10638)


As a Vue SFC developer using `<script setup lang="ts">`, I need the type resolution logic to understand the file extension mapping that TypeScript and Node.js use with modern module formats. Currently, when I write:

```vue
<script setup lang="ts">
import type { LinkProps } from './mts.mjs'
import { Foo } from './tsx.jsx'
import { Bar } from './mtsTyped.mjs'
import type { Baz } from './cts.cjs'
defineProps<LinkProps & { foo: Foo; bar: Bar; baz: Baz }>()
</script>
```

The compiler fails to resolve the types because it only strips the `.js` extension and then looks for `.ts`, `.tsx`, `.d.ts` files. It does **not** try `.mts`, `.cts`, `.d.mts`, or `.d.cts` – the standard TypeScript declaration extensions that correspond to `.mjs` and `.cjs` JavaScript files.

### Expected behavior

1. **`.mjs` imports prefer `.mts` declarations.** When the compiler resolves an import whose source ends with `.mjs`, it should first try to find a `.mts` file, then a `.d.mts` file, before falling back to `.ts`/`.tsx`/`.d.ts`. This matches the TypeScript `NodeNext` module resolution behavior for ESM files.

2. **`.cjs` imports prefer `.cts` declarations.** When the source ends with `.cjs`, the compiler should try `.cts` first, then `.d.cts`, then fall back to `.ts`/`.tsx`/`.d.ts`.

3. **General `.js` imports also benefit.** Even for plain `.js` imports (without an explicit `.mjs`/`.cjs` suffix), the resolution should eventually try `.mts`, `.mtsx`, `.d.mts`, `.cts`, and `.d.cts` as additional fallbacks after the existing `.ts`/`.tsx`/`.d.ts` attempts, so that project setups using `.mts`/`.cts` type files work without requiring import ers to change every specifier.

4. **Parser recognizes `.cts` as TypeScript.** Any file with a `.cts` or `.d.cts` extension must be parsed by the TypeScript-enabled babel parser so that type declarations are correctly extracted. The parser configuration should treat `.cts` the same way it already treats `.ts`, `.mts`, and `.tsx`.

5. **No regression.** Imports from `.js`, `.ts`, `.tsx` files that already work should continue to work exactly as before.

### Edge cases / constraints

- The extension stripping that occurs before resolution must handle `.mjs`, `.cjs`, and also the `.jsx` / `.mjsx` / `.cjsx` variants correctly.
- If both a `.mts` and a `.ts` file exist for the same base name, the modular one (`.mts`) must take precedence when the import uses `.mjs`.
- Similarly, for `.cjs` imports, `.cts` must win over `.ts` if both are present.
- The change should be limited to the SFC compiler’s type resolution in `<script setup>`; it should not affect runtime module resolution or the bundler.

### Technical scope

The resolution order should follow this logic (in pseudocode):

```
If import source ends with .mjs:
  remove .mjs extension
  try <base>.mts
  try <base>.d.mts
  try <base>.ts
  try <base>.tsx
  try <base>.d.ts
  try index files...

If import source ends with .cjs:
  remove .cjs extension
  try <base>.cts
  try <base>.d.cts
  try <base>.ts
  try <base>.tsx
  try <base>.d.ts
  try index files...

Otherwise (plain .js or no extension):
  try <base>
  try <base>.ts
  try <base>.tsx
  try <base>.d.ts
  try <base>.mts
  try <base>.d.mts
  try <base>.cts
  try <base>.d.cts
  try index files...
```

The `resolveParserPlugins` function and the file parsing logic must include `cts` as a recognized TypeScript language extension.

Acceptance criteria: Importing types from `.mjs` files where the declaration is in `.mts`/`.d.mts`, and from `.cjs` files where the declaration is in `.cts`/`.d.cts`, must successfully resolve and produce the expected runtime type strings for `defineProps`.

fix(compiler-sfc): add resolution trying for `.mts/.cts` files (#14402)


**Title:** Errors from async `setup()` functions are not propagated to `errorCaptured` or `app.config.errorHandler`

**Description:**
When a component defines its `setup()` function as `async` and the returned promise rejects, the error is not handled by Vue’s standard error-capture mechanism. This means that:

- The component’s own `errorCaptured` hook (and those of its ancestors) is never invoked.
- The globally configured `app.config.errorHandler` does not receive the error.
- No warning (e.g., `'Uncaught error in async setup'`) is logged to the console.

As a result, rejections in asynchronous setup functions can go entirely unnoticed or cause unhandled promise rejections that crash the application. The expected behavior is that Vue should treat rejections in `async setup()` the same way it treats synchronous errors thrown during setup: the error should be caught, passed to the error-capturing lifecycle hooks, forwarded to the global error handler, and a descriptive warning should be emitted.

**Acceptance Criteria**
1. Given a component whose `setup()` is `async` and ultimately returns a rejected promise, when that component is rendered (client-side or server-side), then the error is caught.
2. The caught error must be passed to the `errorCaptured` hook of the component (or a parent) before it reaches the global handler.
3. After (or instead of) being handled locally, the error must be forwarded to `app.config.errorHandler`, if configured.
4. A warning with the message `'Uncaught error in async setup'` (or equivalent) must be logged to the console.
5. The application must not crash due to an unhandled promise rejection – the error should remain observable but non-fatal, following Vue’s synchronous error handling contract.
6. The rendering should not be entirely aborted; the component may fall back to rendering its default template with empty state (matching the behavior when synchronous setup errors are caught).

fix(runtime-core): handle error in async setup (#2881)


The `Transition` wrapper component incorrectly handles `vnode` references after cloning the root element, causing transition classes to stick or fail to apply.

### Reproduction

```vue
<!-- MyTransition.vue -->
<template>
  <transition name="fade">
    <slot />
  </transition>
</template>
```

```vue
<!-- Parent -->
<MyTransition>
  <div v-if="show">content</div>
</MyTransition>
<button @click="show = !show">Toggle</button>
```

- Any fallthrough attribute on `MyTransition` (e.g., `foo="1"`) is passed to the inner `<div>`.
- Toggle `show` off and on again **before the leave transition finishes**.

### Expected

The enter/leave classes are correctly applied and removed, resulting in a clean DOM with only the normal classes/attributes of the element (e.g., `class=""` or no `class` attribute).

### Actual

The element is left with a stale `class` attribute (e.g., `class=""`) or transition classes like `fade-leave-to` are not cleaned up. The transition hooks reference the original VNode before cloning for fallthrough attributes, so later updates operate on an outdated node.

### Impact

Any pattern that wraps a `<transition>` inside a component and passes fallthrough attributes (or uses `inheritAttrs: false` / manual merging) is affected. This is commonly seen in libraries that provide `<FadeTransition>`, `<SlideTransition>`, etc.

### Desired Fix

When `renderComponentRoot` clones the root VNode to merge fallthrough attributes, `class`, `style`, or inherited directives/transition data, the transition hooks attached to that VNode must be updated to point to the cloned VNode so that subsequent transition callbacks use the correct node.

fix(runtime-core): properly handle inherit transition during clone VNode (#10809)


A template ref bound to a `<script setup>` variable declared with `let` (binding type `setup-maybe-ref`) produces missing or incorrect runtime code when compiled with `inline: true`. The generated handler should use the `isRef` helper to check if the variable is a ref and assign to its `.value` accordingly; otherwise, assign the element directly. The `setup-let` case should also use this dual-path assignment, not just a bare `variable = _value` overwrite.

fix(compiler): fix template ref codegen for setup-maybe-ref binding types (#4549)


# Fix directive parsing for dynamic arguments containing dots

**Context**
In `packages/compiler-core/src/parse.ts`, the `parseAttribute` function uses a regex to decompose a directive name into its parts (directive name, argument, modifiers). The current regex treats dots as strict delimiters between the argument and any modifiers:

```
/(?:^v-([a-z0-9-]+))?(?:(?::|^@|^#)([^\.]+))?(.+)?$/i
```

Dynamic arguments are expressed inside square brackets (e.g., `[event]`), but the argument capture group `([^\.]+)` fails to match anything containing a dot, which means a directive like `v-on:[a.b].camel` is not parsed correctly—the dot inside the brackets prematurely terminates argument capture, and the remainder is misinterpreted as a modifier or expression.

**Request**
Update the directive-name regex so that dynamic arguments (enclosed in square brackets) are recognized as a single argument even when they contain dots. After the closing bracket, any following `.modifier` parts should still be captured as modifiers.

Specifically, the argument capture should match either:
- a dynamic argument: `\[[^\]]+\]` (an opening bracket, any characters except `]`, then a closing bracket), **or**
- a static argument: the existing `[^\.]+` pattern.

This must not break parsing of:
- directives without arguments
- static arguments with modifiers
- dynamic arguments without dots (already working)
- shorthand directives (`:`, `@`, `#`)

**Expected behavior**
For `<div v-on:[a.b].camel>`:
- `name` → `"on"`
- `arg` → `{ type: SIMPLE_EXPRESSION, content: "a.b", isStatic: false }`
- `modifiers` → `["camel"]`

**Additional notes**
No AST node structure changes are required; the fix is purely in the regex inside `parseAttribute`. The new tests in the related spec already demonstrate the expected output.

fix(compiler-core): fix parsing for directive with dynamic argument containing dots


**Title:** Support dynamic `import()` type expressions in `<script setup>` type resolution

**Background**
In `<script setup lang="ts">`, the compiler can resolve external types used in `defineProps`/`defineEmits` when those types are imported via top-level `import` statements. However, TypeScript’s inline import type syntax `import('./module').Type` (often used without a standalone import) is currently not handled, causing an “Unresolvable type reference” error.

**Request**
Extend the SFC type resolver to understand `TSImportType` nodes so that macro calls like
```ts
defineProps<import('./types').MyProps>()
```
resolve correctly, following the same resolution logic as explicit imports.

**Expected behavior**
- The resolver should locate the target module using the same file-system and module-resolution logic already employed for static `import`s.
- It should then resolve the named or default export from that module’s scope.
- The resolved type should be recursively walked (including re‑exported types, interfaces, and nested dynamic imports) so that the final props/emits runtime types are inferred correctly.
- Runtime type inference (`inferRuntimeType`) must also support this node type and produce the correct string arrays (e.g., `['String']`, `['Number']`).
- Dependency tracking (the `deps` set) should include the resolved file so that HMR invalidation works as expected.

**Non‑obvious constraints**
- If the import path is relative, it should be resolved relative to the current file.
- The feature must handle both named exports (`import('./foo').Bar`) and default exports (the qualified name may be absent, meaning `default`).
- Existing helper `resolveImportSource` (or equivalent) should be reused so that resolution behaviour remains consistent.
- The change must not break existing static import resolution or runtime type inference like `Pick`, `Omit`, etc.

**Impact**
This allows users to reference shared types inline without adding an import statement, which is a common pattern in utility‑type definitions and ad‑hoc type composition.

feat(compiler-sfc): support dynamic imports when resolving types


When a textarea element is resized by the user via the browser’s native resize handle, the browser directly sets inline `width` and `height` styles. If a Vue component later re-renders with the same style object (i.e., identical `width` and `height` string values to the previous render), the style-patching logic overwrites those inline dimensions with the original values, effectively reverting the user’s resize. This should not happen.

**Expected behavior**:
For `<textarea>` elements only, when the previous and next style values for `width` or `height` are equal strings, do not set the corresponding inline style property. This preserves any dimensions the user has changed via the resize handle while still allowing other style properties (and width/height changes when the values actually differ) to be applied as normal. The special case must be limited to `width` and `height` on `textarea`; all other elements and properties should continue to follow the existing style patching rules.

fix(runtime-dom): preserve textarea resize dimensions (#14747)


As a developer using Vue with server-side rendering or hydration, I want the template compiler to warn me at compile time when the HTML nesting in my templates violates the HTML specification, so that I can catch mismatches that would otherwise cause subtle hydration errors or undefined behavior in the browser.

**Acceptance Criteria:**

1. **Dev-only compile warning**: The warning is emitted only during development compilations (i.e., when `__DEV__` is true), and it does not affect production builds.
2. **Invalid nesting detection**: A curated set of invalid parent–child combinations is enforced. Common examples include:
   - `<p>` cannot contain block-level elements like `<div>`, `<ul>`, `<section>`, `<h1>`–`<h6>`, etc.
   - Heading elements (`<h1>`–`<h6>`) cannot be nested inside one another.
   - Interactive elements cannot nest themselves (e.g., `<a>` inside `<a>`, `<button>` inside `<button>`).
   - Table-related structure rules are enforced (e.g., `<tr>` must be a child of `<thead>`, `<tbody>`, or `<tfoot>`; `<td>` must be a child of `<tr>`).
3. **Valid but surprising nests remain allowed**: Certain valid but often surprising combinations **must not** trigger a warning, such as `<select><hr></select>` (which is permitted by the spec).
4. **Warning message format**: The warning message should identify the offending child and parent tags in a clear manner, e.g., `"<div> cannot be child of <p>, according to HTML specifications. This can cause hydration errors or potentially disrupt future functionality."`
5. **Integration with existing compiler infrastructure**: The warning is surfaced via the compiler’s `onWarn` callback, consistent with other compiler warnings. It is implemented as a node transform that examines the current element and its parent context.
6. **No interference with compilation**: The warning is purely diagnostic; the template continues to compile and render regardless of the warning.

dx(compiler-dom): warn on invalid html nesting (#10734)


**Feature Request: Add `onTrack` / `onTrigger` debug hooks to `computed()`**

### Problem
`ReactiveEffect` instances support optional `onTrack` and `onTrigger` callbacks that fire during dependency collection and when a dependency triggers re-execution. This is invaluable for debugging reactivity, visualizing dependency graphs, or building devtools. However, `computed()` (both readonly and writable) does not expose these hooks, even though every computed property internally uses an effect. Developers cannot observe when a computed property tracks its dependencies or when a dependency change marks it as dirty and triggers a re-evaluation.

### Expected behavior
1. **Readonly computed**
   ```ts
   const c = computed(() => obj.foo, { onTrack, onTrigger })
   ```
2. **Writable computed**
   ```ts
   const c = computed({ get: () => obj.foo, set: v => obj.foo = v }, { onTrack, onTrigger })
   ```

The callbacks should behave identically to those on `ReactiveEffect`:
- `onTrack(event: DebuggerEvent)` fires for every tracked access during the computed’s getter evaluation. The event includes `effect`, `target`, `type` (e.g. `TrackOpTypes.GET / HAS / ITERATE`), and `key`.
- `onTrigger(event: DebuggerEvent)` fires when a dependency change triggers the computed’s scheduled re-run (before re-evaluation), including `effect`, `target`, `type` (e.g. `TriggerOpTypes.SET / DELETE`), `key`, and the relevant `oldValue` / `newValue`.

The `effect` field in both events should reference the computed’s internal `ReactiveEffect` so that tooling can correlate tracks/triggers with the correct computed instance. No prior evaluation (i.e. lazy behavior) should be forced; the hooks are attached at creation time and fire during normal lazy or eager access patterns.

### Impact
Without these hooks, debugging reactivity graphs that involve computed properties is a black box. This omission forces developers to fall back to manual logging or to wrap every computed in a plain `effect`, defeating the purpose of computed caching and lazy evaluation. Adding `onTrack`/`onTrigger` parity aligns `computed` with the rest of the reactivity system and greatly improves developer experience for complex reactive applications and custom devtools.

### Additional constraints
- The feature must be tree-shakeable in production; the hooks should be entirely stripped when `__DEV__` is false.
- The existing `computed` signatures must remain backward compatible (the debug options are a second, optional argument).
- The same `DebuggerEvent` type used by effects must be reused/exported to avoid duplication.

feat(reactivity): support onTrack/onTrigger debug options for computed


### Feature request: `customRef` should support different getter/setter types like `Ref<T, S>`

#### Context
The existing `Ref<T, S>` interface allows a ref whose getter returns `T` while its setter accepts `S` (default `S = T`). This is used, for example, in `shallowRef` and `ref` to model that the setter accepts a wider type (the raw value) than the getter exposes (the unwrapped reactive value). However, `customRef` currently accepts only a single type parameter `T`, forcing the getter and setter expressions in the factory to operate on exactly the same type. This prevents common patterns where a `customRef` parses or transforms the value on read (narrowing), while accepting a different type on write.

#### Desired behavior
- `customRef` and its associated factory type `CustomRefFactory` should accept an optional second type parameter `S` (defaulting to `T`).
- `customRef<T, S>(factory)` should return `Ref<T, S>`, where the factory’s setter receives `S` values and its getter must return `T` values.
- The change should maintain backward compatibility: the single-type-argument form `customRef<T>(factory)` should behave exactly as before, with `S = T`.

#### Non-goals / invariants
- The runtime behavior of `customRef` (tracking, triggering, dep management) stays unchanged; this is purely a typing change.
- The internal `CustomRefImpl` class may need to be generic in both `T` and `S` to correctly type the getter/setter accessors, but external users care only about the public `customRef` overload and that `Ref<T, S>` is properly obeyed in assignments and value reads.

#### Related API surface
- `Ref<T, S>` – already defined in `packages/reactivity/src/ref.ts`
- `ShallowRef<T, S>` and `ref()` already demonstrate the two-type-parameter pattern.

#### Example use case
```ts
const cr = customRef<string, number>((track, trigger) => ({
  get: () => 'hello',       // T = string
  set: (val: number) => {   // S = number
    trigger()
  }
}))
// cr.value is typed as string
// cr.value = 123 is allowed
// cr.value = 'world' is a type error
```

fix(types): allow customRef to have different getter/setter types (#14639)


## Bug Report: Mapped types, template literal keys, and string-intrinsic types are not supported in compiler-sfc macros

### Summary
Defining component `props`/`emits` using mapped types, template literal keys, or built-in string-manipulation types (e.g., `Capitalize`, `Uppercase`) currently fails with compiler errors. This forces developers to manually flatten types, which undermines the purpose of TypeScript’s type-system features and leads to duplication.

### Observed behavior
When a SFC type referenced by a macro (`defineProps`, `defineEmits`, etc.) contains any of:

- A mapped type with a finite union constraint, e.g. `{ [K in 'foo' | 'bar']: string }`
- An index signature with a template literal key, e.g. `[`_${T}_${S}_`]: boolean` where `T` and `S` are unions of string literal types
- A type that uses string-intrinsic utilities such as `Capitalize<T>`, `Uppercase<T>`, `Lowercase<T>`, `Uncapitalize<T>`, `Extract`, `Exclude` on string literal unions

the compiler throws an error like:

- `computed keys are not supported in types referenced by SFC macros.`
- `Unsupported type in SFC macro: TSMappedType`
- `Failed to resolve type reference.`

For example, the following valid TypeScript causes a compile error:

```ts
// A.component.vue
<script setup lang="ts">
type Size = 'sm' | 'md' | 'lg'
type Props = {
  [K in Size]: number
}
defineProps<Props>()
</script>
```

Similar errors appear for template-literal keys and `Capitalize<Something>`.

### Expected behavior
The compiler should resolve finite mapped types, template literal keys, and string-intrinsic types to concrete string literal sets and produce correct runtime type strings (`String`, `Number`, etc.) for macros. Intersections of such types should merge correctly, and optional properties (`?`) must be preserved.

Specifically:

- `[K in T]: V` where `T` is a union of string literals should expand to a property for each member of the union, with the given value type.
- Template literal keys like `` { [\`_\${T}_\${S}_\`]: string } `` should expand to all combinations and map to the value type.
- `Capitalize`, `Uppercase`, `Lowercase`, `Uncapitalize`, `Extract`, `Exclude` applied to string literal unions should be evaluated at compile time.
- Intersections that include such mapped types should combine all resulting keys (keys from different intersected members should be merged).
- Only keys that can be statically resolved to a finite set of string literals should be supported; any type leading to an infinite or unresolvable key set should produce a clear error.

### Impact
Developers cannot use these fundamental TypeScript patterns to define props/emits in a DRY way. They must manually duplicate keys or abandon type safety, leading to larger, less maintainable codebases.

### Additional context
Vue 3.3+, TypeScript 4.x+. The compiler already processes simple type literals, unions, and intersections. Extending this to support mapped types, template literal keys, and string-intrinsic types would align the SFC macro experience with common TypeScript idioms and eliminate a significant pain point.

feat(compiler-sfc): support mapped types, string types & template type in macros


**Title:** HMR reload triggers infinite recursion when parent accesses exposed child data via ref

**Background**
During hot module replacement, calling `reload(id, newComp)` on a component may lead to an infinite update loop if a parent instance references the child via a template ref and reads the child’s exposed properties in its render function. The loop causes the browser tab to freeze or crash.

**Steps to reproduce**
1. Create a child component that exposes some reactive data (e.g., a `count` ref) and has an HMR record.
2. Create a parent that renders the child with a template ref callback and accesses `child.value?.count` in its return value.
3. Trigger an HMR reload of the child (e.g., by changing `data` or the template).
4. Observe that the parent’s scheduled re-render causes the old child instance to be evaluated again, repeatedly triggering the reload hooks in an infinite recursion.

**Expected behavior**
The HMR reload should complete without entering an infinite loop. The old child component should unmount and the new version should mount, and any parent referencing exposed properties should see the updated values after a single re-render cycle.

**Technical constraints / hints**
- The problem originates from the internal `hmrDirtyComponents` tracking and the way the parent update is queued via `queueJob`.
- When the parent re-renders, it may evaluate `com.value?.count` while the child’s HMR status still marks the old component as dirty, causing the child to be re-processed and the parent to be scheduled again.
- The fix should ensure that after the parent’s update is queued, the old component definition is removed from the dirty set so that subsequent re-evaluations do not re-trigger the HMR path.

**Acceptance criteria**
- The test case described above (parent with ref + exposed child data) must not cause infinite recursion when `reload` is called.
- The child should unmount and mount exactly once during the HMR cycle.
- Existing HMR functionality (other reload, rerender, and record scenarios) should remain intact.

fix(hmr): avoid infinite recursion when reloading hmr components (#6936)


**Title:** Add `watchSyncEffect` shorthand for sync-flush watch effects

**Background:**
Vue 3 currently provides `watchEffect` (which defaults to `flush: 'pre'`) and `watchPostEffect` (which sets `flush: 'post'`). For cases where an effect must run synchronously immediately after a dependency changes, the only way is to pass `{ flush: 'sync' }` to `watchEffect`. For consistency and discoverability, we should add a dedicated `watchSyncEffect` convenience function mirroring the existing `watchPostEffect` pattern.

**Acceptance Criteria:**
- Expose a new function `watchSyncEffect` from `@vue/runtime-core` and through the public `vue` package.
- Signature: `watchSyncEffect(effect: WatchEffect, options?: DebuggerOptions): WatchStopHandle`
- Internally, the function delegates to `doWatch` with `flush: 'sync'`, merging any debug options in development (analogous to `watchPostEffect`).
- The effect runs synchronously when a tracked dependency updates, before any DOM rendering or scheduled flush jobs.
- The `effect` callback receives the standard `onInvalidate` registrator and behaves identically to a `watchEffect` with `flush: 'sync'` in all other respects (cleanup on stop, component-unmount handling, SSR bail-out, etc.).

**Non-goals:**
- No changes to existing `watch`, `watchEffect`, or `watchPostEffect` APIs.
- No additional flush modes beyond the existing `'sync'`.


**Title:** Add compat tests for legacy `Vue.config.keyCodes` and `Vue.config.ignoredElements`, and fix `ignoredElements` mapping for app instances

**Background**
In the compat build we support the Vue 2 global config options `Vue.config.keyCodes` and `Vue.config.ignoredElements`. The `ignoredElements` option should be mapped to the Vue 3 `compilerOptions.isCustomElement` so that the template compiler recognizes those elements as custom elements and avoids “unknown component” warnings.

**Current issue**
The `ignoredElements` → `isCustomElement` mapping currently only happens in the setter of the `Vue.config` proxy, which runs when the global config property is assigned. This means that if the global config is set *before* an app instance is created, the mapped `isCustomElement` is available on the singleton app config, but it may not be correctly propagated when app configs are copied for new instances (e.g. when using `new Vue()` after setting `Vue.config.ignoredElements`). The resulting apps can still treat those elements as unknown components.

**Desired behavior**
- When `Vue.config.ignoredElements` is set (or available globally), every app instance created via `new Vue()` (or `Vue.createApp` in compat mode) must have its `compilerOptions.isCustomElement` created from that array, so the template compiler respects it.
- The legacy `keyCodes` config should also be fully functional: custom key codes defined on `Vue.config.keyCodes` must work as key modifiers in `v-on` handlers.
- There should be dedicated tests for both config options that exercise the actual runtime behavior (key events, DOM rendering) to ensure the features work end to end.

**Constraints / safety**
- The mapping from `ignoredElements` (array of strings and regexps) to `isCustomElement` (function) must be applied at the point where an app’s config is initialized (i.e. during the config copy in the compat global setup), not only on assignment.
- `ignoredElements` should only be mapped in the full (runtime compiler) build; the runtime-only build should not attempt to set `compilerOptions`.
- The global config tests should not leak deprecation warnings into test output; suppress warnings via existing toggles where needed.

**Acceptance criteria**
- New test file covering `GLOBAL_KEY_CODES` and `GLOBAL_IGNORED_ELEMENTS` is present and passes.
- `Vue.config.keyCodes` custom aliases trigger the correct key handlers.
- Tags matching `Vue.config.ignoredElements` entries (string or regex) are rendered as native elements without warnings.
- The `ignoredElements` → `isCustomElement` mapping is moved to the app config copy logic, ensuring all apps respect the value.


The `defineComponent` return type does not expose the original options object, making it impossible to access options like `props`, `provide`, or `render` in a type‑safe manner after component definition.

### Steps to reproduce
```ts
const MyComponent = defineComponent({
  props: {
    msg: String
  },
  provide() {
    return { theme: 'dark' }
  },
  render() { return null }
})

// TypeScript errors – props, provide, render are not recognized on the return type
MyComponent.props.msg
MyComponent.provide().theme
MyComponent.render()
```

### Expected behavior
After calling `defineComponent`, the returned component type should carry all the properties and methods defined in the original options object with their exact types. For example:

- `MyComponent.props` should be typed as `{ msg: { type: StringConstructor } }` (or the exact prop options passed in).
- `MyComponent.provide` should be typed as `() => { theme: string }`.
- `MyComponent.render` should be typed as `() => null`.

### Actual behavior
The return type of `defineComponent` is a complex intersection built from inferred generics but does *not* include the raw options object. Properties like `props`, `provide`, `render`, etc. are either absent or typed as overly broad (e.g., `any`), preventing safe reuse of the options later.

### Impact
This makes common patterns impractical in TypeScript:
- Inspecting or reusing prop definitions from a component (e.g., to build a wrapper).
- Accessing the `provide` function for testing or composition.
- Extracting any custom option defined on a component.

### Desired solution
The `defineComponent` overloads should accept and preserve the full options shape as part of the return type. This likely requires threading a new generic parameter through the `DefineComponent`, `ComponentOptionsBase`, and related internal types so that the originally passed options intersect with (or become part of) the component's public type. Additionally, the `provide` option should be typed with the actual provide function’s return type instead of a loose `Function` or `any`.

The fix should be purely type‑level; no runtime changes are needed. It must remain backward compatible for existing consumers that do not rely on these properties.

fix(types): preserve and expose original options on defineComponent return type (#5416)


When using `defineProps` with a generic mapped type that combines `Omit` and `Pick` (e.g., a type that makes specific keys optional), the compiler fails to resolve the expected property types. The resulting props are either missing or have incorrect types.

**Minimal reproduction**
```vue
<script setup lang="ts">
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>

interface Test {
  foo: string
  bar?: string
}
type OptionalTest = Optional<Test, 'foo'>

const props = defineProps<OptionalTest>()
</script>
```

**Expected behavior**
`props` should be inferred as having two optional properties of type `String`:
- `foo?: string`
- `bar?: string`

**Actual behavior**
The props object doesn’t contain both `foo` and `bar` – either some keys are missing entirely, or they resolve to `unknown`.

**Additional context**
The root cause appears to be that the type parameter `K` is not being resolved to its actual string literal argument `'foo'` when evaluating the `Pick` and `Omit` built-in utility types. The key resolution for `Pick<T, K>` and `Omit<T, K>` doesn't seem to receive the generic type parameters from the enclosing mapped type, so it cannot expand `K` to the concrete string union `'foo'`. As a result, the mapped type’s structure is not correctly reconstructed for runtime props inference.

This prevents using common patterns like `Optional` to define prop types and forces developers to manually inline the intersection, reducing type safety and reusability.

fix(compile-sfc): handle mapped types work with omit and pick (#12648)


## Bug report: `EffectScope.off()` called out of order leaks scope references and prevents garbage collection

### Description
When `withAsyncContext` is used in an `async setup()` function, sibling components can restore their effect scopes in one order and then clean them up in a different order (e.g., restore A → restore B → cleanup A). This non‑LIFO invocation pattern causes `EffectScope.off()` to leave a dangling reference in the active effect scope chain. The stale scope remains globally reachable through the `activeEffectScope` variable, even after the scope is completely disposed. As a result, the entire scope—together with everything it references (component instances, watchers, handlers, and ultimately the Vue application)—is retained and cannot be garbage‑collected.

This is particularly problematic in SSR scenarios where many apps are created sequentially; memory usage grows indefinitely because previous apps are never released.

### Expected behavior
`EffectScope.off()` should correctly unlink the scope from the active scope chain regardless of the call order. After all scopes have been deactivated, no stale scope should remain reachable through `getCurrentScope()`. Any objects only referenced via the disposed scope should be eligible for garbage collection.

### Observed behavior
The current implementation of `EffectScope.off()` only handles the common LIFO case where the scope being deactivated is currently at the top of the chain (`activeEffectScope === this`). When a scope in the middle of the chain is deactivated, its `prevScope` pointer is not removed from the chain, leaving the scope still reachable by iterating from `activeEffectScope`. This keeps the scope and all associated resources alive.

### Steps to reproduce (high‑level)
1. Create two components that use `withAsyncContext` inside `async setup()`.
2. In each component’s setup, create a watcher and register its stop handle via `onScopeDispose`.
3. Render an SSR app containing both components repeatedly via `createSSRApp` and `renderToString`.
4. After rendering, observe that previous app instances are not garbage collected (e.g., using `WeakRef` and exposed GC).

### Additional context
- The issue is triggered when `withAsyncContext` restores scopes in order A → B, but the cleanup microtasks run B’s restoration followed by A’s cleanup, leading to `off()` calls that are not in LIFO order.
- The fix needs to traverse the active chain and remove the scope’s `prevScope` link from whichever scope currently points to it, so that the chain remains consistent and the deactivated scope becomes unreachable.

### Impact
Unbounded memory usage in SSR or any long‑lived application that frequently creates and disposes such async‑setup components.

fix(reactivity): unlink effect scopes on out-of-order off (#14734)


The `<Transition>` component with `mode="out-in"` should properly clean up a leaving `<Suspense>` branch when the transition itself is conditionally rendered (for example, placed inside a `v-if` / `v-else` block). After toggling the condition, no stale DOM nodes from the previously active branch should remain in the container — only the latest rendered content should be visible and included in the DOM tree. The fix should apply to any scenario where a `<Transition mode="out-in">` wraps a `<Suspense>` and the whole transition boundary is added/removed due to a conditional render, regardless of how many times the condition is toggled.

fix(suspense): avoid DOM leak with out-in transition in v-if fragment (#14762)


As a user, I want the Vue template compiler to offer an explicit whitespace handling strategy so I can choose between the current space-saving condensation and exact preservation of source whitespace.

**Acceptance Criteria**

1. The compiler’s parser options accept a new `whitespace` option with two valid values: `'condense'` and `'preserve'`.
2. When `whitespace` is not set, the parser behaves exactly as today – i.e. the default strategy is `'condense'`.
3. When the strategy is `'condense'` (default), the parser applies the existing whitespace rules:
   - Text nodes containing only whitespace at the very beginning or very end of an element’s child list are dropped.
   - Whitespace text nodes that contain a newline and appear between elements or between an element and a comment are removed.
   - Consecutive whitespace inside a text node is condensed (multiple spaces/newlines collapsed to a single space), while leading/trailing spaces of that text node are preserved unless otherwise removed.
   - Whitespace between interpolations, and whitespace without newlines between elements, are kept as-is (existing behavior).
   - These rules do not apply inside `<pre>` or when `inVPre` is active.
4. When the strategy is `'preserve'`, **no** whitespace text nodes are dropped, and no whitespace condensation occurs:
   - Text nodes that are solely whitespace remain as children of their parent element, including at the start/end of an element’s content.
   - Whitespace between elements, between an element and a comment, and between interpolations is preserved as text nodes with their original content.
   - Content of text nodes is kept exactly as in the source, without any collapsing of spaces or newlines.
5. The `whitespace` option is available through the same `ParserOptions` interface that consumers pass to `baseParse`. Its value is merged into the parser context and used in `parseChildren` when deciding whether to apply whitespace removal/condensation logic.
6. The feature must maintain full backward compatibility: existing usage of the parser without the new option continues to yield the same AST as before.

feat(compiler-core): whitespace handling strategy


We need to resolve several parser issues that currently block DOM template parsing tests. The compiler-core tokenizer and parser should handle these cases correctly so that `compiler-dom` test expectations pass.

### Specific changes

1. **RCDATA inside `<textarea>` and `<title>`**
   - The tokenizer must support `{{ }}` interpolations and HTML entity decoding (`&...;`) when parsing content inside RCDATA elements.
   - After parsing an interpolation inside RCDATA we must return to the “in special tag” state, not plain text state.
   - Entity start (`&`) detection should also fire during RCDATA parsing so entities are properly consumed and reported (non‑browser builds only).

2. **Accurate source locations for entities**
   - The `ontextentity` and `onattribentity` callbacks should receive the exact `start` and `end` positions of the entity in the source, not just the decoded character.
   - When an attribute value contains an entity, the attribute’s recorded start/end should span the entity’s position so that source‑map information is preserved.

3. **Decode entities inside interpolation expressions**
   - For backwards compatibility, if an interpolation’s raw content contains `&`, we must decode HTML entities before building the expression AST node.
   - Use the existing `decodeEntities` option in browser builds, and `decodeHTML` from `entities/lib/decode.js` otherwise.

4. **CDATA sections in foreign namespaces**
   - When the current element’s namespace is not HTML (e.g. SVG, MathML), a `<![CDATA[...]]>` section should be treated as plain text content.
   - In the HTML namespace it should eventually produce an error; for now a TODO is acceptable.

5. **Safety on closing tag detection**
   - While scanning for the `>` that closes a tag, guard against reading past the end of the input to avoid an infinite loop when `>` is missing.

6. **Namespace resolution**
   - When determining the namespace of a new element (in `onopentagname`), use the direct parent from the element stack (`stack[0]`) rather than falling back to the root. This ensures correct inheritance in nested foreign elements (e.g. `<svg>` inside `<html>`).

Together these fixes should bring the DOM parser in line with the expected behavior defined by the `compiler-dom` parse suite.


**Title:** Force dynamic slots when `v-slot`'s name or props expression references a scope variable (`prefixIdentifiers: true`)

**Context:**
In `packages/compiler-core/src/transforms/vSlot.ts`, the `buildSlots` helper determines whether the component’s slots need the `DYNAMIC_SLOTS` patch flag. When `prefixIdentifiers` is on, we attempt to optimise this by checking whether any scope variable (e.g. a `v-for` iteration variable) is actually referenced inside the slot’s children. If not, we skip the flag.

**Problem:**
The current check only inspects the slot’s children. It does **not** account for scope variables that are referenced directly in the `v-slot` directive’s argument (dynamic slot name) or expression (destructured slot props with defaults). Consequently, slots like these are incorrectly treated as static when they should be dynamic:

- `v-slot:[i]` – the slot name depends on a loop variable.
- `v-slot="{ value = i }"` – a slot-prop default value uses a loop variable.

Leaving `DYNAMIC_SLOTS` off in these cases produces incorrect render output because the slot’s identity or contents can change across loop iterations.

**Desired behaviour:**
When `prefixIdentifiers: true`, `hasDynamicSlots` should become `true` if **any** `v-slot` directive on the component element has an `arg` or `exp` that contains a reference to an outer scope identifier (checked via `hasScopeRef`). The existing child-only check should be retained as an additional condition.
This ensures that the three cases below behave correctly with `v-for`:

1. `v-slot:[i]` → `DYNAMIC_SLOTS`
2. `v-slot="{ value = i }"` → `DYNAMIC_SLOTS`
3. `:i="i"` (a plain prop, no `v-slot`) → only `PROPS` flag (i.e., do **not** force `DYNAMIC_SLOTS` here)

**Additional notes:**
- The change should only affect the `prefixIdentifiers: true` branch.
- The fix must not introduce false positives that break the optimisation for normal props or static slot names.

fix(compiler-core): force dynamic slots when slot referencing scope vars (#9427)


Support resolving type imports when a `tsconfig.json` project reference points to a directory containing a `tsconfig.json` rather than directly to a file.

When a `tsconfig.json` includes a `references` entry with `"path": "./some-folder"`, the resolver should:
- resolve the path to `./some-folder/tsconfig.json` (as TypeScript does),
- apply that config’s `include`, `exclude`, and `compilerOptions.paths` when resolving module imports,
- silently skip references whose resolved path does not exist (instead of failing or ignoring the reference entirely).

fix(compile-sfc): Support project reference with folder,  (#10908)


When a template contains a **self-closing** element that carries `v-pre`, the compiler should stop ignoring expressions and directives only for that element and its (empty) content; any sibling elements after it must be compiled normally.  The same applies when a **self-closing** tag is recognized as a `<pre>` (via a custom `isPreTag` option): the whitespace-preservation / condensing behavior must not leak into the text content of following sibling elements.

Currently, the compiler fails to clear the internal `v-pre` and `pre` modes after parsing a self-closing tag, causing later siblings to be incorrectly treated as if they were still inside that boundary.

**Acceptance Criteria**

1. Given a template like `<div v-pre/><div :id="foo"><Comp/>{{ bar }}</div>`, the second `<div>` must be processed normally:
   - Its `:id` directive must parse as a dynamic binding (`foo` evaluated as an expression).
   - Its inner `<Comp/>` must be recognized as a component.
   - Its `{{ bar }}` must become a standard interpolation node with `bar` as a non-static expression.

2. Given a custom `isPreTag` option that returns `true` for `"pre"` and a template like `<pre/><span>\n  foo   bar</span>`, the `<span>` and its text must **not** have its whitespace preserved as raw; instead it must be condensed according to the normal condensing rules (e.g., `" foo bar"`).

3. The fix must only affect the mode reset after self-closing tags; normal (non-self-closing) `<tag v-pre>...</tag>` and `<pre>...</pre>` must continue to work exactly as before.

4. There should be no impact on any other parsing behavior—in particular, the fix must not change how open/close tag matching works, how nested elements inside non-self-closing `v-pre`/`pre` are handled, or how `v-pre` interacts with other directives.

fix(compiler-core): fix self-closing tags with v-pre


When a component uses `useTemplateRef('foo')` to create a template ref, the setup state ref for `foo` (if any) must not be updated when the ref is resolved. Only the template ref should receive the element. This prevents unintended side effects where a setup ref with the same name gets overwritten, leaving the user's ref value corrupted. The check should apply both to string refs and to refs passed via `ref: someRef` + `ref_key`.

fix(useTemplateRef): don't update setup ref for useTemplateRef key (#12756)


Make `readonly` collection wrappers (Map, Set, WeakMap, WeakSet) stop tracking dependencies when the original target is a plain (non-reactive) collection, while keeping them transparently reactive when wrapping an already-reactive collection.

**Acceptance Criteria**

1. **Readonly-of-plain does not track**
   Given a plain `Map`, `Set`, `WeakMap`, or `WeakSet` wrapped only with `readonly()` (not `reactive()`), reading from it inside an `effect` must **not** register the effect as a dependent. Subsequent mutations to the same underlying collection via a separate `reactive()` wrapper must **not** cause the effect to re-run.

   - Applies to: `.get(key)`, `.has(key)`, `.size`, `.forEach()`, and all iterator methods (`entries()`, `keys()`, `values()`, `[Symbol.iterator]()`).

2. **Readonly-of-reactive still tracks**
   When `readonly()` wraps a collection that was already made reactive with `reactive()`, all access inside an `effect` **must** still register as dependencies. Mutating the reactive source must trigger the effect.

   - Example: `const src = reactive(new Map()); const view = readonly(src);` – an effect reading `view.get('foo')` should re-run when `src.set('foo', newValue)` is called.

3. **Value wrapping unchanged**
   - Readonly proxy methods should continue to return their values wrapped in `readonly` (or `reactive` when appropriate, e.g. for nested objects inside a reactive+readonly collection).
   - The `isReactive()` check on the readonly wrapper of a reactive original should still return `true`.

4. **Safety / Correctness**
   - The readonly wrapper must always return the current up-to-date value from the collection; the change only concerns **when** effects re-run, not data staleness.
   - Instrumented mutations that are forbidden on readonly collections (add, set, delete, clear) must still throw or behave as no-ops in development mode (unchanged).
   - The `readonly` proxy should not accidentally expose any internal tracking state that could cause memory leaks or cross-contamination.

**Stakeholder Note**
This addresses a common pitfall where a `readonly(map)` passed to a reactive system unexpectedly causes effects to react to internal mutations of the plain map, leading to over-firing effects and potential performance issues. The intended contract: `readonly` provides a non-mutating view, not an automatically reactive view unless the underlying data source is itself reactive.

refactor(reactivity): readonly collections should not track


In `renderSlot`, when a slot is provided but its rendered content consists only of comment nodes (e.g., from conditional branches that evaluate to nothing, or from nested `<slot>` calls that resolve to empty output), the fallback content is not displayed. Instead, the component renders nothing, which violates the expectation that fallback content should appear whenever a slot contributes no visible DOM.

**Desired behavior:**
- If the VNodes produced by a slot function are entirely "empty" (all children are comment VNodes, or `Fragment` VNodes whose own children recursively contain only comment VNodes), the slot should be treated as if no slot were provided at all.
- In that case, the component should render its explicit fallback content (the `fallback` argument of `renderSlot`) exactly as it would for an unprovided slot.
- This rule applies to default slots, named slots, and nested slot renderings.
- The presence of any valid VNode (anything other than a comment or an all-comment fragment) should **not** trigger fallback, even if that valid VNode is mixed with comments.
- After falling back due to no valid nodes, the patch flag of the wrapper fragment must be set to `PatchFlags.BAIL` (not `STABLE_FRAGMENT`) so that the renderer does not incorrectly assume stable slot content.
- The visible outcome is that components using `<slot>fallback</slot>` correctly display the fallback content when the provided slot contains only non-renderable comments (e.g., from `<template v-if="false">`, `v-else`, or a forwarded slot that itself yields no real output).

fix(slots): should render fallback content when slot content contains no valid nodes  (#2485)


Allow Node.js subpath imports (paths starting with `#`) in template asset URL and srcset transformations, while keeping hash-only fragment references working on non-asset attributes. Specifically:

- `img[src]`, `video[poster]`, `source[src]`, and `image[href]` (and their xlink variants) should treat a `#`-prefixed value as a relative import path, generating the appropriate import statement (e.g., `import _imports_0 from '#src/assets/vue.svg'`).
- For `srcset` strings, URLs with fragments (e.g., `./icons.svg#icon-heart`) should import only the path part and append the fragment to the expression (`_imports_0 + '#icon-heart'`). Descriptors (like `2x`) must still follow the fragment.
- Hash-only values on non-asset attributes (e.g., `<use href="#fragment">` and any custom tag/attribute) must remain literal strings, not imports.
- Malformed percent-encoding sequences (e.g., `./foo%.png`) should not throw; the raw string should be used as the import source.

fix(compiler-sfc): allow Node.js subpath imports patterns in asset urls (#13045)


**Title:** Slots: Manually rendered compiled slot can retain the compiler optimization flag after parent update, causing patch errors

**Issue:** #11336

**Description**
When a parent component passes compiled slots (i.e. slots with a `_` flag) to a child, and that child renders the slots via a manual `renderSlot` call (non-optimized mode), the internal `_` flag may leak into the child’s runtime slots object under certain update sequences. This causes `renderSlot` to incorrectly treat the slots as fully compiled and skip the `BAIL` Fragment wrapper. The result is a mismatch between the expected patch flags and the actual vnode tree, leading to runtime errors (e.g. “Cannot read properties of null”) during subsequent dynamic toggles (like a `v-if` inside the slot content).

**Reproduction scenario**
- `Outer` is a functional component that returns `slots.default()` and has a reactive dependency.
- `Mid` is a component that manually renders its default slot using `renderSlot`.
- `App` renders `Outer` with compiled slots containing a `v-if` inside the content passed to `Mid`.
- `Outer`’s reactive dependency changes, forcing a re-render. `Outer` calls `slots.default()` again, producing the same compiled slot content.
- The slot object passed to `Mid` is reassigned during `updateSlots`. If the `_` flag is not properly stripped (or is inadvertently re-copied), `Mid`’s `renderSlot` sees the flag and creates an optimized Fragment instead of a bailed one.
- Subsequent toggle of the `v-if` branch then triggers a failed patch.

**Expected behavior**
When a slot is consumed in non-optimized (manual) rendering context, the internal `_` compiler marker must **never** be present on the runtime slots object, regardless of whether the slot object was originally generated by the compiler. The flag should be filtered out during both slot initialization and updates when the `optimized` flag is `false`.

**Technical notes**
- This is a follow-up to the original fix in #2893, which handled the mount case but did not cover subsequent updates consistently.
- The correction should ensure that the `_` property is excluded from the slot object copy when the component is not in optimized mode, rather than relying on deletion after copying. This avoids enumeration and reactivity pitfalls.
- The same guard must apply in `initSlots` and `updateSlots` for path consistency.
- No changes to public API or slot contract are required.

**Acceptance criteria**
- The repro case from #11336 passes without error.
- A Mid component receiving compiled slots via re-rendering parent does not accumulate or retain the `_` flag on its `$slots`.
- Existing optimized-mode behavior (compiled slots in optimized parent/child) remains unaffected.

fix(runtime-core): more edge case fix for manually rendered compiled slot


# Pre watcher fires on child component unmount and runs out of expected order

## Background
Pre watchers (`watch` with `{ flush: 'pre' }`) are currently flushed globally during `updateComponentPreRender` via `flushPreFlushCbs()`. This means when a component is about to re-render, **all** pending pre watcher callbacks from any component in the tree are executed, not just those belonging to the component being updated.

## Problem
1. **Unwanted execution on unmount** – when a parent re-render causes a child component to unmount (e.g. `v-if` toggles), the child’s pre watcher may still fire because it is in the global pre flush queue. It should not fire at all.

2. **Incorrect ordering** – if both a parent and a child component register pre watchers on the same reactive dependency, a change to that dependency triggers both. Currently the child’s pre watcher can fire before the parent’s, even though the parent is the one initiating the update. The expected order is: parent pre watcher → parent render → child pre watcher → child render.

## Desired behavior
- When `updateComponentPreRender` is called for a specific component instance, `flushPreFlushCbs` should only run pre-flush jobs that belong to **that** instance.
- If `flushPreFlushCbs` is called without an instance (the existing call sites that serve global flushes), behavior must remain unchanged – all pending pre jobs are flushed.
- A pre watcher job’s ownership is identified by its `id` property, which is set to the component’s `uid` when the job is created.

## Implementation note
Modify `flushPreFlushCbs` to accept an optional `instance?: ComponentInternalInstance`. When provided, skip any job whose `id` does not match `instance.uid`. Then, in `updateComponentPreRender` (renderer), pass the current instance to `flushPreFlushCbs`. No other public API surface should change.

fix(watch): should not fire pre watcher on child component unmount (#7181)


**Title:** `readonly(reactive(map)).get(key)` returns readonly but non-reactive value

**Observed behavior**
When a `Map` is made reactive with `reactive()` and then wrapped with `readonly()`, accessing an entry via `.get(key)` returns a value that is **readonly** but **not reactive** (i.e., `isReadonly(value)` is `true`, but `isReactive(value)` is `false`). This means the returned value is a shallow readonly wrapper around the raw original – it does not preserve the reactive tracking that should be inherited from the reactive source.

In contrast, iterating over the same readonly reactive `Map` (e.g., `for...of`, `forEach`, `.values()`, `.entries()`) already returns keys and values that are **both reactive and readonly**. The inconsistency between `get` and iteration is unexpected.

**Expected behavior**
`readonly(reactive(map)).get(key)` should return a value that is **both reactive and readonly**, mirroring the behavior of iteration methods. The value should act as a deeply readonly proxy that still participates in the reactivity system (dependency tracking and triggering) for any nested reads/writes that are permitted through the readonly interface.

The same invariant should hold for other collection types that support `get` (e.g., `WeakMap`).

**Impact**
This inconsistency causes silent loss of reactivity when accessing nested data through a readonly wrapper of a reactive collection. Any effect, computed, or watcher that depends on a property of the value obtained via `.get()` will not react to changes made through the original reactive `Map`. The behavior is especially problematic because iteration methods work correctly, so developers may rely on `get` under the impression it should behave consistently, leading to subtle bugs in applications that combine `readonly` and `reactive` on collections.

fix(reactivity): readonly+reactive collection should also expose readonly+reactive values


The current API for processing `<script setup>` in SFCs is overly cumbersome and inconsistent. Users must call `parse()` to obtain a descriptor, then separately call `compileScriptSetup()` to compile the script. This two-step process is verbose and easy to overlook. Additionally, `compileScriptSetup()` returns a custom object (`{ code, map, bindings }`) rather than an `SFCScriptBlock`, which breaks the pattern used for templates and styles. The `parserPlugins` option name is misleading because it only affects Babel parsing, not the Vue template parser.

**Expected Behavior**

- `parse()` should be able to automatically compile the `<script>` or `<script setup>` block and expose the result directly on the descriptor. The descriptor should gain a `scriptTransformed` field of type `SFCScriptBlock` (including `content`, `map`, and `bindings` metadata).
- The standalone compilation function should be renamed to `compileScript` (instead of `compileScriptSetup`) and should return an `SFCScriptBlock` with the same structure as the new descriptor field, rather than a disparate object.
- The option controlling Babel parser plugins should be renamed to `babelParserPlugins` for clarity, and the type should be exported as part of the public API alongside `BindingMetadata`.

**Impact**

This simplification eliminates the manual glue code needed to compile script setups, makes the output type consistent with other block types, and reduces confusion about the option's scope. It aligns the script compilation API with the single-step ergonomics already used for template and style compilation.

refactor: simplify sfc script transform usage


v-model's `.trim` and `.number` modifiers are mutually exclusive: when both are set on a component or input, only one is applied (due to an `else if` in the processing logic). The expected behavior is that both modifiers are applied in sequence — the value is trimmed first, then coerced to a number. This applies to:

- native element `v-model-text` (the `vModelText` directive)
- component v-model, where `modelModifiers` contain both `trim` and `number` (handled in `emit`)

The fix should change the conditional from `else if (number)` to `if (number)` so that both transformations can run when the respective flags are true.

fix(v-model): fix case where .trim and .number modifiers are used together (#5842)


When a computed getter mutates its own dependency (a side effect) and that computed is read during rendering, the render effect re-runs infinitely. The cycle is: render reads the computed, the computed's getter modifies a dependency, the dependency marks the computed dirty, the render effect sees the computed as dirty, re-runs, and repeats.

Adjust the reactivity dirty tracking to avoid this infinite loop without suppressing legitimate updates. Specifically:

- The computed that directly causes the side effect (the "origin") should be treated as not dirty during the same evaluation cycle, so that a render or watcher accessing it does not schedule another run based solely on its own side-effect dirtiness.
- Computed values that depend on that origin computed (chained computeds) must still be considered dirty and re-evaluated, so they can incorporate any actual changes that resulted from the side effect.
- The existing `MaybeDirty_ComputedSideEffect` level is insufficient to distinguish between the origin and its dependents; a separate dirty level for the origin is needed to break the loop.
- When a dependency notifies its subscribers, if the subscriber is a computed effect that is currently running (i.e., it is the origin), it should skip marking itself Dirty and instead be marked with the new origin-side-effect level so that later `dirty` checks can treat it as clean while still allowing dependents to detect it.
- The `triggerEffects` path and the `dirty` getter should use this new level: origin computeds return false from `dirty`, but when a dependent computed queries its `dirty` and sees an upstream origin computed, it treats that as true and forces re-evaluation.
- Ensure that the warning for computed side effects still fires in development when the origin computed is re-evaluated.

This must prevent the infinite re-render while preserving correct reactivity for chained computed values after the side-effect mutation.

fix(reactivity): avoid infinite loop when render access a side effect computed (#11135)


Improve type inference for `setup()` props and for `this`/`vm` inside `data()` when a component uses `mixins` or `extends`.

- In `setup()`, the first argument (`props`) should be a merged view that includes the prop types from all mixins and extends, not only the component’s own declared props.
- In `data()`, `this` and the `vm` parameter should expose the component’s own props and mixin/extends props, but must not expose computed properties (since they are not yet available during `data()` execution).
- Ensure that prop types extracted from mixin/extends are preserved; if a mixin/extends does not declare props, treat it as `{}` so it does not pollute the intersection.

This addresses the lack of type-safe access to inherited props inside `setup` and `data`, and prevents accidental access to computed properties inside `data`.

types: mixin and extends typing on data and setup (#2404)


## Implementation Request: Fix TypeScript generation for struct getters/setters

When a `#[wasm_bindgen]` struct exports methods annotated with `#[wasm_bindgen(getter)]` and/or `#[wasm_bindgen(setter)]`, the generated TypeScript declaration (`.d.ts`) for the corresponding class property is incorrect in several ways:

1. **Getter-only properties are not marked `readonly`.** A property that only exposes a getter should be declared as `readonly` in TypeScript so that assignment will produce a compile error.

2. **Getter+setter properties are incorrectly marked `readonly`.** When both a getter and a setter are exported for the same logical property, the TypeScript property must *not* be `readonly`.

3. **Setter-only properties are missing a type annotation.** When a struct exports only a setter for a property (no corresponding getter), the generated TypeScript property lacks a type. This causes a TypeScript compilation error. The property should use the setter’s argument type as its type annotation.

4. **Setter-only properties are incorrectly marked `readonly`.** Even though the property is writable, the current output marks it `readonly`. It should not.

The fix must ensure that the generated TypeScript class declarations respect these invariants for every exported struct that uses getter/setter attributes. The JavaScript runtime bindings (the actual getter/setter functions) appear to be generated correctly; only the TypeScript definition needs adjustment.

**Acceptance criteria:**
- For a property that has **only a getter**: `readonly propName: ReturnType;`
- For a property that has **only a setter**: `propName: ArgumentType;` (derived from the setter’s argument type)
- For a property that has **both a getter and a setter**: `propName: ReturnType;` (assuming the types match; if they differ, use a union or the wider type — but in the typical case they are the same)
- Existing tests and functionality unrelated to getter/setter TypeScript output must remain unchanged.


The WebIDL frontend (`wasm-bindgen-webidl`) currently only produces a type import for interfaces. It should also emit import functions for regular operations defined on those interfaces, so that the generated Rust bindings include `impl` methods for calling into JS.

For example, given an `Event` interface with the operations `stopPropagation`, `preventDefault`, etc., the generated code should contain methods like `fn stopPropagation(&self)` that invoke the corresponding JS function via a shim.

Implementation requirements:

- Only regular operations are handled for now. Special, static, and stringifier operations should be silently skipped.
- Operations without a name, or with optional or variadic arguments, must be skipped (no partial generation).
- If any argument type or the return type uses an unsupported WebIDL type (e.g., `DOMString`, `sequence`, etc.), the entire operation should be skipped.
- The self parameter should be a shared reference (`&self`) to the interface type, and the import kind must be `Method` with the correct class name.
- The `#[wasm_bindgen(method)]` attribute must be set on the generated function's options.

The interface name must be available when processing its member operations; adjust the parser plumbing as needed.

webidl: emit methods for regular operations


**Title:** Consumed-by-value class arguments leave stale entries in the finalization registry when weak references are enabled

**Description**

When wasm-bindgen exports a Rust struct (class) that has a method taking `self` by value or any argument of the class type by value, the generated JavaScript glue does not unregister the JS wrapper from the internal `FinalizationRegistry`. Instead it only reads the raw pointer from `obj.ptr` and then sets `obj.ptr = 0`. The wrapper object remains registered, so when the garbage collector later finalizes the wrapper it attempts to free the same Rust memory a second time.

**Observed behavior**
With weak references enabled, calling such a consuming method and then triggering a garbage collection produces a runtime error similar to:

```
recursive use of an object detected which would lead to unsafe aliasing in rust
```

**Expected behavior**
All code paths that move ownership of a class instance into Rust (consuming `self`, by-value arguments, etc.) must use the same built-in helper that `free` and the destructor use, which properly extracts the raw pointer **and** removes the wrapper from the finalization registry. The generated JS should never leave a wrapper registered after its backing Rust memory has been surrendered.

**Impact**
- Makes exported classes that consume themselves or each other unusable with weak references / finalization.
- Risk of use-after-free-style corruption in Wasm linear memory.

**Reproduction sketch**
1. Define a `#[wasm_bindgen]` struct with a method that takes `self` by value (or takes another instance by value).
2. Enable the weak-reference feature in wasm-bindgen.
3. In JavaScript, create instances, call the consuming method, and force garbage collection (e.g., via `--expose-gc` in Node).
4. The error described above appears.

**Request**
Please update the JS glue generation so that every site where a class value is consumed into Rust invokes the existing "take ownership and unregister" mechanism instead of raw pointer extraction + nullification.

Call __destroy_into_raw everywhere a value is consumed (#3117)


## Feature request: support importing JS functions via `extern "JS"` blocks in `wasm_bindgen!`

I’d like to define foreign JavaScript functions that Rust code can call, as mentioned in the planned‑features list in the README: *“Importing JS functions with richer types (strings)”*.  Currently, the `wasm_bindgen!` macro does not accept any form of imported function.  Trying to write

```rust
wasm_bindgen! {
    extern "JS" {
        fn my_func(s: &str, n: u32);
    }
}
```

results in a compile error like *“unexpected item in bindgen macro”*.  This prevents any callback‑style interaction where Rust needs to call into user‑supplied JS.

### Desired behaviour

1. **Macro support** – Allow `extern "JS" { … }` items inside the `wasm_bindgen!` macro.  Each item is a foreign function declaration with a limited set of argument / return types (initially `&str`, integers, and `()` or integer returns).

2. **Rust glue** – For each declared import, the macro should generate a Rust wrapper that:
   - Converts `&str` arguments into raw `*const u8` and `usize` length pairs before calling the external function with the WebAssembly ABI.
   - Leaves integer arguments as‑is.
   - Returns integer return values directly.

3. **JS glue** – The generated JS output should include a shim for each imported function:
   - The shim accepts the raw wasm‑level parameters (pointer, length for strings).
   - It reads the string from wasm memory (using the raw pointer and length) and then calls the user‑provided JS function with a JS string.
   - Integer arguments and return values flow through unchanged.

4. **Instantiation wiring** – Currently the `instantiate` export created by `wasm‑bindgen` does not accept an imports object; it calls `WebAssembly.instantiate(bytes, {}).then(…)`.  It should be changed so that the caller can supply an imports object (e.g., `instantiate(bytes, { env: { my_func } })`).  The JS glue should look up each imported function inside `imports.env`, wrap it with the necessary string‑decoding shim, and pass the wrapped functions onward to `WebAssembly.instantiate`.

5. **String‑reading helper (getStringFromWasm)** – The existing `getStringFromWasm` helper currently expects a *boxed* string handle and makes calls into `exports.__wbindgen_boxed_str_ptr` / `__wbindgen_boxed_str_len` / `__wbindgen_boxed_str_free` to obtain the raw data.  This pattern does **not** work for import arguments, which arrive as raw pointer/length pairs from Rust.  `getStringFromWasm` therefore needs to be refactored to accept a raw pointer and length directly, so that both the export‑return path and the import‑argument path can use the same mechanism without depending on `exports` methods for every string read.  The export‑return path can extract the raw pointer/length *before* calling `getStringFromWasm`.

### Why this matters

Without the ability to import JS functions, every interaction is one‑way: Rust exports are called from JS, but Rust cannot call back into JS.  This blocks use‑cases like callbacks, event handlers, and integration with arbitrary JS APIs.  Supporting imports, even with the basic `&str` + integer signature set, opens up bidirectional interop and is a necessary foundation for the richer features that are planned.


Feature request: Expose public struct fields as JavaScript properties on generated classes.

Currently, when a `#[wasm_bindgen]` struct with public fields is exported, the generated JavaScript class only exposes methods. Public fields are completely inaccessible from JavaScript — `instance.myField` is `undefined` and assigning to it silently does nothing. The only workaround is to manually write getter and setter methods in an `impl` block, which is boilerplate that clutters the Rust code.

### Expected behavior
For every **public** field of an exported `#[wasm_bindgen]` struct, the generated JavaScript class should expose a corresponding property backed by a getter and a setter. That is:
- `instance.publicField` should read the current value from the Rust struct.
- `instance.publicField = value` should write the value into the Rust struct.
- The property should appear in the generated TypeScript declarations with the correct type.

Fields that are not `pub` should not be exposed. Tuple struct fields (unnamed) can be ignored for now — only named fields of regular structs need to be handled.

### Initial type support
For the first implementation it is fine to require that the field type implements `Copy` (e.g., `u32`, `f64`, `i32`). This avoids complexity around ownership and borrowing. Support for `Clone` types and `JsValue` can be added later. Attempting to use a non-Copy field should produce a clear compile-time error.

### Desired mechanics
- The underlying access should go through `wasm-bindgen`’s existing `WasmRefCell` for the struct.
- The generated getter/setter wasm functions should be automatically named following the project’s established conventions (similar to method exports) so they do not clash with user-defined exports.
- The JS class should emit native `get`/`set` accessor definitions. This keeps the API ergonomic and makes it feel like a natural JavaScript class.

This would eliminate a common source of boilerplate and make the JS interop layer feel much more like working with ordinary JS objects.

Generate accessors for public struct fields


**Title:** `Vec<JsValue>` cannot be returned from `#[wasm_bindgen]`-exported functions

**Description:**
When I attempt to return a `Vec<JsValue>` from a Rust function that is exported to JavaScript via `#[wasm_bindgen]`, the toolchain does not accept the type. Other vector types like `Vec<u32>`, `Vec<f64>`, and `Vec<String>` work fine and produce usable JavaScript arrays (or typed arrays), but `Vec<JsValue>` is rejected at compile time.

**Expected behavior:**
A function declared as `pub extern fn bar() -> Vec<JsValue>` should be accepted and, when invoked from JS, should return a plain JavaScript `object[]` where each element is an actual JavaScript value (not a numeric index or raw byte sequence). The values should be the same objects that the Rust code collected, correctly converted through the existing `JsValue` handling. For example, if the Rust function calls an imported JS function that returns a `JsValue` multiple times and pushes the results into a `Vec`, the JS caller should receive an array containing those same JS objects.

**Out of scope / deliberate constraints:**
- Passing `Vec<JsValue>` **into** an imported JS function is not required at this point; it is acceptable for the generator to report an error (e.g., a panic) when someone attempts to use `Vec<JsValue>` as an argument to an import. The request is only about returning such a vector from an export.
- Slices `&[JsValue]` do not need to be supported; attempting to use a slice of `JsValue` should result in a clear, early error (not silent miscompilation).

**Impact:**
Without this feature, it is impossible to return a dynamically sized collection of arbitrary JavaScript values from a Rust/wasm function, which forces users to implement awkward workarounds (e.g., serializing to JSON or using side-channel arrays). Supporting this would naturally extend the set of interoperable vector types and follows the same pattern already established for primitive and string vectors.