diff --git a/frontend/package.json b/frontend/package.json index ab30bee186d..cbb5e8960db 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,8 +5,9 @@ "license": "SEE LICENSE IN LICENSE.md", "scripts": { "build:csp": "node scripts/build.csp.mjs", + "build:seo": "node scripts/build.seo.mjs", "build:preload": "node scripts/build.preload.mjs", - "build:post-process": "npm run build:csp", + "build:post-process": "npm run build:seo && npm run build:csp", "i18n": "node scripts/i18n.types.js && prettier --write ./src/lib/types/i18n.d.ts", "dev": "npm run i18n && vite dev", "build": "npm run i18n && tsc --noEmit && vite build && npm run build:post-process", diff --git a/frontend/scripts/build.seo.mjs b/frontend/scripts/build.seo.mjs new file mode 100644 index 00000000000..657a17df747 --- /dev/null +++ b/frontend/scripts/build.seo.mjs @@ -0,0 +1,38 @@ +import { readFileSync, writeFileSync } from "node:fs"; +import { dirname, join, relative } from "node:path"; +import { findHtmlFiles } from "./build.utils.mjs"; + +const OUTPUT_DIR = join(process.cwd(), "public"); +const SITE_ROOT_CANONICAL = "https://nns.ic0.app/"; + +const updateCanonical = (htmlFilePath) => { + // 1. We determine the route based on the output + const routePath = dirname(relative(OUTPUT_DIR, htmlFilePath)); + + // 2. Build the effective canonical route + const canonicalPath = `${SITE_ROOT_CANONICAL}${routePath}/`; + + // 2. Read content + let html = readFileSync(htmlFilePath, "utf-8"); + + // 3. Update canonical + html = html.replace( + ``, + `` + ); + + // 4. Update og:url to reflect the canonical + html = html.replace( + ``, + `` + ); + + // 5. Save the content with the updated canonical URL + writeFileSync(htmlFilePath, html); +}; + +// Do not replace canonical for root and 404 pages +const filterSubPages = (htmlFile) => dirname(htmlFile) !== OUTPUT_DIR; + +const htmlFiles = findHtmlFiles().filter(filterSubPages); +htmlFiles.forEach(updateCanonical);