logo科技微讯

用 Next.js 改写科技微讯博客

作者:科技微讯
日期:2021-10-29
📝 笔记

这篇笔记记录了我用 next.js 重构科技微讯博客时做的零散笔记,重构完成后我写了一篇完整文章到博客:把博客从 GatsbyJS 迁移至 NextJS

  • 按照目前的 posts 目录直接复制到 nextjs 项目,用 nodejs 的 fs 读取目录的每一个 md 文件,根据 md 文件中里的 front matter 确定每一篇文章的 url,而要读取 front matter 的内容,需要借助一个叫 gray-matter 的工具;
  • 拿到 markdown 的位置,并用 fs 读取了 md 文件的内容,得到 md 文本,接着用 remark、remark-html 把它转换为 html 文本。这里需要理解 md 文本是如何转换为 html 文本的:原始文本,通过 parser()转换为 syntax trees,然后用 plugin 处理这些 syntax trees,最后用 compiler 把处理过的内容再转换为文本,整个过程叫做 processors,一个 processor 同时整合了 parser、plugin、compiler,remark 就是一个 processor,remark 有很多 plugin,其中一个就是 remark-html,它可以把 md 转换为 html 格式的文本,remark 还可以用 remark-prism 插件进行代码高亮,
  • nextjs 默认使用 Static Generation,也可以用 Server-side Rendering 或者 Client-side Rendering,SG 和 SSR 都是先生成 HTML 之后返回给用户,而 CSR 返回 js 文件给用户,再由用户的浏览器执行 js 文件最后得到完整的 html 文件,不建议这样,至少对于博客这种以文章为主体的网站最后用 SG 或 SSR,至于用 SG 还是 SSR,还是 SG 和 SSR 结合,根据实际情况使用;
  • 如果是 SG,使用 getStaticProps 这个函数生成页面所需数据,并用 props 的方式传递给本页面,本页面在 SG 时会用这些初始数据渲染出 html 文件,如果 html 文件的路径也需要根据外部数据来定义,则还需要 getStaticPaths;而对于 SSR,用 getServerSideProps 这个函数;
  • nextjs 支持一种叫 Incremental Static Regeneration 的功能,简称 ISR,实现方法是在 getStaticProps 函数返回的对象中增加 revalidate 属性;
  • 科技微讯博客主要页面有 3 个:
    • index.js:根据本地所有文章的 md 文件获得所有文章的标题、日期、链接,SG 在首页;
    • /blog/[slug].js:根据 slug 获取文章的详情,而 slug 的获取方法是 getStaticPaths,getStaticPaths 会把 slugs 数组传递给 getStaticProps,getStaticProps 再根据 slug 获取每一篇文章的数据,最后为每一篇文章 SG 出 html 文件;
    • tools
  • 需要注意,有些 dependency 只能用在服务端,这些 dependency 可以在页面组件 import 进来,但只能在组件的 getStaticProps 等函数内部使用,如果只 import 但不使用也是会出错的,这些 dependency 甚至要注意谨慎写在一个独立的文件中,例如 utils 文件夹中的,因为 nextjs 可能不知道怎么进行 code spliting,我的理解是 utils 里的 js 文件要不只运行在前端,要不只运行在服务端,不要混在一起写在一个文件。
  • 渲染 markdown 里面的图片的方法有几种,如果不使用 next/image 是很简单的,因为我的做法是 md 文件及其用到的图片放在同一个文件夹,所以 md 里用到的图片写的是相对路径,这些图片无法直接访问,需要转移到 public 文件夹才能直接访问,这就需要把 md 文件和它引用的图片分开存放在不同的文件夹中了;另一种方法是把整个 post 文件夹上传到 cdn,然后用 remark-img-links 插件在把 remarkdown 转变为 html 时,自动往图片路径增加 cdn 链接的前缀,其实放在 public 文件夹可能也需要用 remark-img-links 增加前缀;如果我希望在 markdown 中使用 next/image,则需要 react-markdown、markdown-to-jsx;
  • 如果直接渲染图片,不经过其他处理,那怎么调整图片的尺寸呢?基本上需要使用 md 标准之外的语法,然后用第三方插件或者自己写代码从这些非标准的 md 语法提炼出图片的尺寸等信息,这个链接有很多讨论
  • 还是用 next/image 比较好,所以我决定用 react-markdown 或 markdown-to-jsx,因为它们可以使用自定义组件去渲染 md 里的指定元素,讨论。虽然我不用 mdx,但是 mdx 也可以处理普通的 markdown 文档,关于如何 style 图片,vercel 的官方博客有一篇文章
  • next/image 需要提供 width 和 height 参数,如果没有需要提供 layout='fill' 参数,如果设置了 layout='fill' 则需要在 Image 组件增加一个 div 作为父组件,并给 div 设置 position: relative 以及提供长宽,否则图片位置会显示错误,通常设置了 layout='fill' 还需要设置 objectFit="contain" 等。由于 fill 效果不好,所以我在 getStaticProps 里获取了当前文章的所有图片的尺寸,把信息传递给页面组件动态设置图片大小,md 文件使用 next-mdx-remote 去渲染 markdown,next-mdx-remote 内置 MDXProvider 功能,可以用自定义组件更换 html 标签,把图片的尺寸传入这个自定义组件就可以动态设置图片尺寸。
  • 可能是由于 nextjs 的图片不支持 static generation,所以图片加载速度可能比不上 gatsby,为了让图片加载时看起来更快一些,有必要在图片加载完成前先失一张很小尺寸的 placeholder,这个功能可以用 placeholder 实现;
  • 对 markdown 进行 style 可以用 remark plugin,使用 next-mdx-remote 对 md 进行 serialize 时传入 plugin 参数即可,因为我用 remark-prism 这个 plugin,所以配置好之后,还需要到 prism 的官网下载定制的 css 文件,import 进 _app 即可,具体看这里
  • 对其他内容进行 style,用 tailwindcss,它的使用方法在文档说得很清楚了;
  • url 的 trailing slash;
  • 如果直接 import 图片,即所谓的 static import,拿到的图片 src 自动加上 hash 字符,同时自动生成 blurDataURL,有 hash 就可以把图片的 cache 设置为永久,有 blurDataURL 就不需要 placeholder 这个工具了,所以最好还是能 static import。如果不是通过 import 进来的,需要设置图片的缓存有效期。

tailwindcss 使用注意事项:

  • 在 nextjs 导入 tailwind css 的方式有两种,其中在 global.css 中导入的方是是 @import 而不是 @tailwind;
  • before 和 after 需要在 jit 模式下使用;
  • jit 模式可以在 tailwind 配置文件开启,开启后就不再需要在配置文件配置 variants 了,所有 pseudo class 可以直接用于所有 plugin;
donation赞赏
thumbsup0
thumbsdown0
暂无评论