Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat rss #3123

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions lib/rss.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Feed } from 'feed'
import fs from 'fs'
import ReactDOMServer from 'react-dom/server'

export const rssCacheHead = 'public, max-age=3600, stale-while-revalidate=600'

/**
* 生成RSS内容
* @param {*} post
Expand All @@ -25,11 +27,7 @@ const createFeedContent = async post => {
}
}

/**
* 生成RSS数据
* @param {*} props
*/
export async function generateRss(props) {
export async function generateRssData(props) {
const { NOTION_CONFIG, siteInfo, latestPosts } = props
const TITLE = siteInfo?.title
const DESCRIPTION = siteInfo?.description
Expand All @@ -39,19 +37,14 @@ export async function generateRss(props) {
const SUB_PATH = NOTION_CONFIG?.SUB_PATH || BLOG.SUB_PATH
const CONTACT_EMAIL = NOTION_CONFIG?.CONTACT_EMAIL || BLOG.CONTACT_EMAIL

// 检查 feed 文件是否在10分钟内更新过
if (isFeedRecentlyUpdated('./public/rss/feed.xml', 10)) {
return
}

console.log('[RSS订阅] 生成/rss/feed.xml')
console.log('[RSS订阅] 生成rss')
const year = new Date().getFullYear()
const feed = new Feed({
title: TITLE,
description: DESCRIPTION,
link: `${LINK}/${SUB_PATH}`,
language: LANG,
favicon: `${LINK}/favicon.png`,
favicon: `${LINK}/favicon.ico`,
copyright: `All rights reserved ${year}, ${AUTHOR}`,
author: {
name: AUTHOR,
Expand All @@ -68,6 +61,19 @@ export async function generateRss(props) {
date: new Date(post?.publishDay)
})
}
return feed
}

/**
* 生成RSS数据
* @param {*} props
*/
export async function generateRss(props) {
// 检查 feed 文件是否在10分钟内更新过
if (isFeedRecentlyUpdated('./public/rss/feed.xml', 10)) {
return
}
const feed = await generateRssData(props)

try {
fs.mkdirSync('./public/rss', { recursive: true })
Expand Down
11 changes: 11 additions & 0 deletions lib/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
// 封装异步加载资源的方法
import { memo } from 'react'
import BLOG from '@/blog.config'

/**
* 判断是否是Vercel生产环境,主要为了避免写入文件
* @type {boolean}
*/
export const isNotVercelProduction =
process.env.npm_lifecycle_event === 'build' ||
process.env.npm_lifecycle_event === 'export' ||
!BLOG['isProd']


/**
* 判断是否客户端
Expand Down
38 changes: 24 additions & 14 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,37 @@ const locales = (function () {
return langs
})()

// 删除文件,并自动生成日志
function deleteFileIfExists(relativePath) {
// 使用 path.resolve 解析为完整路径
const filePath = path.resolve(__dirname, relativePath)
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath)
// 通过路径生成文件名和目录
const fileName = path.basename(filePath) // 获取文件名
const directory = path.dirname(filePath) // 获取文件所在目录
const relativeDirectory = path.relative(__dirname, directory) // 获取相对路径
// 生成日志消息
console.log(`Deleted existing ${fileName} from ${relativeDirectory || 'root directory'}`)
}
}

// 编译前执行
// eslint-disable-next-line no-unused-vars
const preBuild = (function () {
(function () {
if (
!process.env.npm_lifecycle_event === 'export' &&
!process.env.npm_lifecycle_event === 'build'
) {
return
}
// 删除 public/sitemap.xml 文件 ; 否则会和/pages/sitemap.xml.js 冲突。
const sitemapPath = path.resolve(__dirname, 'public', 'sitemap.xml')
if (fs.existsSync(sitemapPath)) {
fs.unlinkSync(sitemapPath)
console.log('Deleted existing sitemap.xml from public directory')
}

const sitemap2Path = path.resolve(__dirname, 'sitemap.xml')
if (fs.existsSync(sitemap2Path)) {
fs.unlinkSync(sitemap2Path)
console.log('Deleted existing sitemap.xml from root directory')
}
// 删除 public/sitemap.xml 文件
deleteFileIfExists('public/sitemap.xml')
// 删除根目录的 sitemap.xml 文件
deleteFileIfExists('sitemap.xml')
// 删除 rss 文件
deleteFileIfExists('public/rss/feed.xml')
deleteFileIfExists('public/rss/atom.xml')
deleteFileIfExists('public/rss/feed.json')
})()

/**
Expand Down
17 changes: 10 additions & 7 deletions pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData, getPostBlocks } from '@/lib/db/getSiteData'
import { generateRobotsTxt } from '@/lib/robots.txt'
import { generateRss } from '@/lib/rss'
import { generateSitemapXml } from '@/lib/sitemap.xml'
import { DynamicLayout } from '@/themes/theme'
import { isNotVercelProduction } from '@/lib/utils'
import { generateRss } from '@/lib/rss'

/**
* 首页布局
Expand Down Expand Up @@ -54,12 +55,14 @@ export async function getStaticProps(req) {
}
}

// 生成robotTxt
generateRobotsTxt(props)
// 生成Feed订阅
generateRss(props)
// 生成
generateSitemapXml(props)
if (isNotVercelProduction) {
// 生成robotTxt
generateRobotsTxt(props)
// 生成Feed订阅
generateRss(props)
// 生成
generateSitemapXml(props)
}

// 生成全文索引 - 仅在 yarn build 时执行 && process.env.npm_lifecycle_event === 'build'

Expand Down
16 changes: 16 additions & 0 deletions pages/rss/atom.xml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import { generateRssData, rssCacheHead } from '@/lib/rss'

export async function getServerSideProps(ctx) {
const from = 'rss-atom-xml-props'
const { locale } = ctx.req
const globalData = await getGlobalData({ from, locale })
const rssData = await generateRssData(globalData)
ctx.res.setHeader('Cache-Control', rssCacheHead)
ctx.res.setHeader('Content-Type', 'text/xml')
ctx.res.write(rssData.atom1()) // 直接返回内容
ctx.res.end()
return { props: {} }
}

export default function rssAtomXml() {}
16 changes: 16 additions & 0 deletions pages/rss/feed.json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import { generateRssData, rssCacheHead } from '@/lib/rss'

export async function getServerSideProps(ctx) {
const from = 'rss-feed-json-props'
const { locale } = ctx.req
const globalData = await getGlobalData({ from, locale })
const rssData = await generateRssData(globalData)
ctx.res.setHeader('Cache-Control', rssCacheHead)
ctx.res.setHeader('Content-Type', 'application/json')
ctx.res.write(rssData.json1()) // 直接返回内容
ctx.res.end()
return { props: {} }
}

export default function rssFeedJson() {}
16 changes: 16 additions & 0 deletions pages/rss/feed.xml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getGlobalData } from '@/lib/db/getSiteData'
import { generateRssData, rssCacheHead } from '@/lib/rss'

export async function getServerSideProps(ctx) {
const from = 'rss-feed-xml-props'
const { locale } = ctx.req
const globalData = await getGlobalData({ from, locale })
const rssData = await generateRssData(globalData)
ctx.res.setHeader('Cache-Control', rssCacheHead)
ctx.res.setHeader('Content-Type', 'text/xml')
ctx.res.write(rssData.rss2()) // 直接返回内容
ctx.res.end()
return { props: {} }
}

export default function rssFeedXML() {}