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

feat!: remove v1 meta API #6958

Merged
merged 14 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .changeset/remove-v1-meta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
"@remix-run/cloudflare": major
"@remix-run/deno": major
"@remix-run/dev": major
"@remix-run/node": major
"@remix-run/react": major
"@remix-run/server-runtime": major
"@remix-run/testing": major
---

We have made a few important changes to the route `meta` API as reflected in the v1 implementation when using the `future.v2_meta` config option.

- The `meta` function should no longer return an object, but an array of objects that map to the HTML tag's respective attributes. This provides more flexibility and control over how certain tags are rendered, and the order in which they appear.
- In most cases, `meta` descriptor objects render a `<meta>` tag. There are a few notable exceptions:
- `{ title: "My app" }` will render `<title>My app</title>`.
- `{ 'script:ld+json': { /* ... */ } }` will render `<script type="application/ld+json">/* ... */</script>`, where the value is serialized to JSON and rendered inside the `<script>` tag.
- `{ tagName: 'link', ...attributes }` will render `<link {...attributes} />`
- This is useful for things like setting canonical URLs. For loading assets, we encourage you to use the `links` export instead.
- It's important to note that `tagName` may only accept `meta` or `link`, so other arbitrary elements will be ignored.
- `<Meta />` will no longer render the `meta` output from the entire route hierarchy. Only the output from the leaf (current) route will be rendered unless that route does not export a `meta` function, in which case the output from the nearest ancestor route with `meta` will be rendered.
- This change comes from user feedback that auto-merging meta made effective SEO difficult to implement. Our goal is to give you as much control as you need over meta tags for each individual route.
- Our suggested approach is to **only export a `meta` function from leaf route modules**. However, if you do want to render a tag from another matched route, `meta` now accepts a `matches` argument for you to merge or override parent route meta as you'd like.
```tsx
export function meta({ matches }) {
return [
// render all ancestor route meta except for title tags
...matches
.flatMap((match) => match.meta)
.filter((match) => !("title" in match)),
{ title: "Override the title!" },
];
}
```
- The `parentsData` argument has been removed. If you need to access data from a parent route, you can use `matches` instead.
```tsx
// before
export function meta({ parentsData }) {
return [{ title: parentsData["routes/some-route"].title }];
}
// after
export function meta({ matches }) {
return [
{
title: matches.find((match) => match.id === "routes/some-route").data
.title,
},
];
}
```
2 changes: 1 addition & 1 deletion docs/api/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ title: Conventions

[Moved →][moved-36]

#### `HtmlMetaDescriptor`
#### `MetaDescriptor`

[Moved →][moved-37]

Expand Down
17 changes: 7 additions & 10 deletions docs/file-conventions/root.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ FIXME: This is mostly the wrong doc, right code.
These components are to be used once inside your root route (`root.tsx`). They include everything Remix figured out or built in order for your page to render properly.

```tsx
import type {
LinksFunction,
MetaFunction,
} from "@remix-run/node"; // or cloudflare/deno
import type { LinksFunction } from "@remix-run/node"; // or cloudflare/deno
import {
Links,
LiveReload,
Expand All @@ -29,16 +26,16 @@ export const links: LinksFunction = () => {
return [{ rel: "stylesheet", href: globalStylesheetUrl }];
};

export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "My Amazing App",
viewport: "width=device-width, initial-scale=1",
});

export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>

{/* All meta exports on all routes will go here */}
<Meta />

Expand Down
10 changes: 5 additions & 5 deletions docs/guides/constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export async function loader() {
}

export function meta() {
return { title: "Posts" };
return [{ title: "Posts" }];
}

export default function Posts() {
Expand All @@ -55,7 +55,7 @@ import { useLoaderData } from "@remix-run/react";
import PostsView from "../PostsView";

export function meta() {
return { title: "Posts" };
return [{ title: "Posts" }];
}

export default function Posts() {
Expand Down Expand Up @@ -90,7 +90,7 @@ export async function loader() {
}

export function meta() {
return { title: "Posts" };
return [{ title: "Posts" }];
}

export default function Posts() {
Expand All @@ -110,7 +110,7 @@ import PostsView from "../PostsView";
console.log(prisma); //🥶

export function meta() {
return { title: "Posts" };
return [{ title: "Posts" }];
}

export default function Posts() {
Expand All @@ -136,7 +136,7 @@ export async function loader() {
}

export function meta() {
return { title: "Posts" };
return [{ title: "Posts" }];
}

export default function Posts() {
Expand Down
15 changes: 9 additions & 6 deletions docs/guides/mdx.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ MDX routes allow you to define both meta and headers as if they were a code base
```md
---
meta:
title: My First Post
description: Isn't this awesome?
- title: My First Post
- name: description
content: Isn't this awesome?
headers:
Cache-Control: no-cache
---
Expand Down Expand Up @@ -56,8 +57,9 @@ By creating a `app/routes/posts.first-post.mdx` we can start writing a blog post
```mdx
---
meta:
title: My First Post
description: Isn't this just awesome?
- title: My First Post
- name: description
content: Isn't this just awesome?
---

# Example Markdown Post
Expand All @@ -72,8 +74,9 @@ You can even export all the other things in this module that you can in regular
```mdx
---
meta:
title: My First Post
description: Isn't this awesome?
- title: My First Post
- name: description
content: Isn't this awesome?

