From a23b965927ecda967dcbede307e1beedc9ac2ddc Mon Sep 17 00:00:00 2001 From: Florian Lefebvre Date: Tue, 30 Apr 2024 12:14:42 +0200 Subject: [PATCH] fix: sitemap --- .changeset/cyan-ghosts-decide.md | 5 +++ .changeset/fast-dolphins-fry.md | 5 +++ package/src/sitemap/generate-sitemap.ts | 43 +++++++++---------- package/src/sitemap/integration.ts | 56 ++++++++++++++++--------- package/src/sitemap/utils.ts | 30 ++++++++++++- 5 files changed, 94 insertions(+), 45 deletions(-) create mode 100644 .changeset/cyan-ghosts-decide.md create mode 100644 .changeset/fast-dolphins-fry.md diff --git a/.changeset/cyan-ghosts-decide.md b/.changeset/cyan-ghosts-decide.md new file mode 100644 index 0000000..4ffe7ae --- /dev/null +++ b/.changeset/cyan-ghosts-decide.md @@ -0,0 +1,5 @@ +--- +"@astrolicious/i18n": patch +--- + +Fixes trailing slash handling in sitemap diff --git a/.changeset/fast-dolphins-fry.md b/.changeset/fast-dolphins-fry.md new file mode 100644 index 0000000..17e39cc --- /dev/null +++ b/.changeset/fast-dolphins-fry.md @@ -0,0 +1,5 @@ +--- +"@astrolicious/i18n": patch +--- + +Fixes duplicated urls with complex routes diff --git a/package/src/sitemap/generate-sitemap.ts b/package/src/sitemap/generate-sitemap.ts index 0097507..f4b41a6 100644 --- a/package/src/sitemap/generate-sitemap.ts +++ b/package/src/sitemap/generate-sitemap.ts @@ -1,24 +1,12 @@ import type { LinkItem, SitemapItemLoose } from "sitemap"; import type { Route } from "./integration.js"; import type { SitemapOptions } from "./options.js"; -import { createImpossibleError } from "./utils.js"; - -const normalizeDynamicParams = ( - _params: Route["sitemapOptions"][number]["dynamicParams"], -) => { - if (!_params) { - return []; - } - - if (Array.isArray(_params)) { - return _params; - } - - return Object.entries(_params).map(([locale, params]) => ({ - locale, - params, - })); -}; +import { + createImpossibleError, + handleTrailingSlash, + normalizeDynamicParams, +} from "./utils.js"; +import type { AstroConfig } from "astro"; type NoUndefinedField = { [P in keyof T]-?: NonNullable; @@ -29,6 +17,7 @@ export function generateSitemap( routes: Array, _finalSiteUrl: string, opts: SitemapOptions, + config: AstroConfig, ) { const { changefreq, priority, lastmod: lastmodSrc } = opts; const lastmod = lastmodSrc?.toISOString(); @@ -57,14 +46,17 @@ export function generateSitemap( for (const equivalentRoute of equivalentRoutes) { links.push({ lang: equivalentRoute.route.locale, - url: `${new URL(page).origin}${ - equivalentRoute.route.injectedRoute.pattern - }`, + url: handleTrailingSlash( + `${new URL(page).origin}${ + equivalentRoute.route.injectedRoute.pattern + }`, + config, + ), }); } return [...links].sort((a, b) => - a.url.localeCompare(b.url, "en", { numeric: true }), + a.lang.localeCompare(b.lang, "en", { numeric: true }), ); } @@ -97,14 +89,17 @@ export function generateSitemap( newPage = newPage.replace(`[${key}]`, value); } - newPage = `${new URL(page).origin}${newPage}`; + newPage = handleTrailingSlash( + `${new URL(page).origin}${newPage}`, + config, + ); links.push({ lang: equivalentRoute.route.locale, url: newPage, }); } return [...links].sort((a, b) => - a.url.localeCompare(b.url, "en", { numeric: true }), + a.lang.localeCompare(b.lang, "en", { numeric: true }), ); }; diff --git a/package/src/sitemap/integration.ts b/package/src/sitemap/integration.ts index 635eeb8..23419e6 100644 --- a/package/src/sitemap/integration.ts +++ b/package/src/sitemap/integration.ts @@ -10,7 +10,7 @@ import { import { AstroError } from "astro/errors"; import { z } from "astro/zod"; import { simpleSitemapAndIndex } from "sitemap"; -import { withTrailingSlash, withoutTrailingSlash } from "ufo"; +import { withoutTrailingSlash } from "ufo"; import { normalizePath } from "vite"; import type { Route as InternalRoute } from "../types.js"; import { generateSitemap } from "./generate-sitemap.js"; @@ -20,7 +20,9 @@ import { createImpossibleError, formatConfigErrorMessage, getPathnameFromRouteData, + handleTrailingSlash, isStatusCodePage, + normalizeDynamicParams, } from "./utils.js"; const OUTFILE = "sitemap-index.xml"; @@ -105,6 +107,23 @@ export const integration = defineIntegration({ ); } route.sitemapOptions.push(response.data); + if (route.route) { + const { locale, injectedRoute } = route.route; + const params = normalizeDynamicParams( + response.data.dynamicParams, + )?.find((e) => e.locale === locale); + if (params) { + let page = injectedRoute.pattern; + for (const [key, value] of Object.entries( + params.params, + )) { + if (value) { + page = page.replace(`[${key}]`, value); + } + } + route.pages.push(page); + } + } } } }, @@ -113,6 +132,12 @@ export const integration = defineIntegration({ "astro:build:done": async (params) => { const { logger } = params; + for (const route of initialRoutes) { + if (route.pages.length === 0 && route.route) { + route.pages.push(route.route.injectedRoute.pattern); + } + } + for (const r of initialRoutes.filter((e) => !e.routeData)) { const routeData = params.routes.find( (e) => @@ -202,16 +227,7 @@ export const integration = defineIntegration({ const newUrl = new URL(fullPath, finalSiteUrl).href; - if (config.trailingSlash === "never") { - urls.push(newUrl); - } else if ( - config.build.format === "directory" && - !newUrl.endsWith("/") - ) { - urls.push(`${newUrl}/`); - } else { - urls.push(newUrl); - } + urls.push(handleTrailingSlash(newUrl, config)); } return urls; @@ -242,21 +258,21 @@ export const integration = defineIntegration({ } for (const route of _routes.filter((e) => e.include)) { - for (const rawPage of pageUrls) { - const page = normalizePath( - `/${relative(config.base, new URL(rawPage).pathname)}`, - ); - // biome-ignore lint/style/noNonNullAssertion: - if (route.routeData!.pattern.test(withTrailingSlash(page))) { - route.pages.push(rawPage); - } - } + route.pages = route.pages.map((page) => + page.startsWith("/") + ? handleTrailingSlash( + new URL(page, finalSiteUrl).href, + config, + ) + : page, + ); } const urlData = generateSitemap( _routes.filter((e) => e.include), finalSiteUrl.href, options, + config, ); const destDir = fileURLToPath(params.dir); diff --git a/package/src/sitemap/utils.ts b/package/src/sitemap/utils.ts index 8299bb9..2baacc2 100644 --- a/package/src/sitemap/utils.ts +++ b/package/src/sitemap/utils.ts @@ -1,6 +1,7 @@ -import type { RouteData } from "astro"; +import type { AstroConfig, RouteData } from "astro"; import { AstroError } from "astro/errors"; import type { ZodError } from "astro/zod"; +import type { Route } from "./integration.js"; const STATUS_CODE_PAGES = new Set(["404", "500"]); @@ -37,3 +38,30 @@ export const getPathnameFromRouteData = ({ segments }: RouteData) => { return `/${pathname}`; }; + +export const normalizeDynamicParams = ( + _params: Route["sitemapOptions"][number]["dynamicParams"], +) => { + if (!_params) { + return []; + } + + if (Array.isArray(_params)) { + return _params; + } + + return Object.entries(_params).map(([locale, params]) => ({ + locale, + params, + })); +}; + +export const handleTrailingSlash = (url: string, config: AstroConfig) => { + if (config.trailingSlash === "never") { + return url; + } + if (config.build.format === "directory" && !url.endsWith("/")) { + return `${url}/`; + } + return url; +};