Blog

从Hexo到Nuxt

2022-06-09

#前端
#NuxtJS
#Hexo

自从2018年我重新建立这个博客以来,建站所使用的程序一直都是 Hexo,所以为什么要从 Hexo 跑路?一切都要从半年前的一个晚上,我打开当时使用的主题的官网发现我使用的那个版本的文档已经消失说起……

准备

首先新建一个 Nuxt3 的项目,然后把所有 MarkDown 文件和图片给下载回来,其他东西就直接不要了。从此Hexo再见。

技术栈

NuxtJS

在这以前大半年前我还尝试过用 NEXT.js 以及 Gatsby 这些基于 React 的框架来写,感觉没达到想要的效果,那时候 Nuxt3 还停留在测试,于是就一直摆烂……既然 React 写得不爽那就用回熟悉的技术栈 Vue,感觉果然好多了,写自己喜欢的玩意还得是用熟悉的工具。Nuxt 这玩意也有基于文件目录来生成的路由,很方便。

tailwindcss

遇到这种原子化的框架其实一开始我是拒绝的,写了多年组件化框架的我心里实在没底,但想到这博客实际上也没多少页面应该不会很麻烦,抱着试一试的想法来用,结果效果不错,也没想象中麻烦。

变动

我不擅长布局和配色,所以目前大伙能见到的页面都是有原型的,比如博客整体的原型是 giuem大佬的博客,不少从他那借鉴来的思路就不展开了,可以阅读他的文章;友链的部分又是从 material you 的实现中借鉴来的……我在这些原型的基础上又加上了一些自己的想法,混在一起就成了目前这个样子了。

只做了一些微小的工作

  • 暗色模式,旧主题的暗色模式只能用稀烂来形容,对眼睛友好那是不可能的,还好 tailwindcss 处理暗色模式并不难,只要堆class就行
    高下立判

    高下立判

  • <h>标签,为了去除掉下划线,我覆写了所有 h 标签的样式,顺便用上了 Element.scrollIntoView() 解决点了不动的问题
  • rsssitemapsitemap 这个简单,因为 content 官网给了能直接抄的 demo,而 rss 就找个 jstoxml 的库顺着 sitemap 的代码 /server/routes/sitemap.xml.ts 照葫芦画瓢就是了
    import {serverQueryContent} from '#content/server'
    import jstoxml, {XmlElement} from 'jstoxml'
    const {toXML} = jstoxml
    
    import metaData from "assets/meta/meta"
    import {getPubDate} from "~/share/Time";
    export default defineEventHandler(async (event) => {
      //generate content
      //Thu, 14 Apr 2022 09:32:52 GMT
      const rssContent: XmlElement = {
        _name: 'rss',
        _attrs: {
          'xmlns:atom': 'http://www.w3.org/2005/Atom',
          'xmlns:content': 'http://purl.org/rss/1.0/modules/content/',
          version: '2.0'
        },
        _content: {
          channel: [
            {title: metaData.name},//其实就是网站名字 MANKAのblog
            {link: metaData.site_url},//这个很好理解吧,域名
            {
              _name: 'atom:link',
              _attrs: {href: '/rss.xml', rel: 'self', type: 'application/rss+xml'}
            },
            {description: metaData.description},//这个就是简介了,我用的是四年前写的那句话,也是我一直以来做博客的想法
            {pubDate: getPubDate()},
            {generator: 'https://blog.nest.moe'},
          ]
        }
      }
      // get all posts
      const data = await serverQueryContent(event).only(['date', 'title', '_path', 'date', 'description']).sort({date: -1}).find()
      data.filter(x => x.date).forEach(postMeta => {
        // @ts-ignore
        //这里不ignore会爆红 TS2339: Property 'channel' does not exist on type 'unknown',但是内容可控时这个问题其实不是很严重,可以未来再修
        rssContent._content.channel.push({
          item: [
            {title: postMeta.title},
            {link: metaData.site_url + postMeta._path},
            {guid: metaData.site_url + postMeta._path},
            {pubDate: getPubDate(postMeta.date)},
            {description: postMeta.description},
            {comments: metaData.site_url + postMeta._path + '#comment'},
          ]
        })
      })
      event.res.setHeader('Content-Type', 'application/xml;charset=UTF-8')
      event.res.end(toXML(rssContent, {
        header: true,
        indent: '  '
      }))
    })
    
  • error.vue 写跳转路由。由于 middleware 运行顺序比错误处理要慢,所以到 middleware 的时候早就跳到错误页了于是只好从错误页开始处理,但我会之间替换掉现有公开的链接,因此这玩意凑合着能用就行,在未来这种跳转会消失都不奇怪
  • 第3次踩进Safari处理时间的坑
    //正确的
    new Date("2022-06-10 00:00:00.000".replaceAll('-', '/'))
    //错误的
    new Date("2022-06-10 00:00:00.000")//Safari不认 `yyyy-mm-dd` 这种用横杠划分的格式
    
  • 花了点时间了解了一下 Open Graph,参考 如何让你的hexo博客拥有分享卡片 写了一些meta信息到 <head>

未来

这玩意当然是有需要的时候再加组件啦,毕竟现在已经全部可控了

  • 图片 lazyload,虽然 我觉得没必要,本来就没几张图还要大费周折去搞这玩意属实是过度优化,目前网站躲在CloudFlare的CDN背后这一点就让这点优化变得微不足道, 浏览器自带一个 loading属性,于是直接在图片标签上面加就行,浏览器不支持?问题不大,我的博文一般都没图。
    <img loading="lazy" ...>
    
  • 合并图片和文章内容,文章和图片在一个文件夹里面才合理
  • 处理初次加载时暗色模式闪屏,毕竟页面是靠ssr提前渲染的,渲染那时是不会有暗色的, 虽然SSR渲染时确实没有暗色,但可以给最顶层的 <div> 加上动画
    <div class="transition duration-150" ...>
    
  • 支持在文章中添加草稿标记(draft: 1),将不会渲染草稿的内容

2024-01-10 补充:

一年半过去,全部坑都填上了,写得太乱,应该不会开源了


评论区