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

fix(astro): better default meta tags #342

Merged
merged 14 commits into from
Oct 1, 2024

Conversation

eric-burel
Copy link
Contributor

@eric-burel eric-burel commented Sep 20, 2024

This PR proposes to use the site logo as the default open graph image, and sets up better default meta tags for opengraph and twitter.

(please double check as opengraph display is usually tested on deployed instances, I couldn't test them locally aside from reading them in the browsers element tab)

Btw I don't think the BASE_URL env variable is documented, to have a proper absolute URL for meta tags.

Copy link

stackblitz bot commented Sep 20, 2024

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@eric-burel eric-burel changed the title Better default meta tags feat: better default meta tags Sep 20, 2024
@AriPerkkio
Copy link
Member

I'll take a look at the code next week, but another idea came into my mind: Should we create new MetaData component that authors could use to define completely custom meta tags? https://tutorialkit.dev/guides/overriding-components/

So something like:

import tutorialkit from '@tutorialkit/astro';
import { defineConfig } from 'astro/config';

export default defineConfig({
  integrations: [
    tutorialkit({
      components: {
        MetaData: './src/components/MetaTags.astro',
      },
    }),
  ],
});

And then in ./src/components/MetaTags.astro you would get access to default meta tags, and you could decide whether to use them or not. And of course add your custom ones there too.

Improving default meta tags is important too.

@eric-burel
Copy link
Contributor Author

Definitely, I've thought about a Metadata component but then the question is how to pass the settings from a lesson to this component
Maybe using the lesson slug as a unique id
This also joins the question of accessing lesson metadata from the content collection to generate tables of content rss feeds etc.

Copy link
Member

@AriPerkkio AriPerkkio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but as I'm not super familiar with Open Graph, @Nemikolh & @sulco what do you think?

I think @sulco you mentioned something about social preview picture generation in the past. 🤔

@AriPerkkio AriPerkkio changed the title feat: better default meta tags fix: better default meta tags Sep 23, 2024
@AriPerkkio AriPerkkio changed the title fix: better default meta tags fix(astro): better default meta tags Sep 23, 2024
Copy link
Member

@Nemikolh Nemikolh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea a lot! Thanks for the PR! 😃

I've left a couple of things to address. @AriPerkkio Or do you want to merge this as is and address the feedback in a follow-up PR?

packages/astro/src/default/layouts/Layout.astro Outdated Show resolved Hide resolved
@@ -17,7 +17,7 @@ type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const { lesson, logoLink, navList, title } = Astro.props as Props;
---

<Layout title={title}>
<Layout title={title} description="A TutorialKit interactive lesson">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this should come from the metadata. You can grab it from Astro.props here and then it needs to be returned as part of generateStaticRoutes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nemikolh I would advise to improve the collection, rather than generateStaticRoutes, to allow feeding more data to the "lesson" object.
Because generateStaticRoutes is specific to this page only and is difficult to reuse if you want to craft a sitemap or an RSS feed. And you still need a way to pass some metadata from your MDX file to feed "generateStaticRoutes". That's why I couldn't come up with a more customizable/elegant solution yet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey! I think I should have provided more pointers, sorry!

Let me explain. So here's what we need to do:

export const metaTagsSchema = z.object({
  // ideally we would have want to use image from 
  // https://docs.astro.build/en/guides/images/#images-in-content-collections
  // but we can't so we'll need a custom logic (see below)
  image: z.string().optional().describe('An image to show on social previews'),
  description: z.string().optional().describe('...'),
  title: z.string().optional().describe('...'),
})

...

export const webcontainerSchema = commandsSchema.extend({
  meta: metaTagsSchema.optional()
    .describe('Configure Open graph meta tags for previews on social medias'),
  ...
});
  • Add 'meta' here:

[
'mainCommand',
'prepareCommands',

  • Now we could handle image in the same file when the collection is traversed to resolve all the relative path to be fully resolved. However that won't be enough to have them included in the final bundle. Instead for now we can limit ourselves to images residing in the public folder (so starting with /).

  • Finally update [...slug].astro to use the new lesson.meta?.<prop> properties

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nemikolh right thanks for the insight, I was not sure if this should be implemented in user-land or not but it seems a sound idea to have at least a title, description and image default setting, having a finer grained system (eg you want a different image for OpenGraph and Twitter, or images outsides of /public or even generated via an API) would be worth a different PR I think

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree! Yeah, let's start with a simple set of settings and move to a finer grained system later 👍

@Nemikolh
Copy link
Member

I'll take a look at the code next week, but another idea came into my mind: Should we create new MetaData component that authors could use to define completely custom meta tags?

That's a good idea. I think this can be done in a second step.

Like @eric-burel said you still want the data like img, title and description to be defined as part of the metadata of a part / chapter / lesson. Especially because you might want to have a common social preview per chapter but not for the entirety of your tutorial which means that the source of the data is better expressed directly in the metadata.

So I think if we start with this first, it should be pretty nice for most use cases 👍

@eric-burel
Copy link
Contributor Author

eric-burel commented Sep 26, 2024

I have a small doubt on the update I've done in the documentation : I documented the BASE_URL variable, which is used to compute the logo, favicon or public images. Initially I thought this would the absolute URL of the application (you want absolute urls for open graph tags) but I am not sure. It seems to be a variable set by Astro and which might rather be a kind of separate directory, eg to handle a monorepo.
But I am not sure, wha'ts your opinion on this @Nemikolh ?
Update: it seems that we might want to use Astro.site in this scenario but I still don't totally grasp "BASE_URL", if we should use both to compute the final absolute URL.

Also I get a messy file diff on GitHub, not sure why. I rebased the branch on "upstream/main" where upstram points on "stackblitz/main" before updating the PR today. Perhaps I should have merged instead?
This page shows a cleaner diff.

@eric-burel
Copy link
Contributor Author

I still don't exactly get what BASE_URL is, but I figured that Astro.site is what I want for absolute URLs, I've pushed an update in this direction.
It's not super elegant but the SEO tags are at least correct.

@Nemikolh
Copy link
Member

Hey @eric-burel !

Do you think you could rebase this PR on top of the latest version of main? This would help reviewing this.

So you do git fetch <stackblitz-tk-remote> and then git rebase <stackblitz-tk-remote>/main. Trying this, you should only get a single conflict on packages/astro/src/default/layouts/Layout.astro.

If you want I can also do it for you, but that means that I'll force push to your branch and you'll have to reset it to the origin. Let me know what you prefer 🙌

@eric-burel
Copy link
Contributor Author

@Nemikolh done, I think I've messed up at some point and used a "merge" instead. It has fixed the diff 👌

@eric-burel
Copy link
Contributor Author

I've also updated the logic to access the site absolute URL, I found another doc explaining that Astro.site will feed the import.meta.env.SITE env variable for consumption in JS files https://docs.astro.build/en/guides/environment-variables/
Ideally this would be set to "http://localhost:4321" in dev but I am not sure how to reliably get the right port.
Astro.url automatically has an absolute URL in development but it's not the right solution, because it's based on the current HTTP request to get a full path while we just want the website root URL so the site value.

@Nemikolh
Copy link
Member

Looking at the PR again, I would keep the previous usage of BASE_URL in place of site for resources loaded by the browser (so everything that is not OG or Twitter related) as those links can be relative and don't have to be absolute.

A big downside of forcing them to be absolute is that it makes preview deployment with cloudflare or netlify a bit more annoying as they would need a custom build.

Regarding your question on what BASE_URL is, see the docs on base.

Copy link
Member

@Nemikolh Nemikolh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good! Good job on this 🌟

packages/astro/src/default/components/MetaTags.astro Outdated Show resolved Hide resolved
packages/astro/src/default/components/MetaTags.astro Outdated Show resolved Hide resolved
packages/astro/src/default/utils/routes.ts Outdated Show resolved Hide resolved
packages/astro/src/default/utils/favicon.ts Outdated Show resolved Hide resolved
@eric-burel
Copy link
Contributor Author

Hi, I'll get back at the few last comments, but in the meantime I've opened a proposal for a portal system in Astro: withastro/roadmap#1032

This would make it easier to support any type of tag that lands into <head> without having to support a full-fledged intermediate JSON représentation that fits into the YAML frontmatter. Not that it's impossible, it's Next.js approach with the metadata object, but maybe more work than it should at framework-level for something that could be done in user-land with good old HTML.

I am thinking of alternate links for instance that I will need in AstroPatterns/NextPatterns because I translate similar content for 2 frameworks and may be punished by Google for that if I don't provide alternate links.

@eric-burel
Copy link
Contributor Author

eric-burel commented Sep 30, 2024

Looking at the PR again, I would keep the previous usage of BASE_URL in place of site for resources loaded by the browser (so everything that is not OG or Twitter related) as those links can be relative and don't have to be absolute.

BASE_URL is still there, and optionally the absolute option can be used to also append the whole website URL via Astro.site. site is only actually used when using the logo as the default ogImage, or passing your own, though I think having it as an option in readPublicAsset may be useful.

I've removed the absolute path for the favicon though, which indeed was a mistake.

A big downside of forcing them to be absolute is that it makes preview deployment with cloudflare or netlify a bit more annoying as they would need a custom build.

If you don't set Astro.site you'll just come up with a warning. I think you are expected to use an env variable in astro.config to handle these cases? Eg Vercel preview URLs.

Let me know if I got something wrong!

Copy link
Member

@Nemikolh Nemikolh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really good! Good work on this @eric-burel !

Just a few minor nits and it's good to go 🙌

packages/astro/src/default/pages/[...slug].astro Outdated Show resolved Hide resolved
packages/types/src/schemas/metatags.ts Outdated Show resolved Hide resolved
Copy link
Member

@AriPerkkio AriPerkkio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thanks @eric-burel!

@AriPerkkio AriPerkkio merged commit d81d1cc into stackblitz:main Oct 1, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants