关于nextjs中next-sitemap插件生成文件样式丢失问题及自定义样式处理
现象没有默认样式
修改后
代码配置如下
next-sitemap.config.js如下
// const { routing } = require('./src/i18n/routing') ;const { flatten } = require('lodash')
const fs = require('fs');
const path = require('path');// 改为硬编码locales值,与routing.ts保持一致
const locales = ['en', 'zh']
module.exports = {siteUrl: process.env.NEXT_PUBLIC_SITE_URL,changefreq: 'weekly',priority: 0.8,sitemapSize: 5000,// generateIndexSitemap: false,transform: async (config, path) => {// 👇 为所有分页文件添加 XSL 声明(包括分页和索引)return {loc: path,lastmod: config.autoLastmod ? new Date().toISOString() : undefined,xsl: '/sitemap-style.xsl'};},// 可选:自定义分页文件名格式filename: 'sitemap-[index].xml',autoLastmod: true, // 从页面文件的修改时间获取generateRobotsTxt: true,exclude: ['/404'// '/admin/*' // 通配符匹配路径],robotsTxtOptions: {policies: [{userAgent: '*', // 所有爬虫allow: '/' // 允许所有路径// disallow: '/private', // 禁止特定路径}],additionalSitemaps: [// process.env.NEXT_PUBLIC_SITE_URL + '/sitemap.xml' // 主站点地图]},// 简化的formatOutput函数,专注于添加样式表引用formatOutput: (sitemapContent) => {console.log('formatOutput正在执行...');// 在XML声明后添加样式表引用const result = sitemapContent.replace('<?xml version="1.0" encoding="UTF-8"?>','<?xml version="1.0" encoding="UTF-8"?>\n<?xml-stylesheet type="text/xsl" href="/sitemap-style.xsl"?>');console.log('formatOutput完成,已添加样式表引用');return result;},additionalPaths: async (config) => {const result = []result.push(locales.map((locale) => {return {loc: process.env.NEXT_PUBLIC_SITE_URL + `/${locale}`,changefreq: 'daily',priority: 1,lastmod: new Date().toISOString(),alternateRefs: locales.filter((targetLocale) => targetLocale === locale).map((targetLocale) => ({href: process.env.NEXT_PUBLIC_SITE_URL + `/${targetLocale}`,hreflang: targetLocale,rel: 'alternate'}))}}) || [])const posts = await fetch(process.env.NEXT_PUBLIC_FETCH_URL + '**************').then((res) => res.json())posts?.data?.map((post) =>result.push(locales.map((locale) => {return {loc: process.env.NEXT_PUBLIC_SITE_URL + `/${locale}/${post.name.toLowerCase()}`,changefreq: 'weekly',priority: 0.8,lastmod: new Date().toISOString(),alternateRefs: locales.filter((targetLocale) => targetLocale === locale).map((targetLocale) => ({href: process.env.NEXT_PUBLIC_SITE_URL + `/${targetLocale}/${post.name.toLowerCase()}`,hreflang: targetLocale,rel: 'alternate'}))}}) || []))const allGames = await fetch(process.env.NEXT_PUBLIC_FETCH_URL + '**************').then((res) => res.json())allGames?.data?.map((post) =>result.push(locales.map((locale) => {return {loc: process.env.NEXT_PUBLIC_SITE_URL + `/${locale}` + '/game/' + `${post.slug}`,changefreq: 'monthly',priority: 0.8,lastmod: new Date().toISOString(),alternateRefs: locales.filter((targetLocale) => targetLocale === locale).map((targetLocale) => ({href: process.env.NEXT_PUBLIC_SITE_URL + `/${targetLocale}` + '/game/' + `${post.slug}`,hreflang: targetLocale,rel: 'alternate'}))}}) || []))return flatten(result)}
}
postbuild.js 处理样式
// 用于处理生成的sitemap文件
const fs = require('fs');
const path = require('path');// 添加站点地图处理逻辑
function processSitemaps() {try {console.log('处理站点地图文件...');const publicDir = path.join(__dirname, 'public');// 确保样式文件存在于public目录const xslSourcePath = path.join(__dirname, 'sitemap-style.xsl');const xslDestPath = path.join(publicDir, 'sitemap-style.xsl');if (fs.existsSync(xslSourcePath)) {fs.copyFileSync(xslSourcePath, xslDestPath);console.log('已复制样式文件到public目录');} else {console.log('警告: 未找到sitemap-style.xsl文件');}// 处理所有站点地图文件const sitemapFiles = fs.readdirSync(publicDir).filter(file => file.startsWith('sitemap') && file.endsWith('.xml'));console.log(`找到 ${sitemapFiles.length} 个站点地图文件`);for (const file of sitemapFiles) {const filePath = path.join(publicDir, file);let content = fs.readFileSync(filePath, 'utf8');if (!content.includes('<?xml-stylesheet')) {console.log(`处理文件: ${file}`);// 替换XML声明,添加样式表引用content = content.replace('<?xml version="1.0" encoding="UTF-8"?>', '<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="/sitemap-style.xsl"?>');fs.writeFileSync(filePath, content, {encoding: 'utf8'});console.log(`已更新文件: ${file}`);} else {console.log(`文件 ${file} 已有样式表引用,跳过`);}}console.log('站点地图处理完成');} catch (error) {console.error('处理站点地图文件时出错:', error);}
}// 执行站点地图处理
processSitemaps();
sitemap-style.xsl 样式
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheetversion="2.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:html="http://www.w3.org/TR/REC-html40"xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0"xmlns:xhtml="http://www.w3.org/1999/xhtml"><xsl:output method="html" indent="yes" encoding="UTF-8"/><xsl:template match="/"><html><head><title><xsl:choose><xsl:when test="//sitemap:sitemapindex">Sitemap Index</xsl:when><xsl:otherwise>Sitemap</xsl:otherwise></xsl:choose></title><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><style type="text/css">body {font-family: Arial, sans-serif;font-size: 14px;color: #333;background: #fff;margin: 0;padding: 20px;}h1 {color: #1a73e8;font-size: 24px;margin: 0 0 20px;}table {border-collapse: collapse;width: 100%;margin: 20px 0;border-radius: 6px;overflow: hidden;box-shadow: 0 0 10px rgba(0,0,0,0.1);}th {background-color: #1a73e8;color: #fff;text-align: left;padding: 12px 15px;font-weight: normal;}td {padding: 12px 15px;border-bottom: 1px solid #eee;}tr:hover td {background-color: #f5f5f5;}tr:last-child td {border-bottom: none;}a {color: #1a73e8;text-decoration: none;}a:hover {text-decoration: underline;}.url {max-width: 500px;word-break: break-all;}.count {text-align: center;font-weight: bold;color: #388e3c;font-size: 16px;padding: 10px 0;}.footer {margin-top: 20px;color: #666;font-size: 12px;text-align: center;}</style></head><body><h1><xsl:choose><xsl:when test="//sitemap:sitemapindex">Sitemap Index</xsl:when><xsl:otherwise>Sitemap</xsl:otherwise></xsl:choose></h1><xsl:choose><xsl:when test="//sitemap:sitemapindex"><!-- This is a sitemap index file --><p>This file contains <xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/> sitemaps.</p><div class="count">Total Sitemaps: <xsl:value-of select="count(sitemap:sitemapindex/sitemap:sitemap)"/></div><table><tr><th>Sitemap URL</th><th>Last Modified</th></tr><xsl:for-each select="sitemap:sitemapindex/sitemap:sitemap"><tr><td class="url"><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc"/></a></td><td><xsl:value-of select="sitemap:lastmod"/></td></tr></xsl:for-each></table></xsl:when><xsl:otherwise><!-- This is a sitemap file --><p>This sitemap contains <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/> URLs.</p><div class="count">Total URLs: <xsl:value-of select="count(sitemap:urlset/sitemap:url)"/></div><table><tr><th>URL</th><th>Priority</th><th>Change Frequency</th><th>Last Modified</th></tr><xsl:for-each select="sitemap:urlset/sitemap:url"><tr><td class="url"><a href="{sitemap:loc}"><xsl:value-of select="sitemap:loc"/></a></td><td><xsl:value-of select="sitemap:priority"/></td><td><xsl:value-of select="sitemap:changefreq"/></td><td><xsl:value-of select="sitemap:lastmod"/></td></tr></xsl:for-each></table></xsl:otherwise></xsl:choose>
<!--<div class="footer"><p>Generated by Next.js and next-sitemap</p></div> --></body></html></xsl:template>
</xsl:stylesheet>
存放位置
next-sitemap.config.js和postbuild.js存放根目录,和package.json同级
sitemap-style.xsl和生成的sitemap.xml同一个位置,我放在public目录下