5

怎么让nextjs根据动态路由读取指定markdown文件内容

 8 months ago
source link: https://www.daozhao.com/11038.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

怎么让nextjs根据动态路由读取指定markdown文件内容

最近用了用nextjs,发现用它建设个小型站点还是很方便的,兼备服务端渲染。 站点架设好之后,后面更多的是写文章,不需要太多的代码改动了,一般来说写写文章,又不用花哨的排版的话,用markdown就很方便了。

使用的是nextjs最新14.x版本+app router模式,

front-matter

为了能让markdown文件如果文章内容部分外,还兼有标题、发布时间、关键词等自定义信息,我们可以借助front-matter

---
title: 测试
description: '测试下描述'
keywords: '关键词'
date: 2023-12-16
---
这里就是内容啦

这里的title等信息就可以在front-matter的帮助下,能程序能直接识别出来了,比如就可以将里面的title内容放在html的title里面了。

front-matter用法如下

import { promises as fsp } from 'fs';
import fm from 'front-matter';

const data = await fsp.readFile('abc.md', 'utf8');
const matter = fm(data);

然后我们就能在matter里面拿到titledescription等信息,md文件的主体内容则在matter.body里面

marked

有时我们在markdown里面可能会写些html,并且有些排版只能依靠html来完成了

import { parse } from 'marked';

const data = await fsp.readFile('abc.md', 'utf8');
const matter = fm(data);
const html = (await parse(matter.body)).toString();

nextjs根据url读取对应的markdown文件

我们创建一个app目录下创建一个[...slug],然后在里面的page.js里面实现路由

file

结合官网的解释,我们其实就可以根据动态路由来读取src/markdown目录下对应.md文件内容了

加上前面提到的front-mattermarkedapp/[...slug]/page.js的完整代码如下

import { promises as fsp } from 'fs';
import path from 'path';
import fm from 'front-matter';
import { parse } from 'marked';

function absPath(dir) {
  return (
    path.isAbsolute(dir) ? dir : path.join(process.cwd(), './src/markdown', dir)
  );
}

async function getFileData(slug, dir = './') {
  const slugList = Array.isArray(slug) ? slug : [slug];
  // 最后一项为文件名,其余是目录名
  const rawId = slugList.pop() || '';
  const id = rawId || 'index'; // 为空时默认为 index
  let dirPath  = dir;
  if (slugList.length > 0) {
    dirPath += slugList.join('/') + '/';
  }
  // dirPath可能以./开头,需要去掉.
  const pathname = dirPath.replace(/^(\.)/, '') + rawId;
  const file = path.join(absPath(dirPath), `${id}.md`);
  const stat = await fsp.stat(file).catch(err => {
    console.log('file not found ~ ', slugList,  err + '');
  });
  // 文件不存在直接返回空
  if (!stat) {
    return;
  }

  const data = await fsp.readFile(file, 'utf8');
  const matter = fm(data);
  const html = (await parse(matter.body)).toString();

  return {
    pathname,
    id,
    html,
    ...matter.attributes
  };
}

export default async function SlugPage({ params }) {
  const data = await getFileData(params.slug);

  if (!data) {
     return (<div>404</div>);
  }

  return (
    <div>
      <div className="app-article">
        <div className="app-article-title">
          <h1>{data.title}</h1>
        </div>
        <section className="app-article-content" dangerouslySetInnerHTML={{
          __html: data.html
        }}></section>
      </div>
    </div>
  )
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK