From 5311f83b0d7b804a679d98862ad765e724d40c13 Mon Sep 17 00:00:00 2001 From: istarkov Date: Wed, 22 Jan 2025 18:08:15 +0000 Subject: [PATCH] canonical link --- .../app/routes/[another-page]._index.tsx | 2 + .../app/routes/_index.tsx | 2 + .../app/routes/[script-test]._index.tsx | 2 + .../app/routes/[world]._index.tsx | 2 + .../app/routes/_index.tsx | 2 + .../app/routes/[another-page]._index.tsx | 2 + .../app/routes/_index.tsx | 2 + .../app/routes/[another-page]._index.tsx | 2 + .../app/routes/_index.tsx | 2 + .../.webstudio/data.json | 42 ++++- .../__generated__/$resources.sitemap.xml.ts | 12 +- .../app/__generated__/[head-tag]._index.tsx | 4 + .../routes/[_route_with_symbols_]._index.tsx | 2 + .../app/routes/[class-names]._index.tsx | 2 + .../app/routes/[content-block]._index.tsx | 2 + .../app/routes/[expressions]._index.tsx | 2 + .../app/routes/[form]._index.tsx | 2 + .../app/routes/[head-tag]._index.tsx | 2 + .../app/routes/[heading-with-id]._index.tsx | 2 + .../routes/[nested].[nested-page]._index.tsx | 2 + .../app/routes/[radix]._index.tsx | 2 + .../app/routes/[resources]._index.tsx | 2 + .../app/routes/_index.tsx | 2 + fixtures/webstudio-remix-vercel/package.json | 2 +- .../proxy-emulator/dedupe-meta.ts | 168 +++++++++--------- 25 files changed, 171 insertions(+), 97 deletions(-) diff --git a/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx b/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx index 6e12e779ed63..63ab5675f96d 100644 --- a/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx +++ b/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx b/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx index 8c2322120c92..9bc280da9b7a 100644 --- a/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx +++ b/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx b/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx index ea6c11a80c03..e1ef0f53c661 100644 --- a/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx +++ b/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx b/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx index 6d2d7d8bc7dc..5e20e7ac2bb1 100644 --- a/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx +++ b/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-custom-template/app/routes/_index.tsx b/fixtures/webstudio-custom-template/app/routes/_index.tsx index 8c2322120c92..9bc280da9b7a 100644 --- a/fixtures/webstudio-custom-template/app/routes/_index.tsx +++ b/fixtures/webstudio-custom-template/app/routes/_index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx index 6e12e779ed63..63ab5675f96d 100644 --- a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx +++ b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx index 8c2322120c92..9bc280da9b7a 100644 --- a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx +++ b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx b/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx index 6e12e779ed63..63ab5675f96d 100644 --- a/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx +++ b/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx b/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx index 8c2322120c92..9bc280da9b7a 100644 --- a/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx +++ b/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/.webstudio/data.json b/fixtures/webstudio-remix-vercel/.webstudio/data.json index 695dc0471cfe..aaa100ed3307 100644 --- a/fixtures/webstudio-remix-vercel/.webstudio/data.json +++ b/fixtures/webstudio-remix-vercel/.webstudio/data.json @@ -1,10 +1,10 @@ { "build": { - "id": "1bd755a0-9c8a-416b-b373-2123f3568393", + "id": "3173a7d8-1af3-4e23-87fd-94c3b0cb1018", "projectId": "cddc1d44-af37-4cb6-a430-d300cf6f932d", - "version": 464, - "createdAt": "2025-01-19T14:02:13.405+00:00", - "updatedAt": "2025-01-19T14:02:13.405+00:00", + "version": 474, + "createdAt": "2025-01-22T17:59:53.714+00:00", + "updatedAt": "2025-01-22T17:59:53.714+00:00", "pages": { "meta": { "siteName": "KittyGuardedZone", @@ -2979,6 +2979,26 @@ "type": "boolean", "value": true } + ], + [ + "DohJcBH-kmzk2lvN_F2hS", + { + "id": "DohJcBH-kmzk2lvN_F2hS", + "instanceId": "56x98yMSVYpp7eVo8wuzK", + "name": "rel", + "type": "string", + "value": "canonical" + } + ], + [ + "_wNeTsN1d6jG8ZM5ud05d", + { + "id": "_wNeTsN1d6jG8ZM5ud05d", + "instanceId": "56x98yMSVYpp7eVo8wuzK", + "name": "href", + "type": "string", + "value": "https://overwritten.slot/head-slot-tag" + } ] ], "dataSources": [ @@ -5026,6 +5046,10 @@ { "type": "id", "value": "EveN4Skg9xb8Lj1QJcW52" + }, + { + "type": "id", + "value": "56x98yMSVYpp7eVo8wuzK" } ] } @@ -5102,6 +5126,16 @@ } ] } + ], + [ + "56x98yMSVYpp7eVo8wuzK", + { + "type": "instance", + "id": "56x98yMSVYpp7eVo8wuzK", + "component": "HeadLink", + "label": "Link", + "children": [] + } ] ], "deployment": { diff --git a/fixtures/webstudio-remix-vercel/app/__generated__/$resources.sitemap.xml.ts b/fixtures/webstudio-remix-vercel/app/__generated__/$resources.sitemap.xml.ts index e2c6e8c37fba..1bad56e430a3 100644 --- a/fixtures/webstudio-remix-vercel/app/__generated__/$resources.sitemap.xml.ts +++ b/fixtures/webstudio-remix-vercel/app/__generated__/$resources.sitemap.xml.ts @@ -1,26 +1,26 @@ export const sitemap = [ { path: "/", - lastModified: "2025-01-19", + lastModified: "2025-01-22", }, { path: "/_route_with_symbols_", - lastModified: "2025-01-19", + lastModified: "2025-01-22", }, { path: "/form", - lastModified: "2025-01-19", + lastModified: "2025-01-22", }, { path: "/heading-with-id", - lastModified: "2025-01-19", + lastModified: "2025-01-22", }, { path: "/resources", - lastModified: "2025-01-19", + lastModified: "2025-01-22", }, { path: "/nested/nested-page", - lastModified: "2025-01-19", + lastModified: "2025-01-22", }, ]; diff --git a/fixtures/webstudio-remix-vercel/app/__generated__/[head-tag]._index.tsx b/fixtures/webstudio-remix-vercel/app/__generated__/[head-tag]._index.tsx index 339e06410a7f..ccea8747cf94 100644 --- a/fixtures/webstudio-remix-vercel/app/__generated__/[head-tag]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/__generated__/[head-tag]._index.tsx @@ -43,6 +43,10 @@ const Page = ({}: { system: any }) => { + {"Test Head Slot"} diff --git a/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx index d7486e72681a..b20c8d220bac 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx index 42f6e9655b17..6b1827cdcf76 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[content-block]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[content-block]._index.tsx index b0767715c78c..58f75037e5ab 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[content-block]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[content-block]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx index 6badc800b29e..db508536023f 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx index 38a92c2b70f3..5b31450447e6 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[head-tag]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[head-tag]._index.tsx index b617f702d662..62036aa81d98 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[head-tag]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[head-tag]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx index 3411491cd6d2..cb7aa40b47d3 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx index f6c0d0796d48..da0ae1858512 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx index 48c413cc1979..46dcaf1bbe7e 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx index 2b874c673d27..2d6a14b080a4 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/app/routes/_index.tsx b/fixtures/webstudio-remix-vercel/app/routes/_index.tsx index 8c2322120c92..9bc280da9b7a 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/_index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/_index.tsx @@ -20,6 +20,7 @@ import { ReactSdkContext, PageSettingsMeta, PageSettingsTitle, + PageSettingsCanonicalLink, } from "@webstudio-is/react-sdk/runtime"; import { Page, @@ -288,6 +289,7 @@ const Outlet = () => { imageLoader={imageLoader} /> {pageMeta.title} + ); }; diff --git a/fixtures/webstudio-remix-vercel/package.json b/fixtures/webstudio-remix-vercel/package.json index c730f914987a..d2685be1fbbb 100644 --- a/fixtures/webstudio-remix-vercel/package.json +++ b/fixtures/webstudio-remix-vercel/package.json @@ -6,7 +6,7 @@ "typecheck": "tsc", "cli": "NODE_OPTIONS='--conditions=webstudio --import=tsx' webstudio", "fixtures:link": "pnpm cli link --link https://p-cddc1d44-af37-4cb6-a430-d300cf6f932d-dot-${BUILDER_HOST:-main.development.webstudio.is}'?authToken=1cdc6026-dd5b-4624-b89b-9bd45e9bcc3d'", - "fixtures:sync": "pnpm cli sync --buildId 1bd755a0-9c8a-416b-b373-2123f3568393 && pnpm prettier --write ./.webstudio/", + "fixtures:sync": "pnpm cli sync --buildId 3173a7d8-1af3-4e23-87fd-94c3b0cb1018 && pnpm prettier --write ./.webstudio/", "fixtures:build": "pnpm cli build --template vercel --template internal --template ./.template && pnpm prettier --write ./app/ ./package.json ./tsconfig.json" }, "private": true, diff --git a/fixtures/webstudio-remix-vercel/proxy-emulator/dedupe-meta.ts b/fixtures/webstudio-remix-vercel/proxy-emulator/dedupe-meta.ts index 8360cc40aa93..0b1a1c4b2e5f 100644 --- a/fixtures/webstudio-remix-vercel/proxy-emulator/dedupe-meta.ts +++ b/fixtures/webstudio-remix-vercel/proxy-emulator/dedupe-meta.ts @@ -13,96 +13,92 @@ export const dedupeMeta: Plugin = { return; } - console.log("req.url", req.url); + // Capture the original response + const originalWrite = res.write; + const originalEnd = res.end; - if (req.url?.endsWith("/head-tag")) { - // Capture the original response - const originalWrite = res.write; - const originalEnd = res.end; + let body = ""; - let body = ""; + res.write = (chunk) => { + body += chunk.toString(); + return true; + }; - res.write = (chunk) => { + res.end = (chunk) => { + if (chunk) { body += chunk.toString(); - return true; - }; - - res.end = (chunk) => { - if (chunk) { - body += chunk.toString(); - } - - const response = new Response(body); - - const metasSet = new Set(); - let hasTitle = false; - let hasCanonicalLink = false; - - const rewriter = new HTMLRewriter() - .on("meta", { - element(element) { - const propertyOrName = - element.getAttribute("property") || - element.getAttribute("name"); - - if (propertyOrName === null) { - return; - } - - if (propertyOrName === "viewport") { - // Allow "viewport" property deduplication - return; - } - - if (metasSet.has(propertyOrName)) { - console.info( - `Duplicate meta with name|property = ${propertyOrName} removed` - ); - element.remove(); - return; - } - - metasSet.add(propertyOrName); - }, - }) - .on("title", { - element(element) { - if (hasTitle) { - element.remove(); - return; - } - - hasTitle = true; - }, - }) - .on('link[rel="canonical"]', { - element(element) { - if (hasCanonicalLink) { - element.remove(); - return; - } - - hasCanonicalLink = true; - }, - }); - rewriter - // @ts-ignore - .transform(response) - .text() - .then((cleanedHtml) => { - // Send the modified response - res.setHeader("Content-Length", Buffer.byteLength(cleanedHtml)); - originalWrite.call(res, cleanedHtml, "utf-8"); - originalEnd.call(res, "", "utf-8"); - }); - - return res; - }; - - next(); - } else { - next(); - } + } + + const response = new Response(body); + + const metasSet = new Set(); + let hasTitle = false; + let hasCanonicalLink = false; + + const rewriter = new HTMLRewriter() + .on("meta", { + element(element) { + const propertyOrName = + element.getAttribute("property") || + element.getAttribute("name"); + + if (propertyOrName === null) { + return; + } + + if (propertyOrName === "viewport") { + // Allow "viewport" property deduplication + return; + } + + if (metasSet.has(propertyOrName)) { + console.info( + `Duplicate meta with name|property = ${propertyOrName} removed` + ); + element.remove(); + return; + } + + metasSet.add(propertyOrName); + }, + }) + .on("title", { + element(element) { + if (hasTitle) { + console.info(`Duplicate title removed`); + element.remove(); + return; + } + + hasTitle = true; + }, + }) + .on('link[rel="canonical"]', { + element(element) { + if (hasCanonicalLink) { + console.info(`Duplicate link rel canonical removed`); + element.remove(); + return; + } + + hasCanonicalLink = true; + }, + }); + rewriter + // @ts-ignore + .transform(response) + .text() + .then((cleanedHtml) => { + // Send the modified response + res.setHeader("Content-Length", Buffer.byteLength(cleanedHtml)); + originalWrite.call(res, cleanedHtml, "utf-8"); + originalEnd.call(res, "", "utf-8"); + }); + + return res; + }; + + next(); }); }, };