个人博客设计

我想要怎样的博客?

从读者角度

好看。
这里的好看更多地是从阅读的角度考虑,而不是审美的角度。我希望我的博客易于阅读,字体、大小、排版、高亮、缩进等是合适的,读者不会因为界面而觉得阅读我的博客是困难的。
此外,打开速度也很关键,除了在网速特别慢时,应当能在两三秒内打开博客。

从作者角度

好写。
写作方便,可以很容易地设置分类、标签,添加图片、视频,容易地进行排版。
上传方便,写好博客后可以容易地上传到服务器。
管理方便,可以容易地增删查改博文,备份、迁移博客。

要如何实现想要的博客

好看

字体、字号、颜色等可参考看上去舒服的网页,看看别人怎么设计的。排版、高亮、缩进等完全由html和css控制,当我看到不满意的地方时去修改即可。至于整体界面的美观,我这个完全不懂设计的人,就只能尽人事,听天命了。

将博客部署在国内(coding的pages服务)、用CDN(七牛云)存储图片等静态资源就可获得相当不错的响应时间。当然这是对国内而言,至于身在国外的朋友,就只好稍稍多等待几秒种了。

好写

  • 博文采用markdown写作,方便排版。
  • 调用七牛云API,自动存储图片、视频等静态资源。
  • 用git管理博客,方便上传、备份、迁移。
  • 标签是动态的,随写随加,不需要提前声明。
  • 分类是树状的,化文件目录树为博文分类树,只需将博文保存在某一目录中便设置好了该博文的分类。
  • 博文地址是可设置的,不随分类、标签的改变而改变。

总体设计

Wblog

为保证访问速度,博客只好部署在国内;避免域名备案,博客只能部署在pages服务中。

因此,我需要的是一个类似Jekyll和hexo这样的静态博客生成工具。Jekyll不能满足我的需求,hexo我没有用过,也暂时不打算去学习如何使用它(听说是hexo是台湾的小伙开发的)。所以我决定自己实现一个,就起名叫Wblog好了。

Wblog的工作是生成静态博客,具体地讲,是将markdown格式的博文渲染为html,处理好分类和标签。

Wmedia

Wblog只负责生成静态博客,不干其他事情。我还需要一个工具来管理图片、视频等静态资源。Wmedia的工作是自动上传静态资源到七牛云,获取外链,并自动替换静态博客中的静态资源链接为七牛云外链。

详细设计

Wblog

Wblog的实现是一个名为wblog.py的Python脚本,其作用是读取博客内容,进行markdown渲染和模板编译,生成静态博客。

准备文件

首先介绍必须的文件、目录:

wblog.conf          //配置文件
index.md            //主页
layouts/            //模板
  -- tag.tpl        //标签
  -- post.tpl       //文章
  -- cate.tpl       //分类
posts/              //博文目录树

非必须的:

static              //存放静态资源文件

运行wblog.py会生成的:

sites/              //生成的静态网站
.compilelog         //记录了渲染编译的历史

博文以makrdown写作,在下文中称为markdown文件,该文件应当以.md结尾。该文件有head部分和body部分。body部分是以markdown语法写作的博客正文,head部分是关于该博客的信息。一个简单的markdown文件如下所示:

---
layout: post.tpl
url : firstmarkdown
title: 我的第一个makrdown文件
date: 2017-06-30
tags: ['置顶', '开始']
---

## HELLO WORLD

这是我的第一个markdown文件,请多多关照。

—和—之间的部分便是head部,该部分是由键值对组成,键是以字母打头,字母或数字组成的词(和通常的编程语言的变量名要求一样),键值之间用:隔开,值可以是字符串、整数、列表等。列表中的字符串必须用引号包围,其余的字符串可以不用引号包围。

wblog.conf文件中也是以:分割的键值对,规则同markdown文件的头部。

工作过程

下面来说说wblog.py的工作过程,如下图所示:

首先,wblog.py读取wblog.conf文件,解析其中的键值对,保存为字典site。

接着,wblog.py会递归遍历posts目录,读其中的markdown文件,解析出它的head和body,将head转换为字典,并添加一些键值,渲染body为html文件,并保存在sites目录中,然后以渲染出的html文件为模板,以head和site为参数,进行编译,用编译结果替换html文件,生成最终html文件。若遇到.html或.htm文件,直接复制到sits目录中,以site为参数进行编译。

