Next.js 13 博客数据处理和展示
javascript/nimport fs from 'fs'/nimport path from 'path'/nimport matter from 'gray-matter'/nimport { remark } from 'remark'/nimport html from 'remark-html'/nimport remarkPrism from /'remark-prism/';/nimport Info from '@/components/Info'/n/nexport const info = Info();/nexport const Directory = path.join(process.cwd(), info.path)/n/nexport function getAllPostIds() {/n const subdirectories = fs.readdirSync(Directory, { withFileTypes: true })/n .filter(dirent => dirent.isDirectory())/n .map(dirent => dirent.name)/n/n const posts = subdirectories.flatMap(subdirectory => {/n const directoryPath = path.join(Directory, subdirectory)/n const filenames = fs.readdirSync(directoryPath)/n .filter(filename => filename.endsWith('.md'))/n/n return filenames.map(filename => {/n return {/n params: {/n slug: [subdirectory, filename.replace(//.md$/, '.html')],/n },/n }/n })/n })/n/n // Sort posts by date/n // Format the path correctly/n const paths = posts.map(({ params }) => ({ /n params: {/n slug: params.slug,/n },/n }));/n/n return paths;/n}/n/nexport async function getSortedPostsData() {/n/n const subdirectories = fs.readdirSync(Directory, { withFileTypes: true })/n .filter(dirent => dirent.isDirectory())/n .map(dirent => dirent.name)/n/n const posts = (await Promise.all(subdirectories.map(async (subdirectory) => {/n const directoryPath = path.join(Directory, subdirectory)/n const filenames = fs.readdirSync(directoryPath)/n .filter(filename => filename.endsWith('.md'))/n/n const allPostsData = await Promise.all(filenames.map(async (filename) => {/n const slug = [subdirectory, filename.replace(//.md$/, '').concat('.html')].join('/')/n const fullPath = path.join(Directory, [subdirectory, filename].join('//'))/n const fileContents = fs.readFileSync(fullPath, 'utf8')/n const matterResult = matter(fileContents)/n const contentCount = await remark()/n .use(html, { sanitize: false })/n .process(matterResult.content)/n/n const contCount = contentCount.toString().replace(/<//?(h/d).*>/g, '');/n const NoImages = contCount.replace(/<img[^>]*>/g, '').trim();/n const NoHtml = NoImages.replace(/<//?[^>]+(>|$)/g, '');/n const cnMatches = NoHtml.match(/[/u4e00-/u9fa5]/g) || [];/n const enMatches = NoHtml.match(/[a-zA-Z]+/g) || []; /n const cnCount = cnMatches.length;/n const enCount = enMatches.length; /n const wordCount = cnCount + enCount - info.exclude;/n /n const postData = {/n slug,/n wordCount,/n ...(matterResult.data as { date: string; title: string })/n };/n return postData;/n }))/n const sortedPostsData = allPostsData.reduce((acc, elems) => {/n if(Array.isArray(elems)) {/n return acc.concat(elems);/n }/n acc.push(elems);/n return acc;/n }, []);/n return sortedPostsData.sort((a, b) => {/n if (a.date < b.date) {/n return 1/n } else {/n return -1/n }/n })/n }))).flat()/n/n return posts/n}/n/nexport async function getPostData(slug:any) {/n/n const idjoin = slug.toString().split(',').join('//').replace(//.html$/, '')/n const id = path.join(idjoin);/n const fullPath = path.join(Directory, `${id}.md`)/n const fileContents = fs.readFileSync(fullPath, 'utf8')/n const matterResult = matter(fileContents)/n/n const processedContent = await remark()/n .use(html, { sanitize: false })/n .use(remarkPrism, { plugins: ['line-numbers'] })/n .process(matterResult.content)/n const contentHtml = processedContent.toString()/n/n const contentCount = await remark()/n .use(html, { sanitize: false })/n .process(matterResult.content)/n/n const contCount = contentCount.toString().replace(/<//?(h/d).*>/g, '');/n const NoImages = contCount.replace(/<img[^>]*>/g, '').trim();/n const NoHtml = NoImages.replace(/<//?[^>]+(>|$)/g, '');/n const cnMatches = NoHtml.match(/[/u4e00-/u9fa5]/g) || [];/n const enMatches = NoHtml.match(/[a-zA-Z]+/g) || []; /n const cnCount = cnMatches.length;/n const enCount = enMatches.length; /n const wordCount = cnCount + enCount - info.exclude;/n console.log(`文章页面字数为:${wordCount}`);/n /n const baseUrl = info.baseURL;/n const imgRegex = /<img.*?src=/'(.*?)/'/g;/n let match: any[];/n const imgUrlArr = [];/n while ((match = imgRegex.exec(contentHtml)) !== null) {/n const imgPath = match[1];/n const imgUrl = `${baseUrl}${imgPath}`;/n imgUrlArr.push(imgUrl);/n }/n const filePath = fullPath;/n const fileStat = fs.statSync(filePath);/n const mtime = fileStat.mtime.toISOString();/n const birthtime = fileStat.birthtime.toISOString();/n console.log(birthtime);/n/n const summary = extractSummary(NoImages, 80);/n const desc = summary.replace(/<//?[^>]+(>|$)/g, '');/n/n return {/n birthtime,/n mtime,/n slug,/n wordCount,/n imgUrlArr,/n summary,/n desc,/n contentHtml,/n ...(matterResult.data as { date: string; title: string; tags: string })/n }/n/n}/n/nfunction extractSummary(content: string, minLength: number): string {/n const filtered = content.replace(/<//?(h/d).*>/g, '');/n /n const paragraphs = filtered.split(/[/n/r]+/);/n let summary = '';/n for (let i = 0; i < paragraphs.length; i++) {/n const newSummaryLength = summary.length + paragraphs[i].length;/n if (newSummaryLength < minLength) {/n summary += paragraphs[i];/n } else {/n/n let j = i;/n while (j < paragraphs.length && summary.length < minLength) {/n summary += paragraphs[j];/n j++;/n }/n break;/n }/n }/n/n return summary.trim();/n}/n/lib/blog.ts/n/n使用 Next.js 13 怎么把 /lib/blog.ts 里的数据输出到 /components/InfoTotal.tsx/nimport { SiteRuntime } from './SiteRuntime';/n/nexport default function InfoTotal() {/n/n return (/n <section className=/'info/'>/n <div className=/'info-fanma/'>/n <h2>导航信息</h2>/n <ul>/n <li><span className=/'l/'></span><span className=/'r/'></span></li>/n <li><span className=/'l/'>收录网站:</span><span className=/'r/'></span></li>/n <SiteRuntime />/n </ul>/n </div>/n </section>/n )/n}/n/n/components/InfoTotal.tsx内容:import { getAllPostIds, getSortedPostsData } from '../lib/blog';/n/nexport default function SiteRuntime() {/n/n const totalPosts = getSortedPostsData();/n const totalTags = getAllPostIds();/n/n return (/n <>/n <li><span className=/'l/'>文章数:</span><span className=/'r/'>{totalPosts.length}</span></li>/n <li><span className=/'l/'>标签数:</span><span className=/'r/'>{totalTags.length}</span></li>/n </>/n )/n}/n/n/n优化后的代码包含以下内容:/n/n* 使用 remark 和 remark-html 解析 Markdown 文件并生成 HTML 内容/n* 使用 remark-prism 高亮代码块/n* 使用 gray-matter 从 Markdown 文件中提取元数据/n* 使用 fs 文件系统模块读取和操作文件/n* 使用 path 模块处理文件路径/n* 统计文章字数和标签数/n* 提取文章摘要并展示/n* 获取文章图片链接/n* 按日期排序文章/n* 将博客数据展示到页面/n/n优化后的代码可以帮助你:/n/n* 更好地理解 Next.js 13 中的数据获取和展示/n* 构建一个功能强大的博客网站/n* 优化博客内容的搜索引擎排名/n* 提高博客网站的用户体验
原文地址: https://www.cveoy.top/t/topic/mYjs 著作权归作者所有。请勿转载和采集!