- 
                Notifications
    
You must be signed in to change notification settings  - Fork 40
 
feat: async nested rendering #270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| 
           Thanks for the PR We can have a simple delayed component. Maybe using a simple timeout would be enough to describe async rendering await new Promise(resolve => setTimeout(resolve, 2000))The current example is complicated to understand  | 
    
Allow resolving nested components via defineAsyncComponent.
923e4af    to
    2c3edc2      
    Compare
  
    
          
 Added back the  
 I can change the example if you prefer; however, note that a simplified example wouldnβt demonstrate how to prevent recursion (an infinite loop whereby a block component imports itself). This seems like a common pattern that may prevent questions down the line, but Iβm happy to simplify the example if you donβt think itβs needed?  | 
    
| 
           @farnabaz I've updated the playground to include a Simple Async Example (the default) and an Advanced Async Example (to demonstrate how to bypass infinite loops due to recursion). Let me know if you'd prefer any other changes  | 
    
| 
           @adamdehaven I've pushed an update for the resolve component helper. Could you confirm its behavior in your project?  | 
    
| 
           @farnabaz yep it looks like everything still works (I tested in the playground pages I added in this PR). It looks like the links for the pages I added in the playground header got removed (but the playground itself is still functional at   | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks

π Linked issue
#263
β Type of change
π Description
The
MDCRenderersupports rendering nested async components and can allow its child component tree to resolve their internal top-levelasync setup()before allowing the parentMDCRendererto resolve. The implementation, while powerful, isn't immediately clear in the current documentation.This behavior allows for introducing MDC block components that themselves can perform async actions, such as fetching their own data before allowing the parent component to resolve.
In order for the parent
MDCRenderercomponent to properly wait for the child async component(s) to resolve:All functionality in the child component must be executed within an async setup function with top-level
await(if no async/await behavior is needed in the child, e.g. no data fetching, then the component will resolve normally).The child component's
templatecontent should be wrapped with the built-inSuspensecomponent with thesuspensibleprop set totrue.In a Nuxt application, this means that setting
immediate: falseon anyuseAsyncDataoruseFetchcalls would prevent the parentMDCRendererfrom waiting and the parent would potentially resolve before the child components have finished rendering, causing hydration errors or missing content.Example: MDC "snippets"
To demonstrate how powerful these nested async block components can be, you could allow users to define a subset of markdown documents in your project that will be utilized as reusable "snippets" in a parent document.
You would create a custom block component in your project that handles fetching the snippet markdown content from the API, use
parseMarkdownto get theastnodes, and render it in its ownMDCorMDCRenderercomponent.See the code in the playground
PageSnippetcomponent as an example, and to see the behavior in action, check out the playground by runningpnpm devand navigating to the/async-componentsroute.Handling recursion
If your project implements a "reusable snippet" type of approach, you will likely want to prevent the use of recursive snippets, whereby a nested
MDCRendererattempts to then load another child somewhere in its component tree with the same content (meaning, importing itself) and your application would be thrown into an infinite loop.One way to get around this is to utilize Vue's
provide/injectto pass down the history of rendered "snippets" so that a child can properly determine if it is being called recursively, and stop the chain. This can be used in combination with parsing theastdocument nodes after calling theparseMarkdownfunction to strip out recursive node trees from theastbefore rendering the content in the DOM.For an example on how to prevent infinite loops and recursion with this pattern, please see the code in the playground's
PageSnippetcomponent.