head中至少有以下几个键:

  • url 字符串,访问该url可访问该博文
  • size 整数,该博文字数
  • date 日期,该博客的写作日期

若markdown的头部缺少url字段,则会自动生成一个随机数作为该博文的url,并将url写会到makrdown文件中。若markdown的头部缺少date字段,则会以当前日期作为该博客的写作日期,注意date字段不会自动写回。

在遍历posts目录的同时,会在内存中根据posts的目录树构建出一颗分类树,树根的变量名是root_cate,根据markdown文件的头部信息中的tags构建出一个标签列表,列表的变量名是tags。

分类树是一颗树,由嵌套的字典表示,每个分类是一个字典,其键值如下:

  • name 字符串,该分类的名字
  • url 字符串,访问该url可到该分类页面
  • subcate 列表,该分类的子分类,子分类也是字典
  • posts 列表,直接属于该分类的博文列表
  • number 整数,直接属于该分类的博文篇数

标签列表中的每个元素是一个标签,标签也是字典,其键值如下:

  • name 字符串,该标签的名字
  • url 字符串,访问该url可到该标签页面
  • posts 列表,其中成员为post
  • number 整数,该标签下博文篇数

在递归遍历posts目录的同时,会在sites/categories目录中生成和posts目录具有相同结构的目录树。在遍历完posts目录后,内存中已经有了分类树,然后就会遍历sites/categories目录,在这个目录中的每个子目录(包括它自己)中都生成一个index.html文件,这个文件是以layouts/cate.tpl为模板、以目录对应的分类字典和site为参数生成的,用分类的url,可以直接访问这个文件。

接着,wblog.py会读取layouts/tag.tpl,以此作为模板,遍历标签列表,以每一个标签和site为参数编译此模板,生成一些列网页文件,保存在sites/tags目录中,这些网页文件用标签的url可以访问。

之后,还会遍历当前目录,遇到markdwon文件则渲染编译、遇到html或htm文件则只编译,将这些编译结果也保存到sites目录中。

最后,wblog.py会复制static目录到sites目录中。这样,便完成了静态博客生成。

一个问题便是若每次运行都要渲染、编译全部markdown文件岂不是会很慢?确实是这样的,解决方法便是每次渲染、编译后记录该文件的hash值,下次再遇到该文件,根据hash值判断该文件是否改变,若没有改变,则不需要再次处理。

但是存在这样的情况,markdown文件没有改变,渲染、编译结果却是不同的,这是由于wblog.conf或layouts中的模板改变了。因此,一味地跳过没有改变的markdown文件是不合适的。所以,引入参数-a,a的含义的all,若有此参数,则无论markdown文件是否改变,都再重新处理。

模板

模板语言使用django的那一套,灵活,强大。当然主要原因是我对django比较熟悉。

全部模板都可使用的变量有:

  • site
  • tags
  • root_cate

不建议在post.tpl等博文模板中使用tags和root_cate,因为posts未遍历结束,tags和root_cate中信息可能不全。

此外,三个必须的模板中各有一个特殊的变量:

  • tag.tpl tag 字典,当前标签
  • post.tpl post 字典,当前博文
  • cate.tpl cate 字典,当前分类

这几个模板都会被多次使用,每次使用会传入不同的参数,生成不同的结果。

post.tpl是markdown文件默认的模板,也可在head中用layout来指定模板。

另外,在渲染markdown为html后,会用“{% block post %}”和“{% endblock %}”包围html,并在其前添加“{% extends “模板名” %}”。所以,用layout指定的模板中应该包含“{% block post%}{% endblock %}”。

Wmedia

直接将图片这样的静态资源存储在github、coding的仓库中不是不行,但是不好,有更好的方式,即将图片存储在七牛云这样的CDN。

若是手动保存图片至七牛云,则需要经过以下几步:

  1. 打开浏览器
  2. 打开七牛云网站
  3. 登录
  4. 进入存储存储,选择存储空间
  5. 上传图片
  6. 复制外链
  7. 将外链写在.md文件中

除了麻烦外,这样做还有以下三点不足:

  1. 写文章时若需要插入图片,则必须处于联网状态
  2. md文件中写入长长的外链很不美观
  3. 虽然可以备份图片,但图片链接仅仅有指向七牛云中的那一份,缺乏有效备份

