Custom Serialization
Override the default XML generation with your own serialization logic.
Basic Usage
Use the serialize option to provide a custom XML serializer:
import sitemap from "@pyyupsk/vite-plugin-sitemap";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
sitemap({
hostname: "https://example.com",
serialize: (routes) => {
// Return custom XML string
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${routes.map((route) => `<url><loc>${route.url}</loc></url>`).join("\n ")}
</urlset>`;
},
}),
],
});Function Signature
type XmlSerializer = (routes: Route[]) => string | Promise<string>;The function receives an array of validated routes and must return the complete XML string.
Using Built-in Helpers
Import helper functions for building XML elements:
import sitemap, { buildSitemapXml } from "@pyyupsk/vite-plugin-sitemap";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
sitemap({
hostname: "https://example.com",
serialize: (routes) => {
// Use the built-in helper for consistent output
return buildSitemapXml(routes);
},
}),
],
});Async Serialization
The serializer can be async:
sitemap({
hostname: "https://example.com",
serialize: async (routes) => {
// Fetch additional data
const metadata = await fetchSiteMetadata();
// Generate XML with additional context
return generateCustomXml(routes, metadata);
},
});Adding Custom Elements
Add custom XML elements not supported by default:
sitemap({
hostname: "https://example.com",
serialize: (routes) => {
const urls = routes
.map(
(route) => `
<url>
<loc>${escapeXml(route.url)}</loc>
${route.lastmod ? `<lastmod>${route.lastmod}</lastmod>` : ""}
${route.changefreq ? `<changefreq>${route.changefreq}</changefreq>` : ""}
${route.priority ? `<priority>${route.priority}</priority>` : ""}
<!-- Custom extension -->
<custom:rating>${route.rating || 0}</custom:rating>
</url>`,
)
.join("");
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:custom="http://example.com/custom">
${urls}
</urlset>`;
},
});XML Escaping
When building custom XML, properly escape special characters:
function escapeXml(str: string): string {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}TIP
The built-in XML builders (buildSitemapXml, buildUrlElement) automatically handle XML escaping.
Filtering Routes
Filter routes during serialization:
sitemap({
hostname: "https://example.com",
serialize: (routes) => {
// Only include high-priority routes
const filteredRoutes = routes.filter((r) => (r.priority || 0.5) >= 0.7);
return buildSitemapXml(filteredRoutes);
},
});TIP
Prefer using the transform option or exclude patterns for filtering. They run before validation and are more efficient.
Sorting Routes
Sort routes in the output:
sitemap({
hostname: "https://example.com",
serialize: (routes) => {
// Sort by priority (highest first)
const sorted = [...routes].sort((a, b) => (b.priority || 0.5) - (a.priority || 0.5));
return buildSitemapXml(sorted);
},
});Adding Comments
Add XML comments for documentation:
sitemap({
hostname: "https://example.com",
serialize: (routes) => {
const now = new Date().toISOString();
return `<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by @pyyupsk/vite-plugin-sitemap -->
<!-- Last updated: ${now} -->
<!-- Total URLs: ${routes.length} -->
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${routes.map((r) => ` <url><loc>${escapeXml(r.url)}</loc></url>`).join("\n")}
</urlset>`;
},
});Alternative Output Formats
Generate non-XML formats (though not standard sitemap format):
// JSON output (for debugging)
sitemap({
hostname: "https://example.com",
filename: "sitemap.json",
serialize: (routes) => JSON.stringify(routes, null, 2),
});
// Plain text URL list
sitemap({
hostname: "https://example.com",
filename: "urls.txt",
serialize: (routes) => routes.map((r) => r.url).join("\n"),
});WARNING
Non-XML formats won't be recognized by search engines as valid sitemaps.
Full Example
import sitemap from "@pyyupsk/vite-plugin-sitemap";
import { defineConfig } from "vite";
// Local escape function for custom XML
function escapeXml(str: string): string {
return str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
export default defineConfig({
plugins: [
sitemap({
hostname: "https://example.com",
serialize: (routes) => {
const timestamp = new Date().toISOString();
// Group routes by section
const sections = {
pages: routes.filter((r) => !r.url.includes("/blog/")),
blog: routes.filter((r) => r.url.includes("/blog/")),
};
const buildUrl = (route) => {
const elements = [` <loc>${escapeXml(route.url)}</loc>`];
if (route.lastmod) {
elements.push(` <lastmod>${route.lastmod}</lastmod>`);
}
if (route.changefreq) {
elements.push(` <changefreq>${route.changefreq}</changefreq>`);
}
if (route.priority !== undefined) {
elements.push(` <priority>${route.priority}</priority>`);
}
return ` <url>\n${elements.join("\n")}\n </url>`;
};
return `<?xml version="1.0" encoding="UTF-8"?>
<!--
Sitemap for example.com
Generated: ${timestamp}
Pages: ${sections.pages.length}
Blog posts: ${sections.blog.length}
Total: ${routes.length}
-->
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<!-- Main pages -->
${sections.pages.map(buildUrl).join("\n")}
<!-- Blog posts -->
${sections.blog.map(buildUrl).join("\n")}
</urlset>`;
},
}),
],
});