Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: sitemap issues #22

Merged
merged 5 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/breezy-games-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrolicious/i18n": patch
---

Fixes a case where non pages were included in the sitemap
5 changes: 5 additions & 0 deletions .changeset/cyan-ghosts-decide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrolicious/i18n": patch
---

Fixes trailing slash handling in sitemap
5 changes: 5 additions & 0 deletions .changeset/fast-dolphins-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrolicious/i18n": patch
---

Fixes duplicated urls with complex routes
5 changes: 5 additions & 0 deletions .changeset/nice-eyes-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrolicious/i18n": patch
---

Fixes a case where invalid dynamic params would cause wrong alternates to be generated
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
"editor.defaultFormatter": "biomejs.biome",
"[mdx]": {
"editor.defaultFormatter": "unifiedjs.vscode-mdx"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
5 changes: 1 addition & 4 deletions package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@
"./components/I18nClient.astro": "./assets/components/I18nClient.astro",
"./components/I18nHead.astro": "./assets/components/I18nHead.astro"
},
"files": [
"dist",
"assets"
],
"files": ["dist", "assets"],
"scripts": {
"dev": "tsup --watch",
"build": "tsup"
Expand Down
60 changes: 31 additions & 29 deletions package/src/sitemap/generate-sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
import type { AstroConfig } from "astro";
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";

type NoUndefinedField<T> = {
[P in keyof T]-?: NonNullable<T[P]>;
Expand All @@ -29,6 +17,7 @@ export function generateSitemap(
routes: Array<Route>,
_finalSiteUrl: string,
opts: SitemapOptions,
config: AstroConfig,
) {
const { changefreq, priority, lastmod: lastmodSrc } = opts;
const lastmod = lastmodSrc?.toISOString();
Expand Down Expand Up @@ -57,27 +46,37 @@ 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 }),
);
}

const index = route.pages.indexOf(page);
const sitemapOptions = route.sitemapOptions[index];
if (!sitemapOptions) {
const sitemapOptions = route.sitemapOptions.filter(
(e) =>
e.dynamicParams &&
(Array.isArray(e.dynamicParams)
? e.dynamicParams
: Object.entries(e.dynamicParams)
).length > 0,
)[index];
if (!sitemapOptions || !sitemapOptions.dynamicParams) {
return [];
}

for (const equivalentRoute of equivalentRoutes) {
const options = normalizeDynamicParams(
sitemapOptions?.dynamicParams,
).find((e) => e.locale === equivalentRoute.route.locale);
const options = normalizeDynamicParams(sitemapOptions.dynamicParams).find(
(e) => e.locale === equivalentRoute.route.locale,
);

if (!options) {
// A dynamic route is not required to always have an equivalent in another language eg.
Expand All @@ -97,14 +96,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 }),
);
};

Expand Down
58 changes: 37 additions & 21 deletions package/src/sitemap/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -20,7 +20,9 @@ import {
createImpossibleError,
formatConfigErrorMessage,
getPathnameFromRouteData,
handleTrailingSlash,
isStatusCodePage,
normalizeDynamicParams,
} from "./utils.js";

const OUTFILE = "sitemap-index.xml";
Expand Down Expand Up @@ -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);
}
}
}
}
},
Expand All @@ -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) =>
Expand All @@ -125,7 +150,7 @@ export const integration = defineIntegration({
);
}
r.routeData = routeData;
r.include = true;
r.include = routeData.type === "page";
}

const _routes = [
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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: <explanation>
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);
Expand Down
30 changes: 29 additions & 1 deletion package/src/sitemap/utils.ts
Original file line number Diff line number Diff line change
@@ -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"]);

Expand Down Expand Up @@ -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;
};
Loading