Import source: global/scripts/generate-article-pages.mjs
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env node
|
||||
// Generates static HTML for each article under dist/article/{slug}/index.html
|
||||
import { readFileSync, writeFileSync, mkdirSync } from 'fs';
|
||||
import { articles, authors, siteConfig } from '../global-data.js';
|
||||
|
||||
const SITE = siteConfig.url;
|
||||
const template = readFileSync('dist/index.html', 'utf8');
|
||||
|
||||
function capDate(d) {
|
||||
const now = new Date().toISOString().split('T')[0];
|
||||
return d > now ? now : d;
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
for (const article of articles) {
|
||||
const author = authors.find(a => a.id === article.author);
|
||||
const canonical = `${SITE}/article/${article.slug}`;
|
||||
const ogImage = `${SITE}${article.photo}`;
|
||||
const lastmod = capDate(article.dateEn);
|
||||
|
||||
const jsonLd = JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': ['NewsArticle', 'TechArticle'],
|
||||
headline: article.metaTitle || article.title,
|
||||
description: article.metaDescription || article.subtitle,
|
||||
image: ogImage,
|
||||
datePublished: article.dateEn,
|
||||
dateModified: lastmod,
|
||||
inLanguage: 'en',
|
||||
isAccessibleForFree: true,
|
||||
mainEntityOfPage: { '@type': 'WebPage', '@id': canonical },
|
||||
author: author ? {
|
||||
'@type': 'Person',
|
||||
name: author.name,
|
||||
url: `${SITE}/author/${author.slug}`,
|
||||
} : undefined,
|
||||
publisher: {
|
||||
'@type': ['Organization', 'NewsMediaOrganization'],
|
||||
name: 'Teknav',
|
||||
url: SITE,
|
||||
logo: { '@type': 'ImageObject', url: `${SITE}/images/og/default.jpg` },
|
||||
},
|
||||
});
|
||||
|
||||
const hreflang = article.persianUrl
|
||||
? `<link rel="alternate" hreflang="fa" href="${article.persianUrl}"/>
|
||||
<link rel="alternate" hreflang="en" href="${canonical}"/>
|
||||
<link rel="alternate" hreflang="x-default" href="${article.persianUrl}"/>`
|
||||
: '';
|
||||
|
||||
const head = `
|
||||
<title>${(article.metaTitle || article.title).replace(/"/g, '"')} | Teknav</title>
|
||||
<meta name="description" content="${(article.metaDescription || article.subtitle || '').replace(/"/g, '"')}"/>
|
||||
<link rel="canonical" href="${canonical}"/>
|
||||
${hreflang}
|
||||
<meta property="og:title" content="${(article.metaTitle || article.title).replace(/"/g, '"')}"/>
|
||||
<meta property="og:description" content="${(article.metaDescription || article.subtitle || '').replace(/"/g, '"')}"/>
|
||||
<meta property="og:image" content="${ogImage}"/>
|
||||
<meta property="og:url" content="${canonical}"/>
|
||||
<meta property="og:type" content="article"/>
|
||||
<meta property="og:locale" content="en_US"/>
|
||||
${article.persianUrl ? `<meta property="og:locale:alternate" content="fa_IR"/>` : ''}
|
||||
<meta name="twitter:card" content="summary_large_image"/>
|
||||
<meta name="twitter:title" content="${(article.metaTitle || article.title).replace(/"/g, '"')}"/>
|
||||
<meta name="twitter:image" content="${ogImage}"/>
|
||||
<script type="application/ld+json">${jsonLd}</script>`;
|
||||
|
||||
const html = template.replace('</head>', `${head}\n </head>`);
|
||||
|
||||
const dir = `dist/article/${article.slug}`;
|
||||
mkdirSync(dir, { recursive: true });
|
||||
writeFileSync(`${dir}/index.html`, html);
|
||||
count++;
|
||||
}
|
||||
|
||||
console.log(`[article-pages] generated ${count} static article HTML pages`);
|
||||
Reference in New Issue
Block a user