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.md
和src/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
};
}
- 分类:
- Web前端
相关文章
怎么让nextjs根据动态路由读取指定markdown文件内容
最近用了用nextjs,发现用它建设个小型站点还是很方便的,兼备服务端渲染。 站点架设好之后,后面更多的是写文章,不需要太多的代码改动了,一般来说写写文章,又不用花哨的排版的话,用markdown就 阅读更多…
markdown+NextJS搭建个人博客
如果你平时不喜欢在排版上花时间,不在乎花里胡哨的样式,觉得markdown编辑文件效果就够用?你还想基于markdown搭建一个博客?那NextJS就可以满足你的需求了 NextJS可以使用Reac 阅读更多…
怎么让nextjs根据动态路由读取指定markdown文件内容
最近用了用nextjs,发现用它建设个小型站点还是很方便的,兼备服务端渲染。 站点架设好之后,后面更多的是写文章,不需要太多的代码改动了,一般来说写写文章,又不用花哨的排版的话,用markdown就 阅读更多…
markdown是不会用还是不好用?自研vscode插件来帮忙,甲方运营人员大呼好用
背景 随着使用markdown语法编写内容越来越流行,有的程序员也开始给甲方做网站时使用markdown来编写文章了,比如用hexo博客系统建站。 使用markdown语法能减轻程序员寻找富 阅读更多…
nextjs动态生成sitemap.xml的修改日期
nextjs是可以自行生成网站的 sitemap.xml 的,但是在打包发不到生产环境后,发现写的日期并没有生效,而是当时打包时的日期,百思不得其解。 此前是自定义 src/sitemap.js 阅读更多…
markdown+NextJS搭建个人博客
如果你平时不喜欢在排版上花时间,不在乎花里胡哨的样式,觉得markdown编辑文件效果就够用?你还想基于markdown搭建一个博客?那NextJS就可以满足你的需求了 NextJS可以使用Reac 阅读更多…