Giter VIP home page Giter VIP logo

astro-seo's Introduction

Astro SEO Logo

🚀 Astro SEO

This Astro component makes it easy to add tags that are relevant for search engine optimization (SEO) to your pages.

The ultimate goal is to make this the one-stop shop for most of your SEO needs when developing Astro sites.

Pull requests and/or feature requests are very welcome!

Installation

To install Astro SEO, run the following command in your terminal:

npm install astro-seo

or if you use yarn:

yarn add astro-seo

How To Use

In any of your Astro pages, import Astro SEO and then use the component inside the <head> section of your HTML:

---
import { SEO } from "astro-seo";
---

<html lang="en">
  <head>
    <SEO
      title="A Very Descriptive Title"
      description="A heavily optimized description full of well-researched keywords."
      openGraph={{
        basic: {
          title: "A Very Descriptive Title",
          type: "A type.",
          image: "https://user-images.githubusercontent.com/5182256/131216951-8f74f425-f775-463d-a11b-0e01ad9fce8d.png",
        }
      }}
      twitter={{
        creator: "@jonasmerlins1"
      }}
      extend={{
        // extending the default link tags
        link: [{ rel: "icon", href: "/favicon.ico" }],
        // extending the default meta tags
        meta: [
          {
            name: "twitter:image",
            content: "https://user-images.githubusercontent.com/5182256/131216951-8f74f425-f775-463d-a11b-0e01ad9fce8d.png",
          },
          { name: "twitter:title", content: "Tinker Tailor Soldier Spy" },
          { name: "twitter:description", content: "Agent" },
        ],
      }}
    />
    // ... rest of <head>
  </head>
    <body> // ... body </body>
</html>

Supported Props

Propname Type Description
title string The title of the page.
titleTemplate string Provide a title template to keep a consistent title style. %s — Astro SEO, %s will be replaced with your title, e.g. Homepage — Astro SEO
titleDefault string Fallback title that is used if no title is provided.
description string Text that gives a concise description of what your page is about.
canonical string Prevent duplicate content issues by specifying the "canonical" or "preferred" url of a web page. If you don't define this, Astro.url.href will be used as the default value.
noindex boolean Set this to true if you don't want search engines to index your page. Since this is an SEO component, this gets set to false by default. This way, indexing is strictly opt-out.
nofollow boolean Set this to true if you don't want search engines to follow links on your page. Since this is an SEO component, this gets set to false by default. This way, following links is strictly opt-out.
charset string Set the charset of the document. In almost all cases this should be UTF-8.
languageAlternates Array<{ href: string; hrefLang: string }> List of language alternates for the page.
openGraph.basic.title string Set the title Open Graph should use. In most situations, this should be different from the value of the title prop. See this tweet to gain an understanding of the difference between the two. If you define this, you must define two other OG basic properties as well: type and image. (Learn more.)
openGraph.basic.type string Set the type Open Graph should use. If you define this, you must define two other OG basic properties as well: title and image. (Learn more.)
openGraph.basic.image string URL of the image that should be used in social media previews. If you define this, you must define two other OG basic properties as well: title and type. (Learn more.)
openGraph.basic.url string The canonical URL of your object that will be used as its permanent ID in the graph. Most likely either the url of the page or its canonical url (see above). If you define this, you must define the other 3 OG basic properties as well: title, type and image. (Learn more.). If you define the other 3 OG basic properties but don't define this, Astro.request.url.href will be used as the default value.
openGraph.optional.audio string A URL to an audio file to accompany this object.
openGraph.optional.description string A one to two sentence description of your object.
openGraph.optional.determiner string The word that appears before this object's title in a sentence. An enum of (a, an, the, "", auto). If auto is chosen, the consumer of your data should chose between "a" or "an". Default is "" (blank).
openGraph.optional.locale string The locale these tags are marked up in. Of the format language_TERRITORY. Default is en_US.
openGraph.optional.localeAlternate Array An array of other locales this page is available in.
openGraph.optional.siteName string If your object is part of a larger web site, the name which should be displayed for the overall site. e.g., "IMDb".
openGraph.optional.video string A URL to a video file that complements this object.
openGraph.image.url string For now, setting this is ignored. This is done because og:image:url is supposed to be identical to og:image. If you have a use case where it makes sense for these to be different, please feel free to contact me, and tell me about it and I will consider adding it. Until then, in the interest of enforcing best practices, the value of this property will be ignored and og:image:url set to the value of openGraph.basic.image.
openGraph.image.secureUrl string Sets og:image:secure_url: An alternate url to use if the webpage requires HTTPS.
openGraph.image.type string Sets og:image:type. A MIME type for the image. e.g. "image/jpeg"
openGraph.image.width number Sets og:image:width. The number of pixels wide.
openGraph.image.height number Sets og:image:height. The number of pixels high.
openGraph.image.alt string Sets og:image:alt. A description of what is in the image (not a caption). If the page specifies openGraph.basic.image it should specify openGraph.image.alt.
openGraph.article.publishedTime string Sets article:published_time. The date the article was published. Must be a ISO 8601 DateTime string.
openGraph.article.modifiedTime string Sets article:modified_time. The date the article was last modified. Must be a ISO 8601 DateTime string.
openGraph.article.expirationTime string Sets article:expiration_time. The date the article will no longer be relevant. Must be a ISO 8601 DateTime string.
openGraph.article.authors string[] Sets article:author. The author(s) of the article, if it's only one, pass an array with one entry. If there are multiple, multiple tags with descending relevance will be created.
openGraph.article.section string Sets article:section. A high-level section name. E.g. Technology
openGraph.article.tags string[] Sets article:tag. Tag words associated with this article. If it's only one, pass an array with one entry. If there are multiple, multiple tags with descending relevance will be created.
twitter.card TwitterCardType (string) Sets twitter:card. The card type. Must be one of “summary”, “summary_large_image”, “app”, or “player”.
twitter.site string Sets twitter:site. (Twitter) @username for the website used in the card footer.
twitter.creator string Sets twitter:creator. (Twitter) @username for the content creator / author.
twitter.title string Sets twitter:title. Title of the page or article (equivalent to Open Graph's og:title).
twitter.image string Sets twitter:image. Full link to the image you want to use for the page (equivalent to Open Graph's og:image).
twitter.imageAlt string Sets twitter:image:alt. A description of what is in the image (not a caption). If the page specifies twitter.image it should specify twitter.imageAlt.
twitter.description string Sets twitter:description. A one to two sentence description of your object.
extend.link Array<Link extends HTMLLinkElement { prefetch: boolean; }> An array of free-form <link> you'd like to define.
extend.meta Array<Meta extends HTMLMetaElement { property: string; }> An array of free-form <meta> tags you'd like to define.

Extending Astro SEO

With the v0.3.14 release, you can now define any <meta> and <link> tag you want using the extend prop. For example :

<SEO
  extend={{
    // extending the default link tags
    link: [{ rel: "icon", href: "/favicon.ico" }],
    // extending the default meta tags
    meta: [
      {
        name: "twitter:image",
        content:
          "https://user-images.githubusercontent.com/5182256/131216951-8f74f425-f775-463d-a11b-0e01ad9fce8d.png",
      },
      { name: "twitter:title", content: "Tinker Tailor Soldier Spy" },
      { name: "twitter:description", content: "Agent" },
    ],
  }}
/>

Open Graph

Open Graph properties are passed as one object to the prop openGraph. The structure of this object is modeled after the Open Graph documentation itself. That means it uses nested objects to differentiate between basic and optional properties, as well as object specific ones. If you pass an openGraph config, you must define all 4 of the basic properties (title, type, image and url). The optional properties are all ... well, optional.

// TypeScript interface of openGraph prop
openGraph?: {
  basic: {
    title: string;
    type: string;
    image: string;
    url: string;
  },
  optional?: {
    audio?: string;
    description?: string;
    determiner?: string;
    locale?: string;
    localeAlternate?: Array<string>;
    siteName?: string;
    video?: string;
  }
}

Goals

Our first goal for this project is to support the most-used tags that are relevant for SEO. That includes the most-used open graph tags.

After that comes feature-parity with Next SEO. After that ... we'll see.

What does this component do, exactly?

There's certainly no magic to what Astro SEO does. Basically, it bundles the creation of regular SEO-relevant HTML tags inside one component that you can then use inside your page's <head> tag.

The translation between props and tags is pretty direct and almost 1:1. After building, there probably won't be anything you wouldn't have written yourself. The idea is to surface the options that exist in a central place and adhere to best practices where it's theoretically possible not to. If you want to see how the sausage gets made, there's only one place you will have to check: /src/SEO.astro

If you want, you can view Astro SEO as a checklist, so you don't forget a tag. Or maybe also as an educational tool, to see which options exist in the first place.

Acknowledgements

Astro SEO is heavily inspired by Next SEO and all the amazing work Gary is doing developing it. Thanks Gary! ❤️

astro-seo's People

Contributors

alex-grover avatar alexmacarthur avatar bl4ckm0r3 avatar c0casio45 avatar charafmrah avatar diegomarty avatar finewolf avatar fujiwaracj avatar gloopsies avatar gvkhna avatar jasikpark avatar jasontyping avatar johnhenry avatar jonasmerlin avatar kylefontenot avatar mansi1 avatar markpinero avatar matteodf avatar mikeethedude avatar rafidmuhymin avatar reaganchisholm avatar shigaichi avatar tugrulates avatar tycrimm avatar ultrasites avatar zaosoula avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

astro-seo's Issues

Can't export `Props` into plain typescript file

I'm simply trying to:

import type {Props} from 'astro-seo';

But I get this error:

Module '"astro-seo"' has no exported member 'Props'.

I can successfully import into a .astro file. Just not a .ts file.

Security

Hey,
It may a bit off topic but adding the most common security headers may be a good idea

Strict-Transport-Security <- strengthens tls implementation

Content-Security-Policy <- prevent xss attack
X-XSS-Protection <- same

X-Frame-Options <- prevent clickjacking

X-Content-Type-Options <- prevent MIME sniffing

Referrer-Policy <- control how much information the browser with navigation
enum ReferrerPolicy {
"",
"no-referrer",
"no-referrer-when-downgrade",
"same-origin",
"origin",
"strict-origin",
"origin-when-cross-origin",
"strict-origin-when-cross-origin",
"unsafe-url"
};

Permissions-Policy <- controle wich feature and api can be used

Title with unicode doesn't work

Thanks for the utility! I think I've found a bug. It seems that setting the <SEO title= field to some unicode breaks the generated HTML:

Screenshot 2024-02-22 at 15 26 40

💡 Feature Request: Type extend.link

Hello, it would be nice if the Link could be passed an optional parameter that is the "type", to be able to do, for example:

<link rel="icon" type="image/svg+xml" href="/favicon.svg" />

Greetings!

How to use in pure .md

How can I use astro-seo in markdown files?

I am using Astro Starlight and would love to display custom tags defined in my Frontmatter.

For example

<meta property="fc:frame" content="vNext" />

when using Starlight to extend head I can't get it in there as in my .md

title: "My sample .md"
head:
  - tag: meta
    content: vNext

doesn't give me the equivalent as it's missing property

How would I do this with astro-seo? in .astro pages I could use the SEO component and pass the extended meta tags though I can't use components in .md files and would love to do it in frontmatter

is there a solution potentially with just pure .md? or if not then with .mdx?

Add advanced Example to readme

Please add how an advanced example looks like in the readme, it will reduce lot of friction on how to format esp when title, opengraph etc. are different.

You defined openGraph.basic.image, but didn't define openGraph.image.alt. This is stongly discouraged.'

I'm still wondering it should be inside the basic object or should create a new image object. The typescript autocomplete doesn't also help here. So an advanced example of a valid use case would be great.

Import SEO component doesn't pass astro check

In a fresh and empty project (with astro-seo version ^0.5.0 installed), running astro check will fail if you include astro-seo as the documentation states.

---
import { SEO } from "astro-seo";
---
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width" />

		<SEO
			title="A Very Descriptive Title"
			description="A heavily optimized description full of well-researched keywords." />
	</head>
	<body>
		<h1>Astro</h1>
	</body>
</html>
> @example/[email protected] check
> astro check

src/pages/index.astro:1:20 - Cannot find module 'astro-seo' or its corresponding type declarations.
1  import { SEO } from "astro-seo";
                       ~~~~~~~~~~~

Found 1 errors.

Position of name and value makes it difficult to quickly read metatag values.

I'm willing to submit a pull request for this.

Right now the extended tags (src/components/ExtendedTags.astro) output from this project output with the content before the name and that makes it difficult to parse at a glance.

      content={content}
      http-equiv={httpEquiv}
      media={media}
      name={name}
      property={property}
    />

I'd think it would make it easier if the name and property were the first attributes filled there.

Displaying OG info

While title and description print out just fine, using the following doesn't render any opengraph meta tags in Astro 1.6.9. What am I doing wrong?

<SEO
title={title ? title : `My title`}
description={description ? description : `My description`}
openGraph.basic.title={ogTitle ? ogTitle : `My OG title`}
openGraph.basic.type="website"
openGraph.basic.image="./images/og.jpg"
openGraph.basic.url="https://website.com"
/>

Getting strange errors when conditionally loading <SEO /> component.

Hello,

Thanks for this package.

Running into an issue when conditionally loading the <SEO /> component with different data.

Here is a minimal example.

Here is [product].astro

---
import MainLayout from '@layouts/MainLayout.astro'
---

<MainLayout pageType="product" data={productData}>
    <!-- children here -->
</MainLayout>

Then here is MainLayout.astro:

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <style>
            svg {
                width: 1em;
                height: 1em;
                /* maybe even... */
                color: currentColor;
            }
        </style>

        {
            pageType && pageType === 'product' && (
                <>
                    <SEO
                        title={title}
                        description={description}
                        openGraph={{
                            image: {
                                alt: title,
                            },
                            basic: {
                                title: title + ' Company',
                                image: imageSrc,
                                imageAlt: imageAlt,
                                type: 'product',
                            },
                        }}
                        twitter={{
                            creator: '@company',
                        }}
                        extend={{
                            // extending the default meta tags
                            meta: [
                                {
                                    name: 'twitter:image',
                                    content: imageSrc,
                                },
                                { name: 'twitter:title', content: title },
                                {
                                    name: 'twitter:description',
                                    content: description,
                                },
                            ],
                        }}
                    />
                    
                </>
            )
        }
        {
            (pageType && pageType !== product && pageType === 'home') ||
                 && (
                    <SEO
                        title="Company - Home"
                        description="Lorem ipsum dolor sit amet, eos ad adhuc minim possim. Cu phaedrum intellegat eum. Persius eligendi est in, vix iriure splendide ad. Sed doctus detraxit legendos eu, quo eu mollis tamquam. Populo consequat efficiendi vix in."
                        openGraph={{
                            image: {
                                alt: 'Company',
                            },
                            basic: {
                                title: 'Company - Home',
                                image: openGraphImage,
                                imageAlt: 'Company',
                            },
                        }}
                        twitter={{
                            creator: '@company',
                        }}
                        extend={{
                            // extending the default meta tags
                            meta: [
                                {
                                    name: 'twitter:image',
                                    content: openGraphImage,
                                },
                                {
                                    name: 'twitter:title',
                                    content: 'Company',
                                },
                                {
                                    name: 'twitter:description',
                                    content:
                                        'Lorem ipsum dolor sit amet, eos ad adhuc minim possim. Cu phaedrum intellegat eum. Persius eligendi est in, vix iriure splendide ad. Sed doctus detraxit legendos eu, quo eu mollis tamquam. Populo consequat efficiendi vix in.',
                                },
                            ],
                        }}
                    />
                ))
        }

        <!-- rest of <head> -->

^^ if I try to load <SEO /> conditionally like this I get very strange errors as if the home page is trying to load [product].astro.

Bottom line is, this doesn't work...how can we dynamically load data into <SEO />?

Undesired escaping of characters

I am passing an & character in my openGraph.basic.title field. I verified that the char is correctly passed as a prop into the SEO component, but in my final output it is changed to:
<meta property="og:title" content="[...] &#38; [...]">

Any ideas?

Tags aren't being added

For some reason every single twitter tag, og:description, every single article tag except for section aren't being added idk why. Is it a bug, I think? Is it me maybe I don't think so tho.

heres the source: https://github.com/yavko/website
The head output
image

Does anyone know what it could be?

Failed to load error when using 0.3.13

Setup

  • Astro 0.20.6
  • astro-seo 0.3.13

Seeing a bug when attempting to start or build astro. This happens just from importing asto-seo

index.astro

---
import { SEO } from "astro-seo";
---

<html>...content here</html>
yarn build

Relevant part of error:

[17:23:38] [esinstall:astro-seo] Failed to load ../src/SEO.astro
  Identifier 'props' has already been declared (Note that you need plugins to import files that are not JavaScript)

If I roll back 0.3.11 this doesn't happen.

Full error message:

[17:23:38] [snowpack] + [email protected]
[17:23:38] [esinstall:astro-seo] Failed to load ../src/SEO.astro
  Identifier 'props' has already been declared (Note that you need plugins to import files that are not JavaScript)
(node:96561) UnhandledPromiseRejectionWarning: Error: Install failed.
    at Object.install (/Users/tyler/workspace/rokt/rokt.com/node_modules/esinstall/lib/index.js:374:19)
    at async Object.installPackages (/Users/tyler/workspace/rokt/rokt.com/node_modules/snowpack/lib/cjs/sources/local-install.js:24:25)
    at async /Users/tyler/workspace/rokt/rokt.com/node_modules/snowpack/lib/cjs/sources/local.js:537:39
    at async PackageSourceLocal.buildPackageImport (/Users/tyler/workspace/rokt/rokt.com/node_modules/snowpack/lib/cjs/sources/local.js:444:30)
    at async PackageSourceLocal.prepare (/Users/tyler/workspace/rokt/rokt.com/node_modules/snowpack/lib/cjs/sources/local.js:220:13)
    at async startServer (/Users/tyler/workspace/rokt/rokt.com/node_modules/snowpack/lib/cjs/commands/dev.js:240:9)
    at async createSnowpack (file:///Users/tyler/workspace/rokt/rokt.com/node_modules/astro/dist/runtime.js:283:14)
    at async createRuntime (file:///Users/tyler/workspace/rokt/rokt.com/node_modules/astro/dist/runtime.js:303:7)
    at async build (file:///Users/tyler/workspace/rokt/rokt.com/node_modules/astro/dist/build.js:40:24)
    at async buildAndExit (file:///Users/tyler/workspace/rokt/rokt.com/node_modules/astro/dist/cli.js:12:15)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:96561) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:96561) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Standard Formatting

Would you be willing to accept a PR for adding either a Prettier configuration or editorconfig for this project?

Either would make it much easier for others to contribute without constantly making changes to the spaces, tabs, etc.

I'd be happy to submit a PR using either based on your preferences. I personally prefer prettier, but it does require more tooling on the developer side. Most IDEs are already 100% aware and compliant with editorconfig.

May I suggest these configurations based on your existing code:

Prettier

{
	"printWidth": 80,
	"semi": true,
	"singleQuote": false,
	"trailingComma": "all",
	"useTabs": true
}

editorconfig

# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org

root = true

[*]
indent_style = tab
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{astro,js,jsx,ts,tsx}]
quote_type = double

NOTE: In each, I have use tabs as the indentation vs spaces. Tabs have some significant accessibility benefits over spaces. Also, I used double quotes as your code already seems to have them.

P.S. editorconfig does not officially recognizequote_type but many IDEs respect this setting.

Get `Cannot find module 'astro-seo' or its corresponding type declarations.ts(2307)`

Hey, love your Astro integration! Does it/can it support typescript out of the box or by doing npm install @types/astro-seo? I get the following error when importing it into a page like so:

---
import { SEO } from "astro-seo";
---

Gives: Cannot find module 'astro-seo' or its corresponding type declarations.ts(2307)

I am fairly new to typescript, but pretty sure it can be added to the DefinitelyTyped repo, it's just a bit past my expertise how to.

At the moment I am supressing the typescript warning by using // @ts-ignore

Thanks for your contributions!

localized version of a webpage

ref : https://developers.google.com/search/docs/specialty/international/localized-versions?hl=fr

<link rel="alternate" hreflang="en-gb"
       href="https://en-gb.example.com/page.html" />
  <link rel="alternate" hreflang="en-us"
       href="https://en-us.example.com/page.html" />
  <link rel="alternate" hreflang="en"
       href="https://en.example.com/page.html" />
  <link rel="alternate" hreflang="de"
       href="https://de.example.com/page.html" />
 <link rel="alternate" hreflang="x-default"
       href="https://www.example.com/" />

This feature can be implemented by using an array as input or defining each country code and giving the url (following next example)

<SEO
   alternate= {{
       en: "https://en.example.com/page.html",
       en_US: "https://en-us.example.com/page.html",
       de: "https://de.example.com/page.html",
       default: "https://www.example.com/"
   }}
/>

Please consider providing a way to disable the same title warning

Specifically, this line.

It's quite opinionated to suggest the OG title should not be the same as the page title: it entirely depends on the page and application. (I understand the point that the linked Tweet is making but it's not relevant to my use case, which uses the heading as the page title and therefore both title and OG title are the same value.)

If it were me, I would remove this altogether and leave it up to the user to decide how they want to configure their site.

Screenshot 2023-02-21 at 4 51 50 PM

Setting charset within Extend

Setting meta: [{ name: "charset", charset: "utf-8" }] within the extend object doesn't produce the correct results.

Results render as <meta content="utf-8" name="charset">.
The valid result should be <meta charset="utf-8">.

Unfortunately, setting meta: [{ charset: "utf-8" }] is invalid and produces no result.

Cannot read properties of undefined (reading 'href') with Astro v0.26

From the Migration docs
Astro.request has been changed to a standard Request object.

  • Move Astro.request.canonicalURL to Astro.canonicalURL

Causes the following ERROR

Cannot read properties of undefined (reading 'href')
TypeError: Cannot read properties of undefined (reading 'href')
    at /node_modules/astro-seo/src/SEO.astro:106:28
    at renderToString (/node_modules/astro/dist/runtime/server/index.js:329:27)
    at Module.renderComponent (/node_modules/astro/dist/runtime/server/index.js:125:26)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

When charset is set inside the SEO component, it's placed after the title tag

These days, a typical HTML5 file will begin something like:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    ...
    <title>Title comes later</title>

The meta charset tag is almost always the first tag inside the head tag, because the HTML5 specification suggests placing the charset declaration within the first 1024 bytes of the document.

Placing the charset declaration first clarifies the character encoding for the entire document, including the title, ensuring proper interpretation of characters. While modern browsers are robust, in rare cases, placing the title before the charset might lead to rendering issues, especially if the title includes non-ASCII characters.

The SEO component provided by astro-seo lets one set the value of charset. If one does that, the generated HTML has the title tag before the charset declaration. That is an issue.

Thoughts on How to Fix this Issue

The first thing you might be tempted to do is put the meta charset tag first, before the title tag. The problem with that is that there might be lots of other tags before the SEO component, inside the head tag. The SEO component has no control over those tags. They're put there by the user of the SEO component, not by the SEO component itself.

The final generated HTML should have the charset declaration first (inside the head tag), yet the SEO component can't do that.

Moreover, the charset declaration isn't really an SEO thing anyhow. It's more like the meta viewport tag.

Therefore, my conclusion is that the SEO component provided by astro-seo should be changed to no longer accept a value for charset, and it should no longer try to set it. Anyone who tries to use the SEO component to set charset should be told it's being deprecated and they should just set it manually, first thing inside the head tag. Then in the future, the charset prop could be removed from the SEO component completely.

Add support for twitter:image

And the other relate attributes like twitter:image:alt. I know this isn't necessary because most platforms use opengraph and twitter interchangeably, but it's important for completions sake.

How to use image from Local image?

On Astro file, this is how to load image from local image

index.astro
<!-- Local image stored at public/assets/stars.png --> <img src="/assets/stars.png" alt="A starry night sky.">

Using similar value on the image Propname doesn't work

---
import { SEO } from "astro-seo";
---

<html lang="en">
  <head>
    <SEO
      title="A Very Descriptive Title"
      description="A heavily optimized description full of well-researched keywords."
      openGraph={{
        basic: {
          title: "A Very Descriptive Title",
          type: "A type.",
          image: "/assets/stars.png",
        }
      }}
    />
    // ... rest of <head>
  </head>
    <body> // ... body </body>
</html>

charset is a bit controversial

Suggestion

charset is a bit controversial as a parameter. It produces something like this:

<meta charset="UTF-8">

It looks like it is a meta parameter but it has to be added as a separate attribute:

<SEO charset='UTF-8'
...
/>

My suggestion is to either add it to the extend meta section or to write about it being a separate <SEO /> attribute in the README.

OpenGraph Image Missing `name=image` Property Causes Image Not Loading

Sites using OpenGraph wouldn't recognize my image and I wasn't sure why. Used LinkedIn's Post Inspector tool which mentions a name=image property on the og:image meta tag. Using the extend functionality to create this meta tag myself fixed the issue. It's strange because OpenGraph's docs don't indicate this being required...

I'm happy to PR but wanted to submit this as a bug first.

You can serve this repro with ngrok to paste the link into the Post Inspector. Visit src/layouts/Base.astro and swap out my old ngrok URL with yours. And make sure to use the same commit as linked!
https://github.com/ari-gibson-consulting-llc/brielle-french-design/tree/8a05ec2ffcf372c2841f0ca416c0273cadae6626

Default values and overiding them

Could you provide an example of the use of default values for the SEO component? Default OpenGraph values for example.

Regular astro pages have the same default opengraph values and then blog posts might specifically have an image that
is used for OpenGraph image and text on the blog post page.

This is most probably a basic javascript question but unfortunately, I dable mainly in python.

---
import { SEO } from "astro-seo";
import { Markdown } from "astro/components";
let noindex = true; // Override the default value here
---

<SEO
  title="Default title foo"
  description="This ios a long description"
  {noindex ? 'noindex='{noindex} : null}
/>

<Markdown>
  # This is a header

  This is some text
</Markdown>

Typo in src/components/ExtendedTags.astro

There is a typo in the src/component/ExtendedTags.astro file which causes the plugin not to render the http-equiv parameter in a proper way when extending <meta> tags.

The media attribute is ignored when included in extend.meta

Since astro-seo does not have built in support for meta elements with the name "theme-color", the preferred method to include those meta elements would be to use extend.meta. Those meta elements can use a "media" attribute.

Extending the meta element in astro-seo would look something like this:
{ name: "theme-color", media: "(prefers-color-scheme: dark)", content: theme_color_dark },

However, astro-seo seems to ignore the media attribute so that the output will just look something like this, missing the media attribute:
<meta content="#010101" name="theme-color">

Workaround is just to enter the meta tag the old fashioned way in the source. But perhaps astro-seo can support this use case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.