Skip to content

Commit

Permalink
feat: add support for multiple entries with same property name
Browse files Browse the repository at this point in the history
  • Loading branch information
kiliman committed Sep 22, 2022
1 parent dfc3bca commit 6d5eb0d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 48 deletions.
6 changes: 6 additions & 0 deletions integration/meta-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,18 @@ test.describe("meta array syntax", () => {
json({
description: "This is a meta page",
title: "Meta Page",
contentType: undefined,
});
export const meta = ({ data }) => [
{ key: "charset", content: "utf-8" },
{ name: "description", content: data.description },
{ property: "og:image", content: "https://picsum.photos/300/300" },
{ property: "og:image:width", content: "300" },
{ property: "og:image:height", content: "300" },
{ property: "og:image", content: "https://picsum.photos/200/200" },
{ property: "og:image", content: "https://picsum.photos/500/1000" },
{ property: "og:image:height", content: "1000" },
{ property: "og:type", content: data.contentType }, // undefined
{ key: "httpEquiv:refresh", httpEquiv: "refresh", content: "3;url=https://www.mozilla.org" },
{ title: data.title },
Expand Down
84 changes: 36 additions & 48 deletions packages/remix-react/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -725,38 +725,21 @@ export function Meta() {

return (
<>
{[...meta.entries()].map(([key, value]) => {
if (key === "title" && typeof value.content === "string") {
return <title key={key}>{value.content}</title>;
{Array.from(meta.entries()).map(([key, descriptor]) => {
let { name, property, content } = descriptor;
if (key === "title" && typeof content === "string") {
return <title key={key}>{content}</title>;
}
if (key === "charset" && typeof value.content === "string") {
return <meta key={key} charSet={value.content} />;
if (key === "charset" && typeof content === "string") {
return <meta key={key} charSet={content} />;
}

if (name === "title") {
return <title key="title">{String(value)}</title>;
if (property !== undefined) {
return <meta key={key} property={property} content={content} />;
}

// Open Graph tags use the `property` attribute, while other meta tags
// use `name`. See https://ogp.me/
let isOpenGraphTag = name.startsWith("og:");
return [value].flat().map((content) => {
if (isOpenGraphTag) {
return (
<meta
property={name}
content={content as string}
key={name + content}
/>
);
}

if (typeof content === "string") {
return <meta name={name} content={content} key={name + content} />;
}

return <meta key={name + JSON.stringify(content)} {...content} />;
});
if (name !== undefined) {
return <meta key={key} name={name} content={content} />;
}
return <meta key={key} {...descriptor} />;
})}
</>
);
Expand All @@ -770,9 +753,12 @@ export function processMeta(
meta: MetaMap,
routeMeta: HtmlMetaDescriptor | HtmlMetaDescriptor[]
) {
// normalize routeMeta to array format
let items: HtmlMetaDescriptor[] = Array.isArray(routeMeta)
? routeMeta.map((item) =>
item.title ? { key: "title", content: item.title } : item
item.title
? { key: "title", content: item.title }
: { key: generateKey(item), ...item }
)
: Object.entries(routeMeta)
.map(([key, value]) => {
Expand All @@ -789,14 +775,24 @@ export function processMeta(
[propertyName]: key,
content,
}))
: { key, [propertyName]: key, content: value };
: typeof value === "object"
? {
key: `${key}.${(value as Record<string, string>)?.content}`,
...(value as Record<string, string>),
}
: {
key: propertyName === "name" ? key : `${key}.${value}`,
[propertyName]: key,
content: assertString(value),
};
})
.flat();

items.forEach((item) => {
let [key, value] = computeKey(item);
// child routes always override parent routes
meta.set(key, value);
// add items to the meta map by key (only add if content is defined)
items.forEach(({ key, ...rest }) => {
if (key && rest && rest.content) {
meta.set(key, rest);
}
});
}

Expand All @@ -808,22 +804,14 @@ function assertString(value: string | string[]): string {
}

function generateKey(item: HtmlMetaDescriptor) {
console.warn("No key provided to meta", item);
if (item.key) return item.key;
if (item.title) return "title";
if (item.charset || item.charSet) return "charset";
if (item.name) return item.name;
if (item.property) return `${item.property}.${item.content}`;
return JSON.stringify(item); // generate a reasonable key
}

function computeKey(item: HtmlMetaDescriptor): [string, HtmlMetaDescriptor] {
let {
name,
property,
title,
key = name ?? property ?? title ?? generateKey(item),
...rest
} = item;

return [key, { name, property, title, ...rest }];
}

/**
* Tracks whether Remix has finished hydrating or not, so scripts can be skipped
* during client-side updates.
Expand Down

0 comments on commit 6d5eb0d

Please sign in to comment.