Hello Blog!

为什么要弄blog

因为看到一些很漂亮的博客,就想着自己也用hexo搭起来。

在这里,整理自己过去在工作和学习中积累下来的笔记,有项目经验,有开发技术,有工具的使用细节;有读书笔记的类型,有肤浅的体会,有网络检索后没有轻易解决的宝贵经验。

“一切美,都是努力不断的更新。”

  • 目前的系统环境是win10,通过vmware搭建了一个ubuntu16.04的开发环境(顺便学习《鸟哥的linux私房菜》)。
  • 常用编辑器是WebStorm和Sublime Text3
  • VSCode最棒了!rua!rua!rua!

认识hexo

  • hexo是呆湾少年Tommy Chen的作品,其安装照着官网来非常容易,右上角还有语言切换很方便,本文不做赘述。
  • 使用上也就很简单:
    1. 通过hexo init [floder]命令就可以很简单的把项目的文件结构建立起来;
    2. 通过hexo new [layout] <filename>可以建立新的文章;
    3. config.yml对配置做修改,主要可以修改blog的说明和将代码部署到git仓库的参数;
    4. 通过hexo s命令在本地运行服务,进行开发;增加--debug选项可以开启调试模式,如果出错可以在控制台获得更多的信息提示
    5. hexo g -d编译并且按照config.yml的配置发布。增加参数--watch之后,只要对posts文件夹下的文件做出修改并保存,就会实时调用这个命令,直到通过ctrl + c来停止监听。

一些hexo命令的解释

  1. 命令hexo g会在pulic目录下建立以日期命名的文件夹,类似这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ├── 2017
    │   └── 09
    │   ├── 21
    │   │   └── Hello-my-blog
    │   │   └── index.html
    │   └── 23
    │   ├── Hello1
    │   │   └── index.html
    │   └── Hello2
    │   └── index.html
  2. 默认情况下,草稿文件夹_drafts下的文件不会被展示,其变动也不会被监听——不论是草稿的创建还是修改。这就是草稿和正文的区别,直到调用了hexo publish [layout] <filename>命令将它发布。未免歧义,举个例子:hexo publish "关于hash的那些事"

  3. 这里有一个关于hexo g的坑:文件的冗余。
    1. 如上tree图,在23日,发布了文章Hello1。如果之后,比如说24日,对其再做编辑,hexo g [--watch]命令会在24日文件夹下生成新的Hello1,23日的Hello1就会成为冗余的旧文件。
    2. 这个时候,hexo clean命令就派上用场了。当博客的内容越来越多,而作者的习惯又不是太好,不喜欢使用”草稿“功能,而是直接编辑正文的话,这个命令可以帮助清理public下的文件。

