summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ktym4a <shoma@ktym4a.me> 2024-02-20 15:36:09 +0700
committerGravatar GitHub <noreply@github.com> 2024-02-20 08:36:09 +0000
commit9b78c992750cdb99c40a89a00ea2a0d1c00877d7 (patch)
tree2ac4a3f5dbe852e54138664b4e0c17aa6efd61ba
parent3c73441eb2eaba767d6dad1b30c0353195d28791 (diff)
downloadastro-9b78c992750cdb99c40a89a00ea2a0d1c00877d7.tar.gz
astro-9b78c992750cdb99c40a89a00ea2a0d1c00877d7.tar.zst
astro-9b78c992750cdb99c40a89a00ea2a0d1c00877d7.zip
Add option to prefix sitemap (#9846)
* Add option to prefix sitemap * Fix call resolve twice * let to const * Apply suggestions from code review Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> * change changeset patch to minor * use node:test * Update changeset * Add regex validation for prefix * Update .changeset/eighty-falcons-tease.md Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * Update prefix regex in SitemapOptionsSchema --------- Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
-rw-r--r--.changeset/eighty-falcons-tease.md24
-rw-r--r--packages/integrations/sitemap/src/index.ts31
-rw-r--r--packages/integrations/sitemap/src/schema.ts7
-rw-r--r--packages/integrations/sitemap/test/prefix.test.js72
4 files changed, 125 insertions, 9 deletions
diff --git a/.changeset/eighty-falcons-tease.md b/.changeset/eighty-falcons-tease.md
new file mode 100644
index 000000000..7ea106f1e
--- /dev/null
+++ b/.changeset/eighty-falcons-tease.md
@@ -0,0 +1,24 @@
+---
+"@astrojs/sitemap": minor
+---
+
+Adds a new configuration option `prefix` that allows you to change the default `sitemap-*.xml` file name.
+
+By default, running `astro build` creates both `sitemap-index.xml` and `sitemap-0.xml` in your output directory.
+
+To change the names of these files (e.g. to `astrosite-index.xml` and `astrosite-0.xml`), set the `prefix` option in your `sitemap` integration configuration:
+
+```
+import { defineConfig } from 'astro/config';
+import sitemap from '@astrojs/sitemap';
+export default defineConfig({
+ site: 'https://example.com',
+ integrations: [
+ sitemap({
+ prefix: 'astrosite-',
+ }),
+ ],
+});
+```
+
+This option is useful when Google Search Console is unable to fetch your default sitemap files, but can read renamed files.
diff --git a/packages/integrations/sitemap/src/index.ts b/packages/integrations/sitemap/src/index.ts
index c254fb662..4c049df91 100644
--- a/packages/integrations/sitemap/src/index.ts
+++ b/packages/integrations/sitemap/src/index.ts
@@ -1,12 +1,14 @@
import type { AstroConfig, AstroIntegration } from 'astro';
-import path from 'node:path';
+import path, { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { EnumChangefreq, LinkItem as LinkItemBase, SitemapItemLoose } from 'sitemap';
-import { simpleSitemapAndIndex } from 'sitemap';
+import { SitemapAndIndexStream, SitemapStream, streamToPromise } from 'sitemap';
import { ZodError } from 'zod';
import { generateSitemap } from './generate-sitemap.js';
import { validateOptions } from './validate-options.js';
+import { createWriteStream } from 'node:fs';
+import { Readable } from 'node:stream';
export { EnumChangefreq as ChangeFreqEnum } from 'sitemap';
export type ChangeFreq = `${EnumChangefreq}`;
@@ -33,6 +35,8 @@ export type SitemapOptions =
lastmod?: Date;
priority?: number;
+ prefix?: string;
+
// called for each sitemap item just before to save them on disk, sync or async
serialize?(item: SitemapItem): SitemapItem | Promise<SitemapItem | undefined> | undefined;
}
@@ -44,7 +48,6 @@ function formatConfigErrorMessage(err: ZodError) {
}
const PKG_NAME = '@astrojs/sitemap';
-const OUTFILE = 'sitemap-index.xml';
const STATUS_CODE_PAGES = new Set(['404', '500']);
function isStatusCodePage(pathname: string): boolean {
@@ -77,7 +80,8 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => {
const opts = validateOptions(config.site, options);
- const { filter, customPages, serialize, entryLimit } = opts;
+ const { filter, customPages, serialize, entryLimit, prefix = 'sitemap-' } = opts;
+ const OUTFILE = `${prefix}index.xml`;
let finalSiteUrl: URL;
if (config.site) {
@@ -166,13 +170,22 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => {
}
}
const destDir = fileURLToPath(dir);
- await simpleSitemapAndIndex({
- hostname: finalSiteUrl.href,
- destinationDir: destDir,
- sourceData: urlData,
+
+ const sms = new SitemapAndIndexStream({
limit: entryLimit,
- gzip: false,
+ getSitemapStream: (i) => {
+ const sitemapStream = new SitemapStream({ hostname: finalSiteUrl.href });
+ const fileName = `${prefix}${i}.xml`;
+
+ const ws = sitemapStream.pipe(createWriteStream(resolve(destDir + fileName)));
+
+ return [new URL(fileName, finalSiteUrl.href).toString(), sitemapStream, ws];
+ },
});
+
+ sms.pipe(createWriteStream(resolve(destDir + OUTFILE)));
+ await streamToPromise(Readable.from(urlData).pipe(sms));
+ sms.end();
logger.info(`\`${OUTFILE}\` created at \`${path.relative(process.cwd(), destDir)}\``);
} catch (err) {
if (err instanceof ZodError) {
diff --git a/packages/integrations/sitemap/src/schema.ts b/packages/integrations/sitemap/src/schema.ts
index a7682e881..da629fc0c 100644
--- a/packages/integrations/sitemap/src/schema.ts
+++ b/packages/integrations/sitemap/src/schema.ts
@@ -34,6 +34,13 @@ export const SitemapOptionsSchema = z
changefreq: z.nativeEnum(ChangeFreq).optional(),
lastmod: z.date().optional(),
priority: z.number().min(0).max(1).optional(),
+
+ prefix: z
+ .string()
+ .regex(/^[a-zA-Z\-_]+$/gm, {
+ message: 'Only English alphabet symbols, hyphen and underscore allowed',
+ })
+ .optional(),
})
.strict()
.default(SITEMAP_CONFIG_DEFAULTS);
diff --git a/packages/integrations/sitemap/test/prefix.test.js b/packages/integrations/sitemap/test/prefix.test.js
new file mode 100644
index 000000000..fdd538d0f
--- /dev/null
+++ b/packages/integrations/sitemap/test/prefix.test.js
@@ -0,0 +1,72 @@
+import { loadFixture, readXML } from './test-utils.js';
+import { sitemap } from './fixtures/static/deps.mjs';
+import assert from 'node:assert/strict';
+import { before, describe, it } from 'node:test';
+
+describe('Prefix support', () => {
+ /** @type {import('./test-utils.js').Fixture} */
+ let fixture;
+ const prefix = 'test-';
+
+ describe('Static', () => {
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/static/',
+ integrations: [
+ sitemap(),
+ sitemap({
+ prefix,
+ }),
+ ],
+ });
+ await fixture.build();
+ });
+
+ it('Content is same', async () => {
+ const data = await readXML(fixture.readFile('/sitemap-0.xml'));
+ const prefixData = await readXML(fixture.readFile(`/${prefix}0.xml`));
+ assert.deepEqual(prefixData, data);
+ });
+
+ it('Index file load correct sitemap', async () => {
+ const data = await readXML(fixture.readFile('/sitemap-index.xml'));
+ const sitemapUrl = data.sitemapindex.sitemap[0].loc[0];
+ assert.strictEqual(sitemapUrl, 'http://example.com/sitemap-0.xml');
+
+ const prefixData = await readXML(fixture.readFile(`/${prefix}index.xml`));
+ const prefixSitemapUrl = prefixData.sitemapindex.sitemap[0].loc[0];
+ assert.strictEqual(prefixSitemapUrl, `http://example.com/${prefix}0.xml`);
+ });
+ });
+
+ describe('SSR', () => {
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/ssr/',
+ integrations: [
+ sitemap(),
+ sitemap({
+ prefix,
+ }),
+ ],
+ });
+ await fixture.build();
+ });
+
+ it('Content is same', async () => {
+ const data = await readXML(fixture.readFile('/client/sitemap-0.xml'));
+ const prefixData = await readXML(fixture.readFile(`/client/${prefix}0.xml`));
+ assert.deepEqual(prefixData, data);
+ });
+
+ it('Index file load correct sitemap', async () => {
+ const data = await readXML(fixture.readFile('/client/sitemap-index.xml'));
+ const sitemapUrl = data.sitemapindex.sitemap[0].loc[0];
+ assert.strictEqual(sitemapUrl, 'http://example.com/sitemap-0.xml');
+
+ const prefixData = await readXML(fixture.readFile(`/client/${prefix}index.xml`));
+ const prefixSitemapUrl = prefixData.sitemapindex.sitemap[0].loc[0];
+ assert.strictEqual(prefixSitemapUrl, `http://example.com/${prefix}0.xml`);
+ });
+ });
+});