From ad907196cb42f21d9540ae0d77aa742bf7adf030 Mon Sep 17 00:00:00 2001 From: Atila Fassina Date: Wed, 3 May 2023 18:19:45 +0200 Subject: [PATCH] Sitemap: support SSR routes (#6534) * feat(sitemap): support SSR generated routes * feat(sitemap): add changeset for SSR support * refactor: move logic to `astro:build:done` * generate route to obey `trailingSlash` setting * add logic to respect "directory" build format * integration(sitemap): add unit test for ssr support --- .changeset/chatty-dolls-visit.md | 5 ++ packages/integrations/sitemap/package.json | 1 + packages/integrations/sitemap/src/index.ts | 54 ++++++++++++------- .../test/fixtures/ssr/astro.config.mjs | 12 +++++ .../sitemap/test/fixtures/ssr/package.json | 9 ++++ .../test/fixtures/ssr/src/pages/one.astro | 8 +++ .../test/fixtures/ssr/src/pages/two.astro | 8 +++ .../integrations/sitemap/test/ssr.test.js | 22 ++++++++ pnpm-lock.yaml | 12 +++++ 9 files changed, 113 insertions(+), 18 deletions(-) create mode 100644 .changeset/chatty-dolls-visit.md create mode 100644 packages/integrations/sitemap/test/fixtures/ssr/astro.config.mjs create mode 100644 packages/integrations/sitemap/test/fixtures/ssr/package.json create mode 100644 packages/integrations/sitemap/test/fixtures/ssr/src/pages/one.astro create mode 100644 packages/integrations/sitemap/test/fixtures/ssr/src/pages/two.astro create mode 100644 packages/integrations/sitemap/test/ssr.test.js diff --git a/.changeset/chatty-dolls-visit.md b/.changeset/chatty-dolls-visit.md new file mode 100644 index 000000000..6b9e53e88 --- /dev/null +++ b/.changeset/chatty-dolls-visit.md @@ -0,0 +1,5 @@ +--- +'@astrojs/sitemap': minor +--- + +Adds support to SSR routes to sitemap generation. diff --git a/packages/integrations/sitemap/package.json b/packages/integrations/sitemap/package.json index afd959a62..7c465494e 100644 --- a/packages/integrations/sitemap/package.json +++ b/packages/integrations/sitemap/package.json @@ -37,6 +37,7 @@ "zod": "^3.17.3" }, "devDependencies": { + "@astrojs/node": "workspace:*", "astro": "workspace:*", "astro-scripts": "workspace:*", "chai": "^4.3.6", diff --git a/packages/integrations/sitemap/src/index.ts b/packages/integrations/sitemap/src/index.ts index e6e45ddd1..0814ae0e1 100644 --- a/packages/integrations/sitemap/src/index.ts +++ b/packages/integrations/sitemap/src/index.ts @@ -51,6 +51,8 @@ const OUTFILE = 'sitemap-index.xml'; const createPlugin = (options?: SitemapOptions): AstroIntegration => { let config: AstroConfig; + const logger = new Logger(PKG_NAME); + return { name: PKG_NAME, @@ -59,10 +61,15 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => { config = cfg; }, - 'astro:build:done': async ({ dir, pages }) => { - const logger = new Logger(PKG_NAME); - + 'astro:build:done': async ({ dir, routes }) => { try { + if (!config.site) { + logger.warn( + 'The Sitemap integration requires the `site` astro.config option. Skipping.' + ); + return; + } + const opts = validateOptions(config.site, options); const { filter, customPages, serialize, entryLimit } = opts; @@ -78,12 +85,30 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => { return; } - let pageUrls = pages.map((p) => { - if (p.pathname !== '' && !finalSiteUrl.pathname.endsWith('/')) - finalSiteUrl.pathname += '/'; - const path = finalSiteUrl.pathname + p.pathname; - return new URL(path, finalSiteUrl).href; - }); + let pageUrls = routes.reduce((urls, r) => { + /** + * Dynamic URLs have entries with `undefined` pathnames + */ + if (r.pathname) { + /** + * remove the initial slash from relative pathname + * because `finalSiteUrl` always has trailing slash + */ + const path = finalSiteUrl.pathname + r.generate(r.pathname).substring(1); + + let newUrl = new URL(path, finalSiteUrl).href; + + if (config.trailingSlash === 'never') { + urls.push(newUrl); + } else if (config.build.format === 'directory' && !newUrl.endsWith('/')) { + urls.push(newUrl + '/'); + } else { + urls.push(newUrl); + } + } + + return urls; + }, []); try { if (filter) { @@ -95,18 +120,11 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => { } if (customPages) { - pageUrls = [...pageUrls, ...customPages]; + pageUrls = Array.from(new Set([...pageUrls, ...customPages])); } if (pageUrls.length === 0) { - // offer suggestion for SSR users - if (config.output !== 'static') { - logger.warn( - `No pages found! We can only detect sitemap routes for "static" builds. Since you are using an SSR adapter, we recommend manually listing your sitemap routes using the "customPages" integration option.\n\nExample: \`sitemap({ customPages: ['https://example.com/route'] })\`` - ); - } else { - logger.warn(`No pages found!\n\`${OUTFILE}\` not created.`); - } + logger.warn(`No pages found!\n\`${OUTFILE}\` not created.`); return; } diff --git a/packages/integrations/sitemap/test/fixtures/ssr/astro.config.mjs b/packages/integrations/sitemap/test/fixtures/ssr/astro.config.mjs new file mode 100644 index 000000000..d914d4357 --- /dev/null +++ b/packages/integrations/sitemap/test/fixtures/ssr/astro.config.mjs @@ -0,0 +1,12 @@ +import { defineConfig } from 'astro/config'; +import sitemap from '@astrojs/sitemap'; +import nodeServer from '@astrojs/node' + +export default defineConfig({ + integrations: [sitemap()], + site: 'http://example.com', + output: 'server', + adapter: nodeServer({ + mode: "standalone" + }) +}) diff --git a/packages/integrations/sitemap/test/fixtures/ssr/package.json b/packages/integrations/sitemap/test/fixtures/ssr/package.json new file mode 100644 index 000000000..980e02e73 --- /dev/null +++ b/packages/integrations/sitemap/test/fixtures/ssr/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/sitemap-trailing-slash", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*", + "@astrojs/sitemap": "workspace:*" + } +} diff --git a/packages/integrations/sitemap/test/fixtures/ssr/src/pages/one.astro b/packages/integrations/sitemap/test/fixtures/ssr/src/pages/one.astro new file mode 100644 index 000000000..0c7fb90a7 --- /dev/null +++ b/packages/integrations/sitemap/test/fixtures/ssr/src/pages/one.astro @@ -0,0 +1,8 @@ + + + One + + +

One

+ + diff --git a/packages/integrations/sitemap/test/fixtures/ssr/src/pages/two.astro b/packages/integrations/sitemap/test/fixtures/ssr/src/pages/two.astro new file mode 100644 index 000000000..e7ba9910e --- /dev/null +++ b/packages/integrations/sitemap/test/fixtures/ssr/src/pages/two.astro @@ -0,0 +1,8 @@ + + + Two + + +

Two

+ + diff --git a/packages/integrations/sitemap/test/ssr.test.js b/packages/integrations/sitemap/test/ssr.test.js new file mode 100644 index 000000000..e6f8412d5 --- /dev/null +++ b/packages/integrations/sitemap/test/ssr.test.js @@ -0,0 +1,22 @@ +import { loadFixture, readXML } from './test-utils.js'; +import { expect } from 'chai'; + +describe('SSR support', () => { + /** @type {import('./test-utils.js').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/ssr/', + }); + await fixture.build(); + }); + + it('SSR pages require zero config', async () => { + const data = await readXML(fixture.readFile('/client/sitemap-0.xml')); + const urls = data.urlset.url; + + expect(urls[0].loc[0]).to.equal('http://example.com/one/'); + expect(urls[1].loc[0]).to.equal('http://example.com/two/'); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49ad594ee..c770aa864 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4505,6 +4505,9 @@ importers: specifier: ^3.17.3 version: 3.20.6 devDependencies: + '@astrojs/node': + specifier: workspace:* + version: link:../node astro: specifier: workspace:* version: link:../../astro @@ -4521,6 +4524,15 @@ importers: specifier: 0.5.0 version: 0.5.0 + packages/integrations/sitemap/test/fixtures/ssr: + dependencies: + '@astrojs/sitemap': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + packages/integrations/sitemap/test/fixtures/trailing-slash: dependencies: '@astrojs/sitemap':