hexo的部署发布

  1. 想要使用hexo g -d自动部署,需要先安装插件npm install hexo-deployer-git --save
  2. 然后在_config.yml文件里添加配置:

    1
    2
    3
    4
    5
    deploy:
    type: git
    repo: <repository url> # https://bitbucket.org/JohnSmith/johnsmith.bitbucket.io
    branch: [branch] # published
    message: [message]
  3. hexo g -d的时候发生了什么:

    1. 如果是项目第一次执行,则hexo在根目录下,新建一个.deploy_git文件夹,然后把编译的代码放在里面,并将它设置为一个Git仓库。
    2. 在hexo根目录的.gitignore文件里我们会注意到这个文件夹也是被hexo项目的Git忽略的。
    3. 这个Git仓库完全根据hexo根目录下_config.yml里的配置,message作为commit的message(如不设置,会有默认值,主要反应commit的时间),随后该Git仓库会向设定的repobranch分支去推送。
    4. 如果在本机上没有对git做全局的user设置,部署的时候会提醒要给.deploy_git里的仓库设置user.name和user.email。
  4. 那么怎么通过Git管理hexo项目比较合理呢?

    1. 官方文档里说:“一个推荐的方式是把master作为写作分支,另外使用public分支作为部署分支。”估计很多新手对此感到有点迷茫。
    2. 这个建议旨在告诉我们,我们可以仅仅用一个仓库的2个分支,同时管理部署和写作。但这听起来很不错的建议里,其实有一些细节需要特别注意:首次建立了blog并且推送到远程仓库后,如果在别处从远程仓库拉取了写作分支,(比如在另一台电脑上),写作结束后想顺手部署,想着设置都是正常的,就直接运行了hexo g -d会发现hexo又生成了一个.deploy文件夹。根据_config.yml推送到同一个远程仓库的同一个分之后,你会发现原来的部署分支整个被替换掉了…之前的部署分支的commit全部消失(其实就相当于删掉了原来的远程分支)
    3. 这是因为Git通过.git文件夹存放了对当前仓库的管理,hexo在部署中,如果检测到.deploy_git文件夹里有Git仓库了,就对其做一个提交;如果没有检测到就会新建一个Git仓库(如果你已经设置了global的user.name和user.email,hexo不会给你提醒,你就会忽略这一点),而这个Git仓库的当前分支,会被推送到远程仓库的部署分支上,对其进行一次彻底的覆盖。
    4. 其实部署和写作,完全可以算两个项目了。我们可以简单的用一个仓库一个分支管理hexo项目,而在_congfig.yml里配置部署到另外一个仓库另一个分支。分开管理并不会有什么问题,部署分支并不太需要版本控制,只控制写作分支完全足以保证对项目的维护。而且,鸡蛋装在2个篮子里也是一件好事。
    5. 如果你就是想用、或者只能用一个仓库管理、或者无论如何就是想要维护部署分支并保留其Git提交记录*,以下给出一个从零开始的(适合强迫症患者的)Git管理建议:

      1. 新建一个hexo项目,将其git仓库化,并设置好远程仓库origin
      2. chekout一个write分支(分支名字都随便起)作为写作使用
      3. _config.yml里配置,deploy指向同一个远程仓库,分支名为deploy
      4. 在别处新拉项目时,可以直接拉写作分支git clone -b edit [url]
      5. 然后再拉取部署分支,这里要这么做git clone -b deploy [url] .deploy这样就能吧部署分支放到.deploy文件夹里。如果回到之前的环境工作,也只需要注意更新edit分支就可以了。hexo g -d执行时,.deploy_git会自动跟进,就像一个普通的Git仓库那样工作。
      6. 再次强调:其实hexo只需要关注edit分支就可以了,hexo新建的时候,会准备好.gitignore文件,你不需要多余的操心。网络上很多文章,维护自己的hexo项目居然是以部署分支为核心,实属买椟还珠。如果你没有强迫症想要保留部署分支的提交记录,在别处新拉项目的时候你完全可以忽略上面的步骤。(第5步)
      7. 初次推送部署的项目里,.deploy_git里的git config是:

        1
        2
        branch.master.remote=git@github.com:username/username.github.io.git
        branch.master.merge=refs/heads/master
      8. 而在别处拉取新项目后,拉deploy分支到.deploy_git里,其git config是:

        1
        2
        3
        4
        remote.origin.url=git@github.com:username/username.github.io.git
        remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
        branch.master.remote=origin
        branch.master.merge=refs/heads/master
      9. 注意以上差别,所以为了保留对部署分支的提交,你还需要更改初次推送部署的.deploy_git仓库的git config。否则他的每一次推送都是forced update,会抹除其他新拉项目对部署的推送——从设计上默认的这一点也可以看出,只用一个仓库、或者说执着于部署分支的提交保留并不是作者的出发点。

    6. 如果使用个人帐号的GitHub Pages来展示blog,需要注意的点如下:
      1. 个人GitHub Pages只能关联master分支(GitHub的规则),所以上面的部署分支必须命名为master
      2. 远程仓库会将被推送的第一个分支展示为默选分支,但还是可以到Settings->Branches->Default branch去修改,这一条也是写给强迫症的。
      3. 最后,GitHub Pages只是一个单纯的前端静态服务器,功能有限,只适合初阶使用。

