关于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:stylesheet
  version="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目录下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值