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
This commit is contained in:
parent
cac4a321e8
commit
ad907196cb
9 changed files with 113 additions and 18 deletions
5
.changeset/chatty-dolls-visit.md
Normal file
5
.changeset/chatty-dolls-visit.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/sitemap': minor
|
||||
---
|
||||
|
||||
Adds support to SSR routes to sitemap generation.
|
|
@ -37,6 +37,7 @@
|
|||
"zod": "^3.17.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/node": "workspace:*",
|
||||
"astro": "workspace:*",
|
||||
"astro-scripts": "workspace:*",
|
||||
"chai": "^4.3.6",
|
||||
|
|
|
@ -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<string[]>((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;
|
||||
}
|
||||
|
||||
|
|
12
packages/integrations/sitemap/test/fixtures/ssr/astro.config.mjs
vendored
Normal file
12
packages/integrations/sitemap/test/fixtures/ssr/astro.config.mjs
vendored
Normal file
|
@ -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"
|
||||
})
|
||||
})
|
9
packages/integrations/sitemap/test/fixtures/ssr/package.json
vendored
Normal file
9
packages/integrations/sitemap/test/fixtures/ssr/package.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "@test/sitemap-trailing-slash",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"astro": "workspace:*",
|
||||
"@astrojs/sitemap": "workspace:*"
|
||||
}
|
||||
}
|
8
packages/integrations/sitemap/test/fixtures/ssr/src/pages/one.astro
vendored
Normal file
8
packages/integrations/sitemap/test/fixtures/ssr/src/pages/one.astro
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>One</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>One</h1>
|
||||
</body>
|
||||
</html>
|
8
packages/integrations/sitemap/test/fixtures/ssr/src/pages/two.astro
vendored
Normal file
8
packages/integrations/sitemap/test/fixtures/ssr/src/pages/two.astro
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Two</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Two</h1>
|
||||
</body>
|
||||
</html>
|
22
packages/integrations/sitemap/test/ssr.test.js
Normal file
22
packages/integrations/sitemap/test/ssr.test.js
Normal file
|
@ -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/');
|
||||
});
|
||||
});
|
|
@ -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':
|
||||
|
|
Loading…
Reference in a new issue