hexo server热加载问题

根据Hexo官网的说明,hexo server命令可以监视文件变动并且自动刷新,但在实际的使用当中,我很遗憾地发现这个功能是存在问题的,总需要手动刷新才能生效。这就很难受了。

这可能是因为我的系统不是Mac环境:根据一些前人的经验,hexo-fs模块负责了文件系统,其依赖chokidar(一个监视文件系统的类库),又依赖fsevents去实现OS X上对文件系统事件的监听——那么linux和windows系统自然是走远了。

  1. 使用meta标签:每隔20秒自动刷新一次……pass。

    1
    <meta http-equiv="refresh" content="20">
  2. hexo-browsersync

    1. 官网插件页里的hexo-browsersync,根据介绍,在编辑后,保存动作就会触发更新。
    2. 结果发现:这个插件只有在你停留在blog首页的时候才会触发更新。进入具体的页面去编辑的的时候,还是只有手动刷新能看到改动——要你何用?!
  3. 浏览器插件livereload

    • 又尝试了一下浏览器的插件,这个插件需要同时在浏览器和编辑器里设置(以Sublime Text3为例)。
      1. 在浏览器插件设置里,勾选“允许访问文件网址”;
      2. 打开Sublime之后,ctrl+shift+p输入livereload去手动开启功能。
        初步的使用结果是需要连续保存 2 次才能触发网页的自动更新……这也太蛋疼了,F5逃过一劫,CTRL和S的命又短了,当然,不用先焦点浏览器再F5,勉强算一个进步?这可不行。
    • 虽然如此,我注意到这个插件确实地实现了自动刷新。既然已经出现了“需要第二次保存才能刷新出第一次保存的改动”的情况,那就表明机制是ok的,只是项目本身的更新(毕竟hexo s展示的并不是源md文件,而是有一个编译动作)延迟于编辑器里对页面的更新。
    • 在网络上搜索livereload相关,基本很少涉及这个问题,大部分都是简单抛出在浏览器里的安装和在sublime里的安装、启动以及配置。就像这样:

      1
      2
      3
      4
      5
      6
      {
      "enabled_plugins": [
      "SimpleReloadPlugin",
      "SimpleRefresh"
      ]
      }
    • livereload本身是有着”with delay(400ms)”的模式的。开启这个模式,在配置文件中修改为:

      1
      2
      3
      4
      5
      {
      "enabled_plugins": [
      "SimpleReloadPluginDelay"
      ]
      }

      bingo~!成功实现热更新。需要注意的是,如果你修改了配置文件比如_config.yml,还是需要重新运行hexo s的。

  4. hexo本身就没有使用webpack来配置。这里留个期待,希望将来可以改造一下hexo的项目架构。