所以需要一个工具来自动的上传图片,获取并替换链接。

写作时,在markdown中,图片用

../../static/img/iampic.jpg

来引用,生成的HTML中图片链接也是

../../static/img/iampic.jpg

生成静态博客完毕后,再运行Wmedia,它只作用于sites目录,会遍历sites目录中的所有文件,匹配src中从static/img目录引用资源的链接,上传资源并将链接替换为从七牛云返回的资源外链。

上传文件时调用七牛云API,官方给出了示例代码,很容易实现。关键在于要准确区分哪些文件没有上传过,哪些文件已经上传过,不需要再次上传,哪些文件发生了变化,需要再次上传。

维护一个上传数据库,数据库中记录结构如下:

本地文件路径:hash:url

每上传一个文件,就在该数据库中添加一条记录。
再次运行时,读到一个文件,先在数据库中查找,若找到,则比较hash,若一致,则不用再上传,直接返回url,若不一致,则更新hash,重新上传,更新url。若在数据库中未找不到对应记录,则上传并添加新记录。

虽然名叫做数据库,但实际上用一个文件就可以了。上传信息将保存在文件.update中。

前端设计

其实也谈不上设计了,只是最普通不过的网页布局。顶部是菜单栏,底部是版权声明栏,中间分为左右两部分,左半部分展示博文内容,右半部分是我的头像和友情链接等常驻信息。屏幕较小时隐藏右半部分。

菜单共有以下几个:

  • 主页
  • 分类
  • 标签
  • 归档
  • 微言
  • 读书
  • 关于

一直没想好主页要怎么设计,就干脆把这篇文章作为主页。
分类是一个下拉菜单,其子菜单便是一级子分类。
点击标签菜单可以看到所有标签,按文章数量从高到低排序。
点击归档可以看到所有文章,按发表时间从新到旧排序。
微言和读书以及关于都和以前的博客一样,相当于三个独立页面。

部署使用

安装依赖:

    sudo pip install Django==1.8
    sudo pip install markdown
    sudo pip install Pygments
    sudo pip install qiniu

在coding上创建两个项目,一个私有一个公开。
私有项目用于存放生成前的博客,公开项目用于存放生后的博客。
在公开项目中创建pages,用于博客访问。

在博客主目录中运行git init,并设置其远程仓库为coding上的私有项目。添加.gitignore文件,内容为:

    *~
    sites

忽略临时文件以及生成的静态博客。

在sites目录中运行git init,并设置其远程仓库为coding上的公开项目。添加.gitignore文件,内容为:

    *~
    static/img

忽略临时文件以及static/img中的文件,static/img中的文件是要保存到七牛云这样的CDN上的,
且在私有项目中已有备份,故不再上传。

这样部署,便确保了每一个文件至少在两个不同的地方有备份。若自己本地磁盘上的博客文件损坏,
只需git clone下私有项目即可;若coding上的文件损坏,只需重新git push下即可;
若七牛云中文件损坏,只需删除.update文件重新运行python wmedia.py即可。

修改好博客后,先用命令

  python wblog.py

来生成静态博客。生成完毕后,进入sites目录,运行命令

  python -m SimpleHTTPServer

在浏览器中访问:http://127.0.0.1:8000/,就可以看到本地运行的博客了。

修改满意后,运行命令

    python wblog.py
    python wmedia.py
    git add -A
    git commit -m'自动提交'
    git push
    cd sites
    git add -A
    git commit -m'自动提交'
    git push

来将博客推送到远程仓库。命令有点多,一条一条敲很不方便,故写成一个名为auto.sh的脚本:

  if [ "$#" -ge "1" ]  
  then
      python wblog.py
      python wmedia.py
      git add -A
      git commit -m'自动提交'
      git push
      cd sites
      git add -A
      git commit -m'自动提交'
      git push
  else
      python wblog.py
      cd sites
      python -m SimpleHTTPServer
  fi

当auto.sh没有参数时,执行if的else分支中的命令,有任何参数时,执行if的then分支中的命令。

如果你也想使用Wblog,请联系我:me@werner.wiki

2 Replies to “个人博客设计”

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

2 × 1 =