Skip to content
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

💡 RFC: Vue Dynamic Components #1413

Closed
radohingis opened this issue Sep 22, 2021 · 4 comments
Closed

💡 RFC: Vue Dynamic Components #1413

radohingis opened this issue Sep 22, 2021 · 4 comments
Labels
pkg: vue Related to Vue (scope)

Comments

@radohingis
Copy link

radohingis commented Sep 22, 2021

Background & Motivation

Main idea

Main idea of this feature request is to render vue components on dynamic routes as they come from CMS API.

Proposed Solution

Possible solutions

Alternatives considered

Risks, downsides, and/or tradeoffs

Open Questions

Detailed Design

Example

To get a real world example what this feature should do, consider following [...slug].astro page in ~/pages folder.

First we import our DynamicVueComponent

---
import DynamicVueComponent from '../components/DynamicVueComponent.vue'

Consider DynamicVueComponent.vue as a parser between cms api and vue.
It is design for its minimal purpose. To render what is described in data it receives:

<template>
  <component :is="data.component_name" :data="data.component_data"></component>
</template>

<script>
export default {
  props: {
    data: {
      type: Object,
      required: true
    },
  }
}
</script>

You'll get the point along with reading further. Let's write some latest Astro:

export async function getStaticPaths() {
  const pages = await fetch(`https://yourfavoritecms.api.com/endpoint?token=token2et2wgssdgsd3`)
  .then(response => response.json())
  .then((endpointData) => endpointData);

Now consider endpointData as an array with objects. For example:

[
  {
    components: [
      {
        id: 21435252,
        component_data: {
          title: 'sample title 1',
          image: 'https://yourimageurl.com/image/200x320',
          description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris euismod venenatis lorem, vitae luctus lorem tincidunt vel. Ut blandit diam elit, bibendum vehicula quam dapibus a.'
        },
        component_name: 'card-with-image'
      },
      {
        id: 548350438,
        component_data: {
          title: 'sample title 2',
          image: 'https://yourimageurl.com/image2/200x320',
          description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris euismod venenatis lorem, vitae luctus lorem tincidunt vel. Ut blandit diam elit, bibendum vehicula quam dapibus a.'
        },
        component_name: 'card-with-image'
      },
    ]
    slug: 'home',
  },
  // ...and so on, more pages, more components on page, not important how many
]

Now consider you have multiple objects in your top level array you receive, and so you can use 'page' property to tell astro which pages it is going to build, since [...slug].astro page creation is possible, it is easy to even build pages that have slugs like '/blog/post-352gwgs23436'
Lets return an array of slugs for astro to generate

  return pages.map((page) => {
    return {
      params: {
         slug: page.slug
      },

Now astro knows which pages is it going to generate, but wait, we also need a content, not just blank pages.
And so we're using components property of our mapped pages

      props: {
        page
      }
    };
  });
}

And at the very end we also need to request Astro for props, so we can use them as variables in template later.

const { page } = Astro.props
---
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href={Astro.resolve("../assets/global.css")}>
    <title>{ page.slug }</title> //or anything more relevant, depends on CMS and api response
  </head>
  <body>
    <main>
       {page.components.map(component => (<DynamicVueComponent client:visible data={component} />))}
    </main>
  </body>
</html>

Conclusion

Even though Astro renders for example two cards on given slug, the question is how to tell Astro that he has to render these vue components? I tried to import for example
import CardWithImage from '../components/CardWithImage.vue' to [...slug].astro, but instead of component's template I was given just <CardWithImage><CardWithImage /> or astro-root component with my component in it, and also astro knew what data it has to hydrate, but simply couldn't render this component to it's template. I think the main issue is to tell Astro which vue components it has to import and use dynamically, no matter if they are hardcoded or dynamically rendered with our DynamicVueComponent.

@matthewp
Copy link
Contributor

Thanks for submitting @radohingis. I'm having a hard time understanding this issue, is this a proposal for a new feature? If so what is the new feature?

From reading this it sounds like you are saying that client-side Vue components are not working on dynamic route pages? If that's the case then this is a bug.

@radohingis
Copy link
Author

Thank you for getting involved in topic @matthewp. When you import Vue component to astro file and try to use it, it's not a problem. Problem is that Astro doesn't know which vue components are getting rendered via 'DynamicVueComponent.vue', and even if I import these files in astro page, or directly to DynamicVueComponent.vue, it's rendering only them as tags, not their templates. I'm looking for way how to tell Astro 'Hey, you need to know about all vue components in this project and be prepared to render them if necessary'. If you would like to get a little demonstration I would love to show you where is the problem on video call or google meet or smth :)

@jameslovallo
Copy link

I wasted a whole day trying to get this working and just took 3 Motrin for the headache it gave me. I’d also be happy to get on a call and discuss or provide code samples.

@drwpow drwpow added the pkg: vue Related to Vue (scope) label Oct 20, 2021
@FredKSchott
Copy link
Member

Hey everyone! Our current RFC process is beginning to break down at this size, with over 50 open RFCs currently in the "discussing" stage. A growing community is a great problem to have, but our ability to give you RFC feedback has suffered as a result. In an effort to improve our RFC process, we are making some changes to better organize things.

From now on, all RFCs will live in a standalone repo: https://github.com/withastro/rfcs

This allows us to do three things: 1) Use threaded discussions for high-level ideas and improvements, without necessarily requiring an implementation for every idea. 2) Improve the quality of our RFC template and the speed/quality of all feedback. 3) Support inline comments and explicit approvals on RFCs, via a new Pull Request review process.

We hope that this new process leads to better RFC weekly calls and faster feedback on your RFCs from maintainers. More detail can be found in the new RFC repo README.


We can't automatically convert this issue to an RFC in the new repo because new RFC template is more detailed that this one. But, you can still continue this discussion in the new repo by creating a new Discussion in the RFC repo and copy-and-pasting this post (and any relevant follow-up comments) into it. Discussions are available for high-level ideas and suggestions without the requirement of a full implementation proposal.

Then, when you are ready to propose (or re-propose) an implementation for feedback and approval, you can create a new RFC using the new RFC template. More detail about how to do this can be found in the new RFC repo README.

Thanks for your patience as we attempt to improve things for both authors and reviewers. If you have any questions, don't hesitate to reach out on Discord. https://astro.build/chat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: vue Related to Vue (scope)
Projects
None yet
Development

No branches or pull requests

5 participants