3

nextjs根据动态路由优雅处理目录首页url和无效url

 8 months ago
source link: https://www.daozhao.com/11042.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根据动态路由优雅处理目录首页url和无效url

如果您发现本文排版有问题,可以先点击下面的链接切换至老版进行查看!!!

nextjs根据动态路由优雅处理目录首页url和无效url

前几天写到怎么让nextjs根据动态路由读取指定markdown文件内容,提到了在nextjs项目的app目录下创建一个[...slug],然后在里面的page.js里面实现路由

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
  };
}

这样的话,在访问 example.com/abc 时读取src/markdown里面的abc.md的内容作为结果来渲染,但是实际运行过程发现了两个改进点。

访问目录url

但是当我们将abc作为目录,也就是说可能还有如下url:/abc/a,/abc/b,分别读取的是src/markdown/abc/a.mdsrc/markdown/abc/b.md,我们更希望访问/abc时读取的是src/markdown/abc/index.md,而不一定是src/markdown/abc.md,毕竟把abc相关的内容都放在abc这个文件夹内更加方便管理,此时我们可以将之前的getFileData进行优化。

访问不存在的url时

访问的url不存在,其实可能认为是在对应的src/markdown文件夹内找不到与url匹配的markdown文件,为了避免出现nextjs渲染失败的情况,我们可以直接写入兜底内容作为结果来渲染。 比如提示直接当前url不存在。

完整代码如下:

export async function getFileData(slug, dir = './') {
  const slugList = Array.isArray(slug) ? slug : [slug];
  // 最后一项为文件名,其余是目录名
  const rawId = slugList.pop() || '';
  let id = rawId || 'index'; // 为空时默认为 index
  let dirPath  = dir;
  if (slugList.length > 0) {
    dirPath += slugList.join('/') + '/';
  }
  // dirPath可能以./开头,需要去掉.
  const pathname = dirPath.replace(/^(\.)/, '') + rawId;
  let file = path.join(absPath(dirPath), `${id}.${fileExt}`);
  let stat = await fsp.stat(file).catch(err => {
    console.log('fsp.stat 1~ ', err + '');
  });
  // 尝试将原id作为目录名,读取其index.md
  if (!stat) {
    dirPath = dirPath + '/' + id;
    id = 'index';
    file = path.join(absPath(dirPath), `${id}.${fileExt}`);
  }
  stat = await fsp.stat(file).catch(err => {
    console.log('fsp.stat 2~ ', err + '');
  });
  // 文件不存在直接返回空对象
  if (!stat) {
    return {
      title: '当前URL不存在',
      html: `<section><p>请确认当前页面的URL是否有误</p><p>记录时间:${new Date()}</p></section>`,
    };
  }

  const data = await fsp.readFile(file, 'utf8');
  const matter = fm(data);
  const html = (await parse(matter.body)).toString();
  // date formatting
  const date = matter.attributes.fakeAsUpdateDaily
    ? new Date()
    : (matter.attributes.date || stat.ctime)
  matter.attributes.date = date.toUTCString();
  matter.attributes.dateYMD = dateformat.ymd(date);
  matter.attributes.dateFriendly = dateformat.friendly(date);
  // word count
  const
    roundTo     = 10,
    readPerMin  = 200,
    numFormat   = new Intl.NumberFormat('en'),
    count       = matter.body.replace(/\W/g, ' ').replace(/\s+/g, ' ').split(' ').length,
    words       = Math.ceil(count / roundTo) * roundTo,
    mins        = Math.ceil(count / readPerMin);
  matter.attributes.wordcount = `${ numFormat.format(words) } words, ${ numFormat.format(mins) }-minute read`;
  return {
    pathname,
    id,
    html,
    ...matter.attributes
  };
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK