Nuxt.js 生成sitemap站点地图文件
Nuxt.js 生成sitemap站点地图文件
背景介绍
使用nuxt
框架生成静态文件支持SEO优化,打包之后需要生成一个 sitemap.xml
文件方便提交搜索引擎进行收录。官网有提供一个插件sitemap 但是如果是动态路由需要手动一个个配置比较麻烦,无法自动检索生成。所以自己编写一个生成 sitemap 模块
准备工作
创建nuxt
项目,参考中文官网。安装JavaScript
模板ejs工具
$ npm install ejs
相关网站
- 插件sitemap: https://sitemap.nuxtjs.org/
- 中文官网:https://www.nuxtjs.cn/
- 英文官网:https://v2.nuxt.com/
- JS模板工具ejs:https://github.com/mde/ejs
- 扩展模块:https://v2.nuxt.com/docs/directory-structure/modules
sitemap模块
项目根目录创建 modules
目录,以及对应文件,详细文件内容放在文末。
├─modules │ └─robots.ejs // robots模板 │ └─sitemap.js // 站点地图js │ └─template.ejs //sitemap 模板
配置 nuxt.config.js
在 modules
数组增加以下内容 modules/sitemap
刚才自定义模块,excludes
需要排除的目录,hostname
站点域名
nuxt.config.js
export default { ...省略 // Modules: https://go.nuxtjs.dev/config-modules modules: [ ...省略, ['modules/sitemap', { excludes: ['_nuxt', 'img'], hostname: 'https://www.example.com' } ], ], }
执行命令生成静态资源
$npm run generate
打开项目根目录下dist
(默认输出路径),会多出两个文件
├─robots.txt ├─sitemap.xml
结果展示
官方示例 modules
编写自己的模块
模块就是函数。它们可以打包为 npm 模块或直接包含在项目源代码中。
nuxt.config.js
export default { exampleMsg: 'hello', modules: [ // Simple usage '~/modules/example', // Passing options directly ['~/modules/example', { token: '123' }] ] }
modules/example.js
export default function ExampleModule(moduleOptions) { console.log(moduleOptions.token) // '123' console.log(this.options.exampleMsg) // 'hello' this.nuxt.hook('ready', async nuxt => { console.log('Nuxt is ready') }) } // REQUIRED if publishing the module as npm package module.exports.meta = require('./package.json')
1) ModuleOptions
moduleOptions
:modules
这是用户使用数组传递的对象 。我们可以用它来定制它的行为。
有时,如果我们可以在注册模块时使用顶级选项会更方便 nuxt.config.js
。这使我们能够组合多个选项源。
nuxt.config.js
export default { modules: [['@nuxtjs/axios', { anotherOption: true }]], // axios module is aware of this by using `this.options.axios` axios: { option1, option2 } }
2) this.options
this.options
:您可以使用此参考直接访问 Nuxt 选项。nuxt.config.js
这是分配有所有默认选项的用户内容 。它可用于模块之间的共享选项。
模块.js
export default function (moduleOptions) { // `options` will contain option1, option2 and anotherOption const options = Object.assign({}, this.options.axios, moduleOptions) // ... }
modules文件
modules/robots.ejs
# robots.txt User-agent: Baiduspider Disallow: User-agent: Sosospider Disallow: User-agent: sogou spider Disallow: User-agent: YodaoBot Disallow: User-agent: Googlebot Disallow: User-agent: Bingbot Disallow: User-agent: Slurp Disallow: User-agent: Teoma Disallow: User-agent: ia_archiver Disallow: User-agent: twiceler Disallow: User-agent: MSNBot Disallow: User-agent: Scrubby Disallow: User-agent: Robozilla Disallow: User-agent: Gigabot Disallow: User-agent: googlebot-image Disallow: User-agent: googlebot-mobile Disallow: User-agent: yahoo-mmcrawler Disallow: User-agent: yahoo-blogs/v3.9 Disallow: User-agent: psbot Disallow: Disallow: /bin/ Disallow: /js/ Disallow: /img/ Sitemap: <%= hostname %>/sitemap.xml
modules/sitemap.js
/** * @description 生成 sitemap robots 模块 * @author 方圆百里 * @time 2023年10月12日 */ const path = require('path'); const fs = require('fs'); const ejs = require('ejs'); /** * @description 获取当前目录下载的所有路径 -同步 * @author 方圆百里 * * @param {String} dir 文件路径 * @returns {Array} 返回路径数组 */ const loadFiles = (dir) => { try { const data = fs.readdirSync(dir); return data; } catch (e) { console.error('获取目录路径异常', e) return undefined; } } /** * @description 获取文件信息 * @author 方圆百里 * * @param {String} dir 文件路径 * @returns {Array} 返回路径数组 */ const statFile = (full_path) => { try { const stat = fs.statSync(full_path); stat.path = full_path; return stat; } catch (e) { console.error('获取目录路径异常', e) return undefined; } } /** * @description 递归处理文件路径 * @author 方圆百里 * * @param {String} dir 文件路径 * @param {String} list 文件信息数组 * @returns {Array} 返回路径数组 */ const handleFiles = (dir, list = [], excludes) => { // 1、加载当前目录下所有路径,包含文件夹和文件 const data = loadFiles(dir); if (data) { data.forEach(item => { if (!excludes.includes(item)) { // 2、拼接绝对路径 const absolutePath = path.join(dir, item) // 3、获取文件基本信息 const stat = statFile(absolutePath); // 4、如果是文件,处理基本信息 if (stat.isFile()) { list.push({ size: stat.size, time: stat.ctime, ...path.parse(stat.path) }) } else { // 5、目录递归进行处理 handleFiles(stat.path, list, excludes); } } }) } return list; } /** * @description 格式化日期 * @author 方圆百里 * * @param {Date} date 日期 * @returns {String} 2023-10-12 */ const formatYear = (date) => { // 获取年、月和日 const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始,需要加1,同时确保两位数格式 const day = date.getDate().toString().padStart(2, '0'); // 确保两位数格式 // 格式化日期 return `${year}-${month}-${day}`; } /** * @description 生成站点地图 * @author 方圆百里 * * @param {String} dist 打包后文件路径 * @param {String} hostname 主机名称 * @param {Array} excludes 排除路径 * */ const generateSitemap = (dist, hostname, excludes) => { const data = handleFiles(dist, [], excludes) const set = new Set(); for (var i = 0; i < data.length; i++) { const f = data[i]; if (f.ext === '.html') { const relative = f.dir.replace(dist, "") if (relative) { const paths = relative.split(path.sep); let loc = hostname; for (var x = 1; x < paths.length; x++) { loc += "/" + paths[x]; } set.add({ loc: loc, time: formatYear(f.time) }); } } } // 读取模板文件 const template = fs.readFileSync('modules/template.ejs', 'utf-8'); // 提供模板数据 const datas = { urls: set }; // 使用模板引擎渲染模板 const renderedContent = ejs.render(template, datas); // 写入生成的文件 fs.writeFileSync(path.join(dist, 'sitemap.xml'), renderedContent); console.log('sitemap.xml 生成成功!'); const robotsRendered = ejs.render(fs.readFileSync('modules/robots.ejs', 'utf-8'), { hostname }); // 写入生成的文件 fs.writeFileSync(path.join(dist, 'robots.txt'), robotsRendered); console.log('robots.txt 生成成功!'); } export default function ExampleModule(moduleOptions) { const dist = this.options.generate?.dir || 'dist'; // 打包输出路径 const hostname = moduleOptions.hostname || 'https://www.example.com'; // 主机名称 const excludes = moduleOptions.excludes || ['.nuxt']; // 排除路径 console.log('打包输出路径:=====>', dist) console.log('主机名称:=====>', hostname) console.log('排除路径:=====>', excludes) this.nuxt.hook('generate:done', async generator => { // 这将在Nuxt生成页面之之后调用 console.log('执行 generate 完成') generateSitemap(dist, hostname, excludes) }) } // 将模块发布为npm包 module.exports.meta = require('../package.json')
modules/template.ejs
<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"> <url> <% urls.forEach(function(item) { %> <loc><%= item.loc %></loc> <lastmod><%= item.time %></lastmod> <changefreq>monthly</changefreq> <priority>0.8</priority> <% }); %> </url> </urlset>
哇!又赚了一天人民币
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 本地部署 DeepSeek:小白也能轻松搞定!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 在缓慢中沉淀,在挑战中重生!2024个人总结!
· 大人,时代变了! 赶快把自有业务的本地AI“模型”训练起来!
· 从 Windows Forms 到微服务的经验教训