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();
});
},
};