logo
Published on

搭建一个自己的博客

Authors
  • avatar
    Name
    Muzzik(马赛克)
    Twitter

# 成品

点击体验,由 gitee pages 驱动

# 为什么搭建自己的博客

  • 喷子多,不管理

  • 被删帖,之前发了个把 unity 嵌入 cocos 的帖子后被管理删了

  • 为什么不选择博客园、csdn?广告多,界面不好看

# 选择什么搭建框架?

之前看过了各种框架,中意的有 docusaurusvuepress,最终选择了 vuepress

我的需求

  • 博客:存在分类、标签功能,docusaurus 不符合国人操作习惯,vuepress 存在各种主题,甚至完整的博客插件

  • 文档:两个都没问题,但是 vuepress 更方便配置和加功能

优缺点

  • docusaurus

    • 优点:调试快
    • 缺点:前端 Rect 框架(我不了解),文档缺少翻译,开箱即用的主题几乎没有
  • vuepress

    • 优点:入门简单(了解 ts 就能用),插件丰富,开箱即用的主题多
    • 缺点:调试慢

搭建配置

搜索引擎收录

目前只用到了百度,如果需要其他搜索引擎搜索到自己的网站可以去找下

统计服务

为了方便查看浏览量,用户数,可以使用第三方统计服务

我这里使用了 google analytics,不过统计数据上传没问题,如果是请求数据还是需要梯子

自动构建

使用 github actions,可以直接从 github 同步至 gitee,你只需要上传你的文章,github actions 自动构建并同步至 gitee pages,简直不要太方便

# 迁移文章

由于我没有多平台发布的习惯,而 cocos 论坛的文章一段时间之后就不能编辑了,这更加坚定了搭建自己博客的需求

试过四五个包括 AI 从 html 标签还原为 markdown 格式都不太行,有各种各样的问题

最终自己花了几小时写了段代码从 html 标签转译为 markdown(存在一些小问题),如下,需要的自取

// 帖子链接 url
fetch('https://forum.cocos.org/t/topic/137919', {
  method: 'GET',
  headers: {
    Accept:
      'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.9',
  },
})
  .then((response) => response.text())
  .then((data) => {
    let start_s = `<div class='post' itemprop='articleBody'>`
    let end_s = `<meta itemprop=`
    let start_n = data.indexOf(start_s) + start_s.length
    let html_s = data.slice(start_n, data.lastIndexOf('</div>', data.indexOf(end_s, start_n)))

    html_s = html_s
      // 去除无用标签
      .replace(/\<span class="badge([^(<\/)]+)\<\/span\>/g, '')
      // 转换超链接
      .replace(/(\<a href="([^"]+)"\>)([^\<]+)\<\/a\>/g, function (...args) {
        return `[${args[3]}](${args[2]})`
      })
      // 换行
      .replace(/<br>/g, '\n')
      // <
      .replace(/&lt;/g, '<')
      // >
      .replace(/&gt;/g, '>')

    let convert_string_f = (value_s_: string, connect_b_ = false) => {
      if (!value_s_) {
        return value_s_
      }

      let result_ss: string[] = []

      while (true) {
        let match_result_as = [
          // 0 标题
          value_s_.match(/<h\d>([^]+?)<\/h\d>/),
          // 1 图片
          value_s_.match(
            /<div class="lightbox-wrapper">([^]+?)<img src="([^]+?)"([^]+?)width="([^]+?)" height="([^]+?)"([^>\n]*)/
          ),
          // 2 引用
          value_s_.match(/<blockquote>([^(blockquote)]+)<\/blockquote>/),
          // 3 内容
          value_s_.match(/<p>([^]*?)<\/p>/),
          // 4 选项标题
          value_s_.match(/<li>([^]+?)<ul>/),
          // 5 选项
          value_s_.match(/<li>([^]+?)<\/li>/),
          // 6 代码块
          value_s_.match(/<code([^]+?)>([^]+?)([\n]*)<\/code>/),
          // 7 单代码块
          value_s_.match(/<code>([^]+?)([\n]*)<\/code>/),
          // 8 加粗
          value_s_.match(/<strong>([^]+?)<\/strong>/),
          // 9 下划线
          value_s_.match(/<hr>/),
          // 10 图片
          value_s_.match(/<img src="([^]+?)"([^]+?)width="([^]+?)" height="([^]+?)"([^>]*)/),
        ]

        /** 最接近的下标 */
        let closest_index_n = -1

        // 查找最近数据
        {
          match_result_as.forEach((v, k_n) => {
            if (!v) {
              return
            }

            if (
              closest_index_n === -1 ||
              v.index! < match_result_as[closest_index_n]!.index! ||
              (v.index! === match_result_as[closest_index_n]!.index! &&
                v[0].length < match_result_as[closest_index_n]![0]!.length)
            ) {
              closest_index_n = k_n
            }
          })
        }

        if (closest_index_n === -1) {
          break
        }

        let match_result = match_result_as[closest_index_n]!

        // 链接头
        if (!connect_b_) {
          result_ss.push(value_s_.slice(0, match_result.index!))
        }

        // 更新内容
        value_s_ = value_s_.slice(match_result.index! + match_result[0].length)

        // 转换数据
        switch (closest_index_n) {
          // 标题
          case 0: {
            result_ss.push(
              `${new Array(Number(match_result[0].match(/\d/)![0]))
                .fill('#')
                .join('')} ${match_result[1]}`
            )
            break
          }
          // 图片
          case 1: {
            result_ss.push(`![](${match_result[2]} =${match_result[4]}x${match_result[5]})`)
            break
          }
          // 图片
          case 10: {
            result_ss.push(`![](${match_result[1]} =${match_result[3]}x${match_result[4]})`)
            break
          }
          // 引用
          case 2: {
            result_ss.push(
              match_result[1]
                .replace(/\<\/p\>\<p\>/g, '\n')
                .replace(/(\<p\>)|(\<\/p\>)/g, '')
                .replace(/\n/g, '\n> ')
                .slice(1, -3)
            )
            break
          }
          // 内容
          case 3: {
            result_ss.push(convert_string_f(match_result[1]))
            break
          }
          // 标题
          case 4: {
            result_ss.push(`- ${convert_string_f(match_result[1])}`)
            break
          }
          // 选项标题
          case 5: {
            result_ss.push(`   - ${convert_string_f(match_result[1])}`)
            break
          }
          // 代码块
          case 6: {
            let code_s = match_result[2].replace(
              /<span class="hljs-([^]+?)">([^]+?)<\/span>/g,
              function (...args) {
                return args[2]
              }
            )

            let language_s = match_result[1].match(/class="lang-([^( |")]+)/)?.[1] ?? ''

            result_ss.push(`\`\`\`${language_s}\n${code_s}\n\`\`\``)
            break
          }
          // 单代码块
          case 7: {
            let code_s = match_result[1].replace(
              /<span class="hljs-([^]+?)">([^]+?)<\/span>/g,
              function (...args) {
                return args[2]
              }
            )

            result_ss.push(`\`${code_s}\``)
            break
          }
          // 加粗
          case 8: {
            result_ss.push(`*${convert_string_f(match_result[1])}*`)
            break
          }
          // 下划线
          case 9: {
            result_ss.push(`\n---\n`)
            break
          }
        }
      }

      return result_ss.length === 0 ? value_s_ : result_ss.join(connect_b_ ? '\n' : '')
    }
    html_s = convert_string_f(html_s, true)
    console.log(html_s)
  })