Add json-ld schema to frontend/backend roadmaps

faqs/frontend
Kamran Ahmed 2 years ago
parent 9c24ff23e3
commit 4b681c6317
  1. 38
      src/layouts/BaseLayout.astro
  2. 40
      src/lib/jsonld-schema.ts
  3. 29
      src/lib/roadmap.ts
  4. 23
      src/pages/[roadmapId]/index.astro
  5. 6
      src/roadmaps/backend/backend.md
  6. 6
      src/roadmaps/frontend/frontend.md

@ -16,6 +16,7 @@ export interface Props {
noIndex?: boolean; noIndex?: boolean;
permalink?: string; permalink?: string;
sponsor?: SponsorType; sponsor?: SponsorType;
jsonLd?: Record<string, unknown>;
} }
const { const {
@ -25,14 +26,13 @@ const {
noIndex = false, noIndex = false,
permalink = '', permalink = '',
sponsor, sponsor,
jsonLd,
} = Astro.props; } = Astro.props;
// Remove trailing slashes to consider the page as canonical // Remove trailing slashes to consider the page as canonical
const currentPageAbsoluteUrl = `https://roadmap.sh${permalink}`; const currentPageAbsoluteUrl = `https://roadmap.sh${permalink}`;
const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${ const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${import.meta.env.GITHUB_SHA}`;
import.meta.env.GITHUB_SHA
}`;
--- ---
<!DOCTYPE html> <!DOCTYPE html>
@ -69,43 +69,23 @@ const commitUrl = `https://github.com/kamranahmedse/developer-roadmap/commit/${
<meta name='mobile-web-app-capable' content='yes' /> <meta name='mobile-web-app-capable' content='yes' />
<meta name='apple-mobile-web-app-capable' content='yes' /> <meta name='apple-mobile-web-app-capable' content='yes' />
<meta <meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />
name='apple-mobile-web-app-status-bar-style'
content='black-translucent'
/>
<meta name='apple-mobile-web-app-title' content='roadmap.sh' /> <meta name='apple-mobile-web-app-title' content='roadmap.sh' />
<meta name='application-name' content='roadmap.sh' /> <meta name='application-name' content='roadmap.sh' />
<link <link rel='apple-touch-icon' sizes='180x180' href='/manifest/apple-touch-icon.png' />
rel='apple-touch-icon'
sizes='180x180'
href='/manifest/apple-touch-icon.png'
/>
<meta name='msapplication-TileColor' content='#101010' /> <meta name='msapplication-TileColor' content='#101010' />
<meta name='theme-color' content='#848a9a' /> <meta name='theme-color' content='#848a9a' />
<link rel='manifest' href='/manifest/manifest.json' /> <link rel='manifest' href='/manifest/manifest.json' />
<link <link rel='icon' type='image/png' sizes='32x32' href='/manifest/icon32.png' />
rel='icon' <link rel='icon' type='image/png' sizes='16x16' href='/manifest/icon16.png' />
type='image/png' <link rel='shortcut icon' href='/manifest/favicon.ico' type='image/x-icon' />
sizes='32x32'
href='/manifest/icon32.png'
/>
<link
rel='icon'
type='image/png'
sizes='16x16'
href='/manifest/icon16.png'
/>
<link
rel='shortcut icon'
href='/manifest/favicon.ico'
type='image/x-icon'
/>
<link rel='icon' href='/manifest/favicon.ico' type='image/x-icon' /> <link rel='icon' href='/manifest/favicon.ico' type='image/x-icon' />
<slot name='after-header' /> <slot name='after-header' />
{jsonLd && <script type='application/ld+json' set:html={JSON.stringify(jsonLd)} />}
</head> </head>
<body> <body>
<YouTubeBanner /> <YouTubeBanner />

@ -0,0 +1,40 @@
type ArticleSchemaProps = {
url: string;
headline: string;
description: string;
imageUrl: string;
datePublished: string;
dateModified: string;
};
export function generateArticleSchema(article: ArticleSchemaProps) {
const { url, headline, description, imageUrl, datePublished, dateModified } =
article;
return {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
mainEntityOfPage: {
'@type': 'WebPage',
'@id': url,
},
headline: headline,
description: description,
image: imageUrl,
author: {
'@type': 'Person',
name: 'Kamran Ahmed',
url: 'https://twitter.com/kamranahmedse',
},
publisher: {
'@type': 'Organization',
name: 'roadmap.sh',
logo: {
'@type': 'ImageObject',
url: 'https://roadmap.sh/images/brand-square.png',
},
},
datePublished: datePublished,
dateModified: dateModified,
};
}

@ -22,6 +22,13 @@ export interface RoadmapFrontmatter {
description: string; description: string;
keywords: string[]; keywords: string[];
}; };
schema?: {
headline: string;
description: string;
datePublished: string;
dateModified: string;
imageUrl: string;
};
relatedRoadmaps: string[]; relatedRoadmaps: string[];
sitemap: { sitemap: {
priority: number; priority: number;
@ -46,12 +53,9 @@ function roadmapPathToId(filePath: string): string {
* @returns string[] Array of roadmap IDs * @returns string[] Array of roadmap IDs
*/ */
export async function getRoadmapIds() { export async function getRoadmapIds() {
const roadmapFiles = await import.meta.glob<RoadmapFileType>( const roadmapFiles = await import.meta.glob<RoadmapFileType>('/src/roadmaps/*/*.md', {
'/src/roadmaps/*/*.md',
{
eager: true, eager: true,
} });
);
return Object.keys(roadmapFiles).map(roadmapPathToId); return Object.keys(roadmapFiles).map(roadmapPathToId);
} }
@ -62,15 +66,10 @@ export async function getRoadmapIds() {
* @param tag Tag assigned to roadmap * @param tag Tag assigned to roadmap
* @returns Promisified RoadmapFileType[] * @returns Promisified RoadmapFileType[]
*/ */
export async function getRoadmapsByTag( export async function getRoadmapsByTag(tag: string): Promise<RoadmapFileType[]> {
tag: string const roadmapFilesMap = await import.meta.glob<RoadmapFileType>('/src/roadmaps/*/*.md', {
): Promise<RoadmapFileType[]> {
const roadmapFilesMap = await import.meta.glob<RoadmapFileType>(
'/src/roadmaps/*/*.md',
{
eager: true, eager: true,
} });
);
const roadmapFiles = Object.values(roadmapFilesMap); const roadmapFiles = Object.values(roadmapFilesMap);
const filteredRoadmaps = roadmapFiles const filteredRoadmaps = roadmapFiles
@ -80,7 +79,5 @@ export async function getRoadmapsByTag(
id: roadmapPathToId(roadmapFile.file), id: roadmapPathToId(roadmapFile.file),
})); }));
return filteredRoadmaps.sort( return filteredRoadmaps.sort((a, b) => a.frontmatter.order - b.frontmatter.order);
(a, b) => a.frontmatter.order - b.frontmatter.order
);
} }

@ -1,11 +1,11 @@
--- ---
import CaptchaScripts from '../../components/Captcha/CaptchaScripts.astro'; import CaptchaScripts from '../../components/Captcha/CaptchaScripts.astro';
import FAQs from '../../components/FAQs.astro';
import InteractiveRoadmap from '../../components/InteractiveRoadmap/InteractiveRoadmap.astro'; import InteractiveRoadmap from '../../components/InteractiveRoadmap/InteractiveRoadmap.astro';
import MarkdownRoadmap from '../../components/MarkdownRoadmap.astro'; import MarkdownRoadmap from '../../components/MarkdownRoadmap.astro';
import RoadmapHeader from '../../components/RoadmapHeader.astro'; import RoadmapHeader from '../../components/RoadmapHeader.astro';
import UpcomingRoadmap from '../../components/UpcomingRoadmap.astro'; import UpcomingRoadmap from '../../components/UpcomingRoadmap.astro';
import BaseLayout from '../../layouts/BaseLayout.astro'; import BaseLayout from '../../layouts/BaseLayout.astro';
import { generateArticleSchema } from '../../lib/jsonld-schema';
import { getRoadmapIds, RoadmapFrontmatter } from '../../lib/roadmap'; import { getRoadmapIds, RoadmapFrontmatter } from '../../lib/roadmap';
export async function getStaticPaths() { export async function getStaticPaths() {
@ -22,8 +22,21 @@ interface Params extends Record<string, string | undefined> {
const { roadmapId } = Astro.params as Params; const { roadmapId } = Astro.params as Params;
const roadmapFile = await import(`../../roadmaps/${roadmapId}/${roadmapId}.md`); const roadmapFile = await import(`../../roadmaps/${roadmapId}/${roadmapId}.md`);
const questions = await import (`../../roadmaps/${roadmapId}/faqs.astro`); const questions = await import(`../../roadmaps/${roadmapId}/faqs.astro`);
const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter; const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
let articleSchema;
if (roadmapData.schema) {
const roadmapSchema = roadmapData.schema;
articleSchema = generateArticleSchema({
url: `https://roadmap.sh/${roadmapId}`,
headline: roadmapSchema.headline,
description: roadmapSchema.description,
datePublished: roadmapSchema.datePublished,
dateModified: roadmapSchema.dateModified,
imageUrl: roadmapSchema.imageUrl,
});
}
--- ---
<BaseLayout <BaseLayout
@ -33,6 +46,7 @@ const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
keywords={roadmapData.seo.keywords} keywords={roadmapData.seo.keywords}
sponsor={roadmapData.sponsor} sponsor={roadmapData.sponsor}
noIndex={roadmapData.isUpcoming} noIndex={roadmapData.isUpcoming}
jsonLd={articleSchema}
> >
<RoadmapHeader <RoadmapHeader
description={roadmapData.description} description={roadmapData.description}
@ -55,10 +69,7 @@ const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter;
{ {
!roadmapData.isUpcoming && !roadmapData.jsonUrl && ( !roadmapData.isUpcoming && !roadmapData.jsonUrl && (
<MarkdownRoadmap <MarkdownRoadmap roadmapId={roadmapId} description={roadmapData.description}>
roadmapId={roadmapId}
description={roadmapData.description}
>
<roadmapFile.Content /> <roadmapFile.Content />
</MarkdownRoadmap> </MarkdownRoadmap>
) )

@ -20,6 +20,12 @@ sponsor:
category: "SponsorClick" category: "SponsorClick"
action: "Ambassador Redirect" action: "Ambassador Redirect"
label: "Clicked Ambassador Link" label: "Clicked Ambassador Link"
schema:
headline: "Backend Developer Roadmap"
description: "Learn how to become a Backend Developer with this interactive step by step guide in 2023. We also have resources and short descriptions attached to the roadmap items so you can get everything you want to learn in one place."
imageUrl: "https://roadmap.sh/roadmaps/backend.png"
datePublished: "2023-01-05"
dateModified: "2023-01-20"
seo: seo:
title: "Backend Developer Roadmap" title: "Backend Developer Roadmap"
description: "Learn to become a modern backend developer using this roadmap. Community driven, articles, resources, guides, interview questions, quizzes for modern backend development." description: "Learn to become a modern backend developer using this roadmap. Community driven, articles, resources, guides, interview questions, quizzes for modern backend development."

@ -10,6 +10,12 @@ hasTopics: true
dimensions: dimensions:
width: 968 width: 968
height: 2734.48 height: 2734.48
schema:
headline: "Frontend Developer Roadmap"
description: "Learn how to become a Frontend Developer with this interactive step by step guide in 2023. We also have resources and short descriptions attached to the roadmap items so you can get everything you want to learn in one place."
imageUrl: "https://roadmap.sh/roadmaps/frontend.png"
datePublished: "2023-01-05"
dateModified: "2023-01-20"
seo: seo:
title: "Frontend Developer Roadmap" title: "Frontend Developer Roadmap"
description: "Learn to become a modern frontend developer using this roadmap. Community driven, articles, resources, guides, interview questions, quizzes for modern frontend development." description: "Learn to become a modern frontend developer using this roadmap. Community driven, articles, resources, guides, interview questions, quizzes for modern frontend development."

Loading…
Cancel
Save