Skip to content

Commit e890906

Browse files
authored
enhance(seo): use meta description templates for web-api-* pages (#11635)
* enhance(build): use meta description templates for web-api-* pages * chore(seo): revise meta description templates * chore(seo): further simplify templates * refactor(build): move meta description template to ssr * refactor(ssr): use Intl.ListFormat
1 parent 68ba985 commit e890906

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

Diff for: ssr/meta-description.ts

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { DEFAULT_LOCALE } from "../libs/constants/index.js";
2+
import { Doc } from "../libs/types/document.js";
3+
4+
export function getMetaDescription(doc: Doc): string {
5+
const { pageType } = doc;
6+
if (doc.locale === DEFAULT_LOCALE) {
7+
const sections = doc.toc?.map(({ text }) => text) ?? [];
8+
9+
const syntaxItems = Object.entries({
10+
Value: "type",
11+
"Event type": "type",
12+
Syntax: "syntax",
13+
Parameters: "parameters",
14+
Constructor: "constructor",
15+
"Instance properties": "properties",
16+
"Event properties": "properties",
17+
"Instance methods": "methods",
18+
"Return value": "return value",
19+
})
20+
.filter(([section]) => sections.includes(section))
21+
.map(([, text]) => text);
22+
23+
const otherItems = Object.entries({
24+
Exceptions: "exceptions",
25+
Examples: "code examples",
26+
Specifications: "specifications",
27+
"Browser compatibility": "browser compatibility",
28+
})
29+
.filter(([section]) => sections.includes(section))
30+
.map(([, text]) => text);
31+
32+
const listFormatter = new Intl.ListFormat("en", {
33+
style: "long",
34+
type: "conjunction",
35+
});
36+
const syntaxContents = listFormatter.format(syntaxItems);
37+
const otherContents = listFormatter.format(otherItems);
38+
const contents = [
39+
syntaxContents ? `its ${syntaxContents}` : "",
40+
otherContents,
41+
]
42+
.filter(Boolean)
43+
.join(", ");
44+
45+
switch (pageType) {
46+
case "web-api-instance-property":
47+
case "web-api-static-property":
48+
// "Learn about the Window.localStorage property, ..."
49+
// "Learn about the static Notification.permission property, ..."
50+
return `Learn about the ${doc.title.replace(/^(.*?): (.*?) (static )?property$/, "$3$1.$2 property")}, including ${contents}.`;
51+
52+
case "web-api-instance-method":
53+
case "web-api-static-method":
54+
// "Learn about the EventTarget.addEventListener() method, ..."
55+
// "Learn about the static URL.createObjectURL() method, ..."
56+
return `Learn about the ${doc.title.replace(/^(.*?): (.*?) (static )?method$/, "$3$1.$2 method")}, including ${contents}.`;
57+
58+
case "web-api-interface":
59+
// "Learn about the URLSearchParams interface, ..."
60+
return `Learn about the ${doc.title} interface, including ${contents}.`;
61+
62+
case "web-api-event":
63+
// "Learn about the DOMContentLoaded event, ..."
64+
return `Learn about the ${doc.title.replace(/^.*?: /, "")}, including ${contents}.`;
65+
66+
case "web-api-constructor":
67+
// "Learn about the URL() constructor, ..."
68+
return `Learn about the ${doc.title.replace(/^.*?: /, "")}, including ${contents}.`;
69+
70+
case "web-api-global-function":
71+
// "Learn about the global setTimeout() function, ..."
72+
return `Learn about the ${doc.title.replace(/^(.*) global function$/, "global $1 function")}, including ${contents}.`;
73+
}
74+
}
75+
76+
return doc.summary;
77+
}

Diff for: ssr/render.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1313
// @ts-ignore
1414
import HTML from "../client/build/index.html?raw";
15+
import { getMetaDescription } from "./meta-description";
1516

1617
// When there are multiple options for a given language, this gives the
1718
// preferred locale for that language (language => preferred locale).
@@ -120,6 +121,7 @@ export default function render(
120121
const canonicalURL = `${BASE_URL}${url}`;
121122

122123
let escapedPageTitle = htmlEscape(pageTitle);
124+
let metaDescription = pageDescription;
123125

124126
const hydrationData: HydrationData = { url };
125127
const translations: string[] = [];
@@ -137,6 +139,7 @@ export default function render(
137139
// Use the doc's title instead
138140
escapedPageTitle = htmlEscape(doc.pageTitle);
139141

142+
metaDescription = htmlEscape(getMetaDescription(doc));
140143
if (doc.summary) {
141144
pageDescription = htmlEscape(doc.summary);
142145
}
@@ -231,9 +234,9 @@ export default function render(
231234
return `<meta property="og:${typ}" content="${og.get(typ) || content}"/>`;
232235
}
233236
);
234-
if (pageDescription) {
237+
if (metaDescription) {
235238
html = html.replace(/<meta name="description" content="[^"]*"\/>/g, () => {
236-
return `<meta name="description" content="${pageDescription}"/>`;
239+
return `<meta name="description" content="${metaDescription}"/>`;
237240
});
238241
}
239242
html = html.replace("<title>MDN Web Docs</title>", () => `${titleTag}`);

0 commit comments

Comments
 (0)