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

Dynamic Page Meta #4580

Open
jdbranham opened this issue Jan 2, 2025 · 9 comments
Open

Dynamic Page Meta #4580

jdbranham opened this issue Jan 2, 2025 · 9 comments
Labels
enhancement Anything you want improved

Comments

@jdbranham
Copy link

jdbranham commented Jan 2, 2025

I'd like to dynamically provide the page metadata values.

  • Which feature do you want to improve? (and what problem does it have).

Specifically I have dynamic page routes like /page/[slug]
Since the page meta only allows str values, it prevents accurate meta data when the page is dynamic.

  • What is the benefit of the enhancement?

Improves page previews in social feeds and better SEO

  • Show an example/usecase were the improvement are needed.

Using the state would be great -

@rx.page(
    route="/page/[slug]/",
    on_load=State.load_page,
    meta=[
        {
            "name": "og:image",
            "content": State.image,
        },
        {
            "name": "title",
            "content": State.name,
        },
    ],
)
@jdbranham jdbranham added the enhancement Anything you want improved label Jan 2, 2025
Copy link

linear bot commented Jan 2, 2025

@masenf
Copy link
Collaborator

masenf commented Jan 7, 2025

currently you should be able to pass title as a kwarg with a state var.

for some of the meta attributes though, it doesn't really make sense to use dynamic values because many of the robots reading those meta tags will not run the whole javascript bundle to correctly resolve them and they most-likely will not have the correct value after server side rendering to html.

@jdbranham
Copy link
Author

Thanks @masenf - That makes sense.
I probably need a better understanding of the request and state lifecycle.

When I build a NextJS app manually, I can leverage SSR to populate that data before it reaches the browser.
Is there a similar way to leverage SSR (or something like it) in reflex?

Also, I'm happy to make some code contributions! Just getting familiar with project now 🎉

@PasqualePuzio
Copy link

currently you should be able to pass title as a kwarg with a state var.

for some of the meta attributes though, it doesn't really make sense to use dynamic values because many of the robots reading those meta tags will not run the whole javascript bundle to correctly resolve them and they most-likely will not have the correct value after server side rendering to html.

Would you mind sharing a little example of how to achieve that? i’m not sure I understood. Thanks

@jdbranham
Copy link
Author

jdbranham commented Jan 10, 2025

Also, for reference, when using the Pages routing mode, we could use the getServerSideProps function to provide the metadata.
I'm still digging into the code, but I think we could modify the page compilation process to account for dynamic routes and either use a new template or some conditions on when to use this function.

export default function Page({ data }) {
  // Render data...
}
 
// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API, Redis, Database, etc...
  const res = await fetch(`https://.../data`)
  const data = await res.json()
 
  // Pass data to the page via props
  return { props: { data } }
}

I see references to custom_code in the jinja templates that might be a way to inject additional JS functions, but I've not discovered how to leverage this yet.

A related concern might be for getStaticProps if the reflex export to static site needs to account for all potential dynamic values. I haven't tested this, and not yet familiar enough with the code to know.

@jdbranham
Copy link
Author

jdbranham commented Jan 10, 2025

I've verified the custom_code can inject the getServerSideProps function in page, and NextJS doesn't complain.
But I'm not sure this is the correct way to provide server side props, especially since the generated Page component doesn't currently receive props.
And the custom code would need to hook into the server python events or be pre-populated with data that could be passed to the generated page component as props.

class PageComponent(rx.Component):

    def _get_custom_code(self):
        log.debug(f"Adding custom code: {self}")
        return """
export async function getServerSideProps() {
  const data = {
    value: "xyz"
  }
  return { props: { data } }
}
"""

page_component = PageComponent.create

Also one more caveat - since reflex is exporting as a static site, the getServerSideProps function can't be used.
Maybe there's an option to not export a static site, but rather just build it? This might already be possible, but I need to get more familiar with the CLI.

#17 178.3 Error: Error for page /character/: pages with `getServerSideProps` can not be
#17 178.3 exported. See more info here: https://nextjs.org/docs/messages/gssp-export
#17 178.3     at exportPages

As a (not good) workaround I can create a NextHead element in the page component that will update the metadata, but it still happens client side, and has no benefit for SEO or social preview.

Just thinking outloud....
If the @rx.page had a server_side_props property, and we could provide a python function as the value, then perhaps the getServerSideProps function could be generated as part of the template and the result of the server_side_props function could be passed to the generated page component as props.

@PasqualePuzio
Copy link

I've verified the custom_code can inject the getServerSideProps function in page, and NextJS doesn't complain. But I'm not sure this is the correct way to provide server side props, especially since the generated Page component doesn't currently receive props. And the custom code would need to hook into the server python events or be pre-populated with data that could be passed to the generated page component as props.

class PageComponent(rx.Component):

    def _get_custom_code(self):
        log.debug(f"Adding custom code: {self}")
        return """
export async function getServerSideProps() {
  const data = {
    value: "xyz"
  }
  return { props: { data } }
}
"""

page_component = PageComponent.create

Also one more caveat - since reflex is exporting as a static site, the getServerSideProps function can't be used. Maybe there's an option to not export a static site, but rather just build it? This might already be possible, but I need to get more familiar with the CLI.

#17 178.3 Error: Error for page /character/: pages with `getServerSideProps` can not be
#17 178.3 exported. See more info here: https://nextjs.org/docs/messages/gssp-export
#17 178.3     at exportPages

As a (not good) workaround I can create a NextHead element in the page component that will update the metadata, but it still happens client side, and has no benefit for SEO or social preview.

Just thinking outloud.... If the @rx.page had a server_side_props property, and we could provide a python function as the value, then perhaps the getServerSideProps function could be generated as part of the template and the result of the server_side_props function could be passed to the generated page component as props.

Interesting find @jdbranham
We're also very interested in this matter, soon we'll have the same "problem" as we want to optimize our web app for SEO and need to dynamically create meta tags. Being able to create them starting from the URL (without having to send API requests or database queries) would be a good starting point.

@shekinahayorinde
Copy link

I'm currently at a road block trying to figure this out too.
Any luck?

@PasqualePuzio
Copy link

I'm currently at a road block trying to figure this out too. Any luck?

I don't think that right now Reflex can provide a solution for this, but there may be a workaround (not tested it yet).

You could use nginx to replace the content of the meta tags using a LUA script. Here's the building blocks of the solution:

https://stackoverflow.com/questions/13706658/variable-capture-in-nginx-location-matching
https://stackoverflow.com/a/52296679/343201
https://nginx.org/en/docs/http/ngx_http_sub_module.html

Not an ideal solution but it should work for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Anything you want improved
Projects
None yet
Development

No branches or pull requests

4 participants