headers:
Cache-Control: no-cache
Expand Down
32 changes: 5 additions & 27 deletions docs/guides/migrating-react-router-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -653,35 +653,13 @@ export const links: LinksFunction = () => {

Just as a `<link>` is rendered inside your route component and ultimately rendered in your root `<Links />` component, your app may use some injection trickery to render additional components in the document `<head>`. Often this is done to change the document's `<title>` or `<meta>` tags.

Similar to `links`, each route can also export a `meta` function that—you guessed it—returns a value responsible for rendering `<meta>` tags for that route. This is useful because each route often has its own.

The API is slightly different for `meta`. Instead of an array, it returns an object where the keys represent the meta `name` attribute (or `property` in the case of OpenGraph tags) and the value is the `content` attribute. The object can also accept a `title` property that renders a `<title />` component specifically for that route.

```tsx filename=app/routes/about.tsx lines=[1,3-12]
import type { MetaFunction } from "@remix-run/node"; // or cloudflare/deno

export const meta: MetaFunction = () => {
return {
title: "About Us",
"og:title": "About Us",
description: "Doin hoodrat stuff with our friends",
"og:description": "Doin hoodrat stuff with our friends",
"og:image:url": "https://remix.run/og-image.png",
"og:image:alt": "Just doin a bunch of hoodrat stuff",
};
};
Similar to `links`, each route can also export a `meta` function that returns values responsible for rendering `<meta>` tags for that route (as well as a few other tags relevant for metadata, such as `<title>`, `<link rel="canonical">` and `<script type="application/ld+json">`).

export default function About() {
return (
<main>
<h1>About us</h1>
<PageContent />
</main>
);
}
```
The behavior for `meta` is slightly different from `links`. Instead of merging values from other `meta` functions in the route hierarchy, **each leaf route is responsible for rendering its own tags**. This is because:

Again—no more weird dances to get meta into your routes from deep in the component tree. Export them at the route level and let the server handle it. ✨
- You often want more fine-grained control over metadata for optimal SEO
- In the case of some tags that follow the [Open Graph protocol](https://ogp.me/), the ordering of some tags impacts how they are interpreted by crawlers and social media sites, and it's less predictable for Remix to assume how complex metadata should be merged
- Some tags allow for multiple values while others do not, and Remix shouldn't assume how you want to handle all of those cases

### Updating imports

Expand Down
13 changes: 6 additions & 7 deletions docs/guides/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,8 +580,7 @@ Here's some sample code to show how you might use Styled Components with Remix (

1. First you'll need to put a placeholder in your root component to control where the styles are inserted.

```tsx filename=app/root.tsx lines=[22-24]
import type { MetaFunction } from "@remix-run/node"; // or cloudflare/deno
```tsx filename=app/root.tsx lines=[21-23]
import {
Links,
LiveReload,
Expand All @@ -591,15 +590,15 @@ Here's some sample code to show how you might use Styled Components with Remix (
ScrollRestoration,
} from "@remix-run/react";

export const meta: MetaFunction = () => ({
charset: "utf-8",
viewport: "width=device-width, initial-scale=1",
});

export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<Meta />
<Links />
{typeof document === "undefined"
Expand Down
Loading