Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

indykoning
Copy link

@indykoning indykoning commented Oct 17, 2025

This PR offers some backwards compatibility with Vue 2

In some cases you will want to use passed properties and children to the loading component, this was possible in Vue 2 but not in Vue 3. This PR gets you that ability back.


For some background, i have a heavy autocomplete bar requiring some big libraries which i do not want to load unless the autocomplete gets used.

For this i've created an async component that gets loaded after an event gets fired. This event would get fired when focussing on the "facade" input:

vue.component('autocomplete', defineAsyncComponent({
    loader: () => new Promise(function (resolve, reject) {
        document.addEventListener('loadAutoComplete', () => import('./components/Search/Autocomplete.vue').then(resolve), {'once': true})
    }),
    loadingComponent: {
        data: () => ({
            loaded: false,
        }),

        render() {
            return this.$slots.default(this)
        },
    },
    delay: 0,
}))
<autocomplete v-slot="{ loaded, ... }">
    <form method="GET" action="/search">
        <input 
            type="search" 
            v-on:focus="window.document.dispatchEvent(new window.Event('loadAutoComplete'))"
            ...
        />
        <heavy-search-library v-if="loaded">
            ...
        </heavy-search-library>
    </form>
</autocomplete>

This worked perfectly in Vue 2, however with Vue 3 this results in this.$slots.default is not a function which makes sense because the loadingComponent does not actually get access to their props and children.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed async component loading state to properly inherit context during the pending load phase, ensuring the loading UI displays correctly.

@coderabbitai
Copy link

coderabbitai bot commented Oct 17, 2025

Walkthrough

The async component loading path now wraps the resolved loading component with createInnerComp(resolved) instead of creating a vnode directly, so the loading component is instantiated as an inner component and receives the async wrapper's context (refs, custom element hooks, props).

Changes

Cohort / File(s) Summary
Async Component Loading State
packages/runtime-core/src/apiAsyncComponent.ts
Replace direct createVNode(loadingComponent) with createInnerComp(resolved) for the loading state so the loading component inherits the async wrapper's context

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as App
  participant AsyncWrapper as AsyncWrapper
  participant Resolver as Resolver
  participant InnerComp as createInnerComp
  participant Loading as LoadingComponent

  App->>AsyncWrapper: render async component
  AsyncWrapper->>Resolver: resolve loadingComponent (pending)
  Resolver-->>AsyncWrapper: loadingComponent (resolved)
  note right of AsyncWrapper #E6F7FF: New: wrap resolved\nwith createInnerComp
  AsyncWrapper->>InnerComp: createInnerComp(resolved)
  InnerComp->>Loading: instantiate as inner component
  Loading-->>App: render (inherits wrapper context)
Loading

(Optional comparison — old flow)

sequenceDiagram
  autonumber
  participant AsyncWrapper as AsyncWrapper
  participant Resolver as Resolver
  participant VNode as createVNode
  participant Loading as LoadingComponent

  AsyncWrapper->>Resolver: resolve loadingComponent (pending)
  Resolver-->>AsyncWrapper: loadingComponent (resolved)
  note right of AsyncWrapper #FFF4E6: Old: direct vnode creation
  AsyncWrapper->>VNode: createVNode(loadingComponent)
  VNode->>Loading: instantiate as standalone vnode (no wrapper context)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Suggested labels

:hammer: p3-minor-bug

Poem

🐇
I wrap the spinner snug and tight,
So props and refs feel just right.
As async waits and banners hum,
The inner bloom inherits come—
A tiny hop, a smoother sight.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "fix(runtime-core): pass props and children to loadingComponent" directly and accurately describes the main change in the changeset. The summary shows that the modification enables the loadingComponent to inherit context including props and children by wrapping it with createInnerComp(resolved), which is exactly what the title conveys. The title is concise, clear, uses the project's conventional formatting with the fix prefix, and contains no vague or noise-inducing terms. It aligns well with the PR's stated objective of restoring Vue 2 backwards compatibility by allowing async components' loadingComponent to receive props and slots.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9498a8b and 702adcb.

📒 Files selected for processing (1)
  • packages/runtime-core/src/apiAsyncComponent.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/runtime-core/src/apiAsyncComponent.ts

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

❤️ Share

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

@edison1105 edison1105 changed the title Pass props and children to loadingComponent fix(runtime-core): pass props and children to loadingComponent Oct 17, 2025
@edison1105 edison1105 added ready to merge The PR is ready to be merged. 🍰 p2-nice-to-have Priority 2: this is not breaking anything but nice to have it addressed. labels Oct 17, 2025
@github-actions
Copy link

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 102 kB (+2 B) 38.6 kB (+2 B) 34.8 kB (+13 B)
vue.global.prod.js 160 kB (+2 B) 58.7 kB (+2 B) 52.2 kB (-1 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 46.7 kB 18.3 kB 16.7 kB
createApp 54.7 kB 21.3 kB 19.5 kB
createSSRApp 58.9 kB 23 kB 21 kB
defineCustomElement 60 kB 23 kB 21 kB
overall 68.8 kB 26.5 kB 24.2 kB

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 17, 2025

Open in StackBlitz

@vue/compiler-core

npm i https://pkg.pr.new/@vue/compiler-core@13997

@vue/compiler-dom

npm i https://pkg.pr.new/@vue/compiler-dom@13997

@vue/compiler-sfc

npm i https://pkg.pr.new/@vue/compiler-sfc@13997

@vue/compiler-ssr

npm i https://pkg.pr.new/@vue/compiler-ssr@13997

@vue/reactivity

npm i https://pkg.pr.new/@vue/reactivity@13997

@vue/runtime-core

npm i https://pkg.pr.new/@vue/runtime-core@13997

@vue/runtime-dom

npm i https://pkg.pr.new/@vue/runtime-dom@13997

@vue/server-renderer

npm i https://pkg.pr.new/@vue/server-renderer@13997

@vue/shared

npm i https://pkg.pr.new/@vue/shared@13997

vue

npm i https://pkg.pr.new/vue@13997

@vue/compat

npm i https://pkg.pr.new/@vue/compat@13997

commit: 9498a8b

@edison1105
Copy link
Member

edison1105 commented Oct 17, 2025

Thanks for the PR. It would be better if you added a test case.

Co-authored-by: edison <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🍰 p2-nice-to-have Priority 2: this is not breaking anything but nice to have it addressed. ready to merge The PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants