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>
哇!又賺了一天人民幣

浙公網安備 33010602011771號