一些编写的细节

  1. yaml语言,和json的语法略有区别,他有“约定大于配置”的思想,比如:
    • 配置里的冒号后面需要一个空格,否则容易报错
    • 缩进表示示层级,在标签或者分类的写法里,-符号和名名称之间,必须有一个空格。
  2. 图片引用:

    • 我认为最好的方式就是图片放cdn,直接引url。还可以借助一些hexo插件,让图片上传cdn更加快捷(图片放项目里,deploy的时候自动上传cdn)
    • 图片少的时候直接放项目里也可以

      1. hexo的_config.yml里设置post_asset_folder: true,效果是通过hexo new新建文章的时候,会在同路径下建一个同名文件夹。这里的资源都可以直接在文章里引用(不需要路径)如果不改这个设置仅仅是手动增加文件夹,是不能正常显示的;而这个选项一开,不管是new还是publish,都会自动生成一个文件夹。
      2. 图片不推荐![This is an image](image.jpg),而推荐使用标签语法,这样在首页也能正确解析出来:

        1
        {% asset_img image.jpg This is an image %}
  3. 对自己站内文章的引用:

    1
    {% post_link 文章文件名(不含文件类型) 站位字符(可选) %}
  4. 使用markdown来绘制流程图:

    • 首先要明白,流程图的特征是什么?
      1. 圆形:开始、结束
      2. 矩形:普通环节
      3. 菱形:问题判定
      4. 平行四边形:输入输出
      5. 箭头:工作流方向
    • 其次,hexo并不默认支持显示流程图和序列图,需要安装插件hexo-filter-sequencehexo-filter-flowchart
    • 目前存在这样的bug:单独使用sequence是无效的,根本无法显示出序列图。但是!如果在sequence同时来一个flow——序列图就出现了!所以截止目前,在这个blog里这是一个坑:同一个md文档里,必须有一个flow图,其他sequenc图才能显现出来。
  5. markdown表格的写法

    • 注意,显示有问题的时候,检查下表格整体的缩进,一般没必要缩进。
    • 表头不可以省略,表头下的代码用于标示此列内容的对齐方式。
    • hexo对表格的支持实在不咋地,在列表里放表格更是一种灾难,实在不行可以考虑:

      1
      2
      3
      {% raw %}
      被包裹的 html table
      {% endraw %}
  6. 优化提交:保持更新的话每日都有git操作,推荐增加shell脚本或使用git-gui来节省操作。

  7. 在编写内容的时候,列表和标题应该按需使用,能美化排版
  8. 一个hexo的解析问题:在shell脚本里经常出现的左花括号加井号,在hexo里是会产生歧义的,因此写shell相关文章的时候,需要把这种符号写进三个反引号表示的代码块里,才不会出问题。否则就可能面对Template render error: (unknown path)之类完全找不到报错地方的提示。

    1
    2
    # 在shell里经常出现{#
    # 但是在hexo的解析器看来 {# ... #} 表示注释,所以会导致解析错误

引入theme(next)

  1. 增加next主题——fork了主题的仓库,使用git submodule的形式引入自己的hexo项目。如果仅仅按照主题的安装建议直接git clone,并不会是太好的实践:)虽然git submodule会很复杂,但是仅仅引入一个主题而已的话,并不会太难。在《Git看这篇》里,我补充了相关的内容。
  2. next6以后使用了新的项目地址
  3. next文档按着这个做了简单的配置。配置文件写的还是很清楚的,文档缺少的说明也能自己看懂。
  4. next没有zh-Hans.yml,可以考虑直接复制zh-CN.yml并且改名。

使用插件

hexo-symbols-count-time

  1. 一个字数统计+阅读时间估算插件,插件地址
  2. 在hexo里安装npm install hexo-symbols-count-time --save
  3. 在hexo的_config.yml里增加配置:

    1
    2
    3
    4
    5
    6
    7
    8
    # Extensions
    ## Plugins: https://hexo.io/plugins/
    symbols_count_time:
    symbols: true
    time: true
    total_symbols: true
    total_time: true
    exclude_codeblock: false
  4. 确认next里的_config.yml里有配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # Post wordcount display settings
    # Dependencies: https://github.com/theme-next/hexo-symbols-count-time
    symbols_count_time:
    separated_meta: true
    item_text_post: true
    item_text_total: false
    awl: 2 # 汉语写作推荐
    wpm: 300 # 汉语写作推荐
    suffix: mins.
  5. 注意:想要插件生效,一定要运行一次hexo clean


想要一个怎样的blog

blog里有不少TODO: 和 FIXME: 这些标记能让我更容易补充或者修改内容

blog是一种形式,也是一种态度;是一种鞭策,也是一种坚持;是自我的满足,也是慷慨的分享;是自豪的积累,也是抛砖引玉的谦卑。

我希望我的blog不仅仅是个人经验的整理,更能成为让人一看就懂,一看就有收获的分享。自己写完东西后,还会时不时的回来修订;在写的过程中,努力做到在每一段落之前,用简明扼要的语言抓住重点,辅以必要的样例;内容上既要有切实可行的操作,也要有自己踩了坑带来的小机智。

写在最后,也是写在一开始。