尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Octopress静态博客实战:从WordPress迁移到高效写作的完整指南

Octopress静态博客实战:从WordPress迁移到高效写作的完整指南 凌晨一点半我刚把一篇三千字的长文从剪贴板粘进 WordPress 后台正要点击发布页面忽然变成一片空白——数据库连接错误。那一瞬间我真想把电脑从窗口扔出去。三年积累的两百多篇帖子、几百条评论全躺在 MySQL 里而我连备份都好久没做了。那是压垮我的最后一根稻草。从那天开始我花了整整一个周末研究静态博客方案最后落在了 Octopress 上。这个决定我至今不后悔。Octopress 不是一个全新的博客引擎它是构建在 Jekyll 之上的一套博客专用框架。Jekyll 本身就可以把 Markdown 和模板渲染成纯静态的 HTML 文件但默认的博客功能比较简陋对只想安安静静写文章、不想折腾前端的人仍有门槛。Octopress 把这些东西全部封装好了一键创建文章、内置响应式主题、代码高亮、评论区接入、部署脚本开箱即用。对当时的我来说它最大的价值是把我从维护服务器重新拉回到写文章这件事上。现在回头看这个选择不只是换了个发布工具更像是换了一种写作和生活的节奏。这篇文章我就把这几年用 Octopress 攒下的实操经验完整过一遍包括环境搭建、发布链路、主题定制以及那些网上几乎没人写明白的坑。1. 为什么会从 WordPress 折腾到 Octopress一个静态博客框架的定位1.1 静态博客到底解决了我的哪些真实痛点很多人一听说静态博客就觉得是倒退——没有后台、没有数据库、没有可视化编辑器写个东西还要开终端敲命令图什么我承认这个质疑有道理但前提是你没被 WordPress 的数据库折腾过。我当时遇到的是 MySQL 连接数被打满整个站白屏登录后台也进不去。问题是有一百种理由会让数据库挂掉恶意扫描、插件冲突、内存不足、日志文件撑爆磁盘。每一次我都要花一两个小时去排查而我只想做一件事——写文章。Octopress 这类静态方案把网站压缩成了一堆 HTML、CSS、JS 文件。没有数据库可以挂没有后台可以被人爆破没有 PHP 进程可以去执行恶意代码。内容全部以 Markdown 源文件存着分布式环境的部署也简单因为浏览器到服务器之间除了静态文件什么都没有。还有一个常被忽略的好处是版本控制。WordPress 时代一篇文章改完就没了谁在哪个版本改过、改了什么全凭记忆。而在 Octopress 里整个博客就是一个 Git 仓库一篇文章就是一个带日期的 Markdown 文件。改了哪个段落用git diff看得一清二楚写错了想回滚一条git revert解决。这种把博客当代码管的体验一旦习惯了就回不去。1.2 Octopress 和 Jekyll 的关系半成品与成品准确地说Octopress 是 Jekyll 的上层建筑。Jekyll 提供了最核心的渲染能力读取_posts目录下的 Markdown 文件套上模板输出成_site目录里的静态页面。但它刻意保持克制只做博客之外的最基础的事像分页、分类页、标签页、上一篇下一篇、RSS 订阅这些博客刚需都要你自己写插件或者从第三方代码里抄。Octopress 把这些全部补齐了还额外做了几件很关键的事。一是默认内置了响应式主题2013 年那会儿手机端访问体验还不是标配Octopress 开箱就是自适应布局省了我大量前端工作。二是封装了大量 rake 命令什么rake new_post、rake generate、rake deploy把创建文章→渲染→部署这条流水线变成了一条命令的事。三是把代码高亮、Disqus 评论、Google Analytics 统计这类博客标配功能都做成了傻瓜式开关改几个配置文件就能启用。打个不太恰当的比方Jekyll 是一台装好发动机的裸车能开但只有两个座位Octopress 给这台车装好了自动挡、空调和导航拉到目的地就能直接用。这也是为什么当年我跳到 Octopress 之后几乎没遇到什么学习成本。1.3 什么人适合继续用 Octopress必须承认Octopress 的黄金年代是 2012 到 2016 年后来被 Hexo、Hugo 抢了不少风头。但如果你满足下面几个条件它依然是个好选择你本身对 Git 和命令行不排斥愿意用编辑器写 Markdown。你要发布的地方主要是 GitHub Pages 或自己的 Linux 服务器不需要后台界面。你希望博客完全归你掌控不想把内容和数据托管在某个封闭平台上。你不需要一个团队协作编辑后台就自己一个人写。反过来如果你需要带账号体系的评论、可视化图片管理、多人权限协作或者你压根不想碰终端那 Octopress 不适合你老老实实继续用 WordPress 或者托管在专门的内容平台上更省心。2. 环境搭建Ruby、依赖和那些 README 里不会写的事2.1 先解决 Ruby 版本这个第一大坑Octopress 2.0 当年要求 Ruby 1.9.2 以上而它底下的 Jekyll 1.x 对 Ruby 版本又特别挑剔。我踩过的最典型的一个坑是系统自带 Ruby 2.6结果rake install一路报错一会儿是jekyll依赖找不到一会儿是json这个 gem 编译不过去。问题的根源在于 Octopress 2.0 用的 Jekyll 版本是 1.x这个版本是在 Ruby 2.4 之前写的用了一堆在新版 Ruby 里被移出标准库的组件。最省事的办法是不要和系统 Ruby 纠缠直接用版本管理工具装一个独立的 Ruby 1.9.3 或 2.0.0然后再在这个环境里装 Octopress。我当时的做法是用 rbenv用 RVM 也行看你习惯# 安装 rbenv 和 ruby-build 之后 rbenv install 2.0.0-p648 mkdir octopress cd octopress rbenv local 2.0.0-p648 gem install bundler注意rbenv local这一步很重要它会在当前目录生成一个.ruby-version文件让这个项目的所有命令都强制使用指定版本。不然你在这个目录里敲ruby、rake用的还是系统默认版本前面全都白弄。2.2 Gemfile 和 bundle install 的正确姿势下载 Octopress 源码之后当时是git clone git://github.com/imathis/octopress.git第一件事不是rake install而是先装 bundler 依赖bundle install这里有个很多人第一次跑会懵的点整个项目里既有 Gemfile又有rake install这个命令到底先跑哪个我当时的经验是先跑bundle install再跑rake install。因为rake install会用到不少依赖插件比如 RDiscount、Pygments如果 gem 环境是空的跑一半必然报错。如果网络状况不好bundle install可能卡在从默认源拉取这一环节。我当时在服务器上装的时候把 Gemfile 里的source换成了国内镜像源速度会快很多source https://gems.ruby-china.com说完别忘了一件事bundle install跑完会生成Gemfile.lock把这个文件一并提交到 Git 仓库。等哪天你换电脑重新bundle install它就能按照 lock 文件精确还原当初的依赖版本不会出现这次装出来和上次行为不一样的玄学问题。2.3 目录结构哪些是源码、哪些是产物我刚开始用 Octopress 时对目录结构的理解一团浆糊导致后来几次部署错目录。这里直接说结论source/是真正的源码目录你的 Markdown 文章、模板、图片、JS、CSS 都在这下面。public/是生成目录rake generate之后会在这里产出完整的静态网页文件。_deploy/是部署目录rake deploy会把public/里的内容复制到这里然后以这个目录为基准提交 Git。sass/是主题样式源码目录Octopress 用 Sass 预处理器改样式改这里改完它会编译成public/stylesheets/下的 CSS。plugins/放自定义 Ruby 插件Octopress 在这个目录下用了一些自定义的 Jekyll 插件方法。理解这个结构特别关键。很多人改了一晚上的样式打开浏览器发现没变化就是因为改了public/里的 CSS结果rake generate一跑又被sass/编译出来的东西覆盖了。记住一句话手工不碰public/它是生成产物。3. 写作到发布一套我用得最顺手的完整工作流3.1 创建文章的两种方式以及我给新手的建议Octopress 提供了一个很贴心的 rake 任务来创建文章rake new_post[一篇关于静态博客的文章]执行之后它会在source/_posts/下生成一个带时间戳的 Markdown 文件命名格式大概是2019-05-20-yi-pian-guan-yu-jing-tai-bo-ke-de-wen-zhang.markdown而且文件里已经帮你写好了 YAML Front Matter--- layout: post title: 一篇关于静态博客的文章 date: 2019-05-20 12:00:00 0800 comments: true categories: tags: ---也有另一种做法是手动建文件文件名按YYYY-MM-DD-slug.markdown的规则命名然后在文件顶部自己写这段 Front Matter。我给你的建议是前期先用 rake 命令生成因为文件名里的日期格式一旦错了Jekyll 就不会把它当文章解析而是当成普通文件原样拷贝到 public 里页面上什么都看不到还找不到原因。等用熟了再改成手动创建也不迟。注意 zsh 用户有个坑rake new_post[xxx]里的方括号会被 zsh 当成通配符解释命令可能直接报错。解决方法是给整个参数加引号转义或者临时用 bash 执行。3.2 本地预览和草稿写长文才不慌写文章的过程里我会一直开着本地预览。Octopress 给的命令是rake preview这个命令会把 Jekyll 跑起来并启动一个本地服务默认地址是http://localhost:4000。好处是它会监听文件变化你保存一次 Markdown浏览器刷新一次就能看到效果不必反复手动生成。后来我写长文比如万字以上那种时发现了一个小技巧暂时不想发布的文章不要把日期设成当天直接设成未来日期。Jekyll 默认不会渲染未来日期的文章本地预览时它不会出现在列表里但也不会报错。等你想发布了把日期改成当天重新rake preview就能看到它正常上架。这个用日期控制发布状态的思路比加各种 draft 标志要简单直接。还有个体验上的心得rake preview和rake generate不要同时开它们会同时往public/写文件偶尔会出现文件锁冲突导致预览页面空白。我自己就因为这个在排查上浪费过半小时。3.3 从生成到上线部署这步千万别搞混分支Octopress 的部署逻辑是它最顺手也最容易搞晕的部分。它的默认模式是用 Git 的两个分支来办公代码和文章源码在source分支部署生成的静态文件在master分支。GitHub Pages 默认发布master分支所以对用户来说访问到的始终是master分支的内容。如果你用的是 GitHub Pages第一次部署前要跑rake setup_github_pages它会问你仓库地址然后把_deploy/目录初始化成master分支的 Git 仓库。之后再更新就是一套固定动作rake generate # 重新生成静态文件 rake deploy # 将 public/ 的内容复制到 _deploy/ 并推送这里我强烈建议你把这两条合成一条用 Octopress 自带的rake gen_deploy。它等于先generate再deploy简化了操作也避免了你只 generate 忘记部署、或者只部署没重新生成的情况。如果你用的是自己的服务器而不是 GitHub Pages其实很简单把public/目录用 rsync 推送到服务器的 Nginx 或 Apache 站点目录就行。我当时在云主机上用的是rsync -avz --delete public/ useryour-server:/var/www/blog/--delete很重要它会把服务器上已经不存在于本地的旧文件删掉保证服务器和本地生成的完全一致不然你会发现很多已废弃的页面还在线上诈尸。3.4 评论、统计和图床第三方服务的接法静态博客没有数据库评论这种动态功能自然接不了原生方案当时最省事的办法就是接 Disqus。在_config.yml里填上你的 Disqus 短名称再确认文章 Front Matter 里comments: true评论功能就上线了。后来国内访问 Disqus 不稳定我换成了网易云跟帖再后来又换成了自己搭的基于 LeanCloud 的方案。这属于看环境选方案的问题不变的原则是尽量让第三方服务保持解耦万一哪天换了平台别让评论数据跟着文章一起被绑架。统计这块更简单Google Analytics 的跟踪 ID 填进_config.yml的google_analytics_tracking_id字段部署完刷新页面去 GA 后台看实时访客就能确认是否生效。图片处理是静态博客最头疼的一环。我的做法是单独建一个图床仓库或者用对象存储服务图片上传后得到 URL然后在文章里直接引用绝对地址。为什么不把图放在source/images/下因为图片会白白占用博客仓库的体积而且如果你经常换主题或者换部署方式仓库臃肿会让每次生成和部署都变慢。图藏在一堆代码里也不好管理。4. 主题定制从默认皮肤改成自己的风格4.1 动手改样式前先搞清楚主题文件在哪Octopress 默认主题叫 Classic Theme它的模板文件分散在source/_includes/、source/_layouts/和source/_plugins/里。这里有个新手最容易绕晕的点Octopress 的样式文件不是直接写 CSS而是放在根目录的sass/目录下通过 Sass 编译成public/stylesheets/screen.css。打开sass/你就能看到一套分层的结构最常用的是sass/custom/下的几个文件_colors.scss集中定义颜色变量比如 $main_color、$sidebar_bg。_fonts.scss集中定义字体变量和使用规则。_styles.scss覆盖默认样式的最终入口优先级最高。这套设计其实就是变量集中管理 最终覆盖的思路。你不需要动 Octopress 底层的默认样式文件只需要在_styles.scss里写几行覆盖规则就能把默认主题改成自己的风格而且升级主题时也不会冲突。4.2 换字体、换配色、改布局的实操路径我当年给博客做过一次比较大的视觉改版核心动作就三个。先换字体。Octopress 默认字体栈里有 Georgia 和 font-family 的相互搭配我改成了更耐看的衬线方案。改法是在_fonts.scss里重新定义 $sans-serif 和 $serif 变量然后在_styles.scss里把 body 的 font-family 覆盖成想要的组合。如果你想用中文字体建议在_config.yml里额外引入 Google Fonts 或者其他 CDN 的字体文件要注意的是外部字体加载会拖慢首屏我只做了按需加载而不是全站替换。再换配色。当时我想把默认的白底黑字改成暖黄色护眼风格只需要在_colors.scss里改几个变量比如把 $page_bg 从 #fff 改成 #fcf9f1把主链接颜色从默认的蓝色改成暗红色。改完后重新rake generate刷新浏览器就能看到效果。这些变量名的具体含义你可以在 sass 目录里查每个文件顶部都有注释。最后是布局。默认主题是左侧内容区、右侧侧边栏的布局我想把侧边栏放到左边。这个改起来相对费劲需要动source/_includes/里 HTML 结构的顺序再调整sass/里的浮动方向。我的经验是改布局之前先备份并且在本地预览环境里反复测试不同屏幕宽度下的表现不然很容易出现桌面端正常、手机端错乱的情况。4.3 插件扩展能力边界在哪里Octopress 的灵活性很大一部分来自它建立在 Jekyll 的插件机制上。Jekyll 支持三类 Ruby 插件生成器Generator、过滤器Filter和标签Tag。Octopress 2.0 自带了不少实用插件比如include_code标签可以把外部代码文件嵌入文章里显示避免文章里直接贴大段代码导致维护困难。我记忆比较深的一个自定义需求是相关文章推荐。Octopress 没有内置这个功能我的做法是写一个简单的 Jekyll Generator 插件在生成站点时遍历每篇文章的 tags 和 categories计算相似度然后把相关文章列表注入到模板里。这个插件的核心逻辑不复杂关键是理解 Jekyll 的site.posts在生成阶段已经把所有文章对象加载好了你只是在这个集合上做处理。不过我要提醒你注意插件兼容性的问题。Octopress 2.0 自带的插件是围绕 Jekyll 1.x 写的如果你之后把 Jekyll 升级到 2.x 甚至 3.x有些插件会直接失效。我的原则是**能用配置解决的就写进_config.yml能用模板解决的就在_includes里加 HTML实在躲不开才写插件。**每少写一个插件就少一份升级时的痛。5. 上线之后我踩过的五个坑附完整排查链路5.1 坑一部署成功但线上看不到新文章现象很诡异本地预览新文章一切正常rake gen_deploy也提示推送成功但打开线上博客列表里就是没有那篇文章。排查链路是这样的我先看本地public/里有没有这篇文章对应的 HTML 文件——有。再看_deploy/里有没有——没有。这说明rake deploy在复制文件时出了问题。再细看_deploy/目录我发现里面全是老的静态文件时间戳是上一次部署的。问题出在_deploy/这个 git 仓库里Octopress 的 deploy 脚本会把public/内容强制推送到_deploy/的 Git 里但如果_deploy/里还有未提交的旧文件、或者本地 git 状态异常推送就会被跳过。解决方法是进到_deploy/目录手动看 git 状态cd _deploy git status如果发现有大量modified或untracked文件堆积先git add -A git commit -m sync再回根目录重跑rake deploy。后来我养成了习惯每次部署前先检查_deploy/的 git 状态干净了再部署基本不会再栽在这个坑里。5.2 坑二本地样式正常线上样式全乱这个坑的排查过程让我印象极深。本地打开localhost:4000页面美观整齐部署到 GitHub Pages 之后CSS 完全没有生效所有文字挤在一起像 HTML 初学者的作业。第一反应是想是不是 CSS 文件没有上传。我用浏览器开发者工具打开 Network 面板发现screen.css请求返回 404。再看请求的 URL是http://myusername.github.io/repo-name/stylesheets/screen.css而不是http://myusername.github.io/stylesheets/screen.css。问题一下就清楚了我在 GitHub Pages 上把博客放在了一个仓库子路径下但_config.yml里的url和root配置没有同步更新。Octopress 在配置里有两个关键字段url: http://myusername.github.io root: /repo-name我当时的root是空的rake generate生成的所有资源链接都变成了绝对路径的根目录形式放到子路径下自然全部 404。把root改成仓库名之后重新生成部署瞬间恢复。这个教训也让我养成了一个习惯换部署位置时第一件事同步url和root而不是只找一个页面看效果。5.3 坑三标签页和存档页 404用了一段时间我发现博客里点Tags标签链接跳出来的页面是 404。一开始我以为是路径写错了实际上 Octopress 的标签和分类页不是默认就有的需要对应的页面模板文件存在于source/目录下。Octopress 典型的结构里分类页面是在source/blog/categories/下维护一个index.html标签页面则在source/blog/tags/下。如果你在自定义结构时误删了这些目录或者把文章的 categories 写成了一个不合法的值生成的链接就会指向不存在的页面。排查方式也很直接先用一条命令列出所有文章里用了哪些分类和标签grep -h categories: source/_posts/*.markdown | sort | uniq -c看看有没有你预期之外的分类名。然后再到source/blog/目录下核对页面模板是否存在。我当时就是有一篇文章把 categories 写成了英文的复数形式还在多处写了大小写不一致的标签导致页面模板匹配不上统一成小写之后问题就消失了。5.4 坑四rake 命令莫名其妙的报错有段时间我每次跑rake generate都会在末尾蹦出一堆warning: already initialized constant的提示。看着吓人但生成结果其实是好的。后来才知道这是 Ruby 自带的告警信息因为在 Octopress 的代码里有些常量被多次定义的写法在旧版 Ruby 下没有告警新版 Ruby 会提示但不影响运行。真正要注意的是另一种报错uninitialized constant Rake::DSL。这个一般是 Rake 版本装太高导致的兼容性问题。Octopress 2.0 依赖的 Rake 版本比较老如果你用gem install rake装到了 11.x 以上Octopress 的 Rakefile 就可能会运行失败。解决方法是把 Rake 版本降回来在 Gemfile 里固定一个可用版本我当时用的 10.4.2再bundle install。这里也再次说明Gemfile.lock的重要性它不仅能锁住依赖版本也能让你在别的机器上快速复现一个可用环境而不是考记忆力去猜当初装的是哪个版本。5.5 坑五代码块里的特殊符号变成乱码我写技术文章离不开代码块有段时间经常发现代码里的符号显示异常或者后面的内容直接被当作 HTML 标签吞掉了。原因是 Jekyll 的 Markdown 解析器我当时用的是 RDiscount在某些版本里默认会处理内嵌 HTML如果代码块里的内容被当成 HTML 片段解析一切就乱了。Octopress 推荐用围栏式代码块但 RDiscount 对围栏式代码块的支持需要配置开启不然它依然会把四个空格缩进的代码块当作普通段落的一部分。我的处理方式很朴素代码块一律用 Octopress 推荐的语法带语言标注的围栏并且避开这类字符被误解析的情况改用 HTML 实体写法。如果你用的是 Octopress 2.0检查一下_config.yml里有没有markdown: rdiscount的配置项换成markdown: kramdown也是一个稳定方案新一代解析器对围栏代码块的支持更完整。换完之后一定要重新rake generate再验证所有文章特别是老文章里的代码块不要默认没问题。6. 长期维护的备份、迁移与延续之道6.1 一套我坚持了三年的双备份方案静态博客看起来安全但没有数据库不等于内容不会丢。一次误删、一次磁盘损坏、一次脑袋不清醒的git push -f都可能让文章一夜蒸发。我自己定过一个规矩代码和内容在三个不同地方各存一份。第一份是 Git 远程仓库。每个源文件、每篇文章、每次修改记录都在。这里有两点要做到一是提交信息不要偷懒写成更新了配置这种没有信息的消息三个月后你自己都看不懂当时改了什么二是重要分支要加保护避免误覆盖。第二份是对象存储服务。我每周末手动把整个博客目录打成一个 tar 包传到对象存储的私有桶里。这个过程可以写成一个简单脚本用 crontab 定时跑但核心是别想当然地以为每周同步一次就够还要定期做一次恢复演练。我见过太多人备份是备份了真到要用时才发现备份包是坏的。第三份是本地移动硬盘。这个纯粹是防最坏情况比如服务器被清空、云账号被封、电脑突然进水。三个月同步一次即可频率不用太高但一定要有。等到真出事你会发现这三份备份里总有一份能救你。6.2 换电脑后的重建清单我换过三次电脑每次重建 Octopress 环境流程已经固化成了这几步装好 Git、rbenv或 RVM、对应版本的 Ruby。git clone博客仓库到本地。按前面的方式锁定 Ruby 版本跑bundle install。rake preview确认本地能正常渲染。检查_config.yml里的url、root、Disqus 配置和第三方统计代码。随机抽两三篇老文章确认代码块、图片、标签页正常再往下走。这里最容易漏的是第 5 步。换电脑后一切都正常但评论、统计不生效的案例多半是忘了重新配置第三方服务的关联信息。另外如果你之前用_deploy/目录部署那么 clone 下来的仓库默认只包含source分支_deploy需要单独 clone or 重建。要留意部署分支的状态别部署到一半发现本地根本没有_deploy这个目录。6.3 什么时候该考虑迁移以及迁移的建议Octopress 到今天已经不是一个活跃维护的项目了。Jekyll 本身还在迭代但 Octopress 2.0 停在当年的版本3.0 又没有延续之前的影响力。如果你发现身边的人都在用 Hugo 或 Hexo新主题都要自己移植写新特性找不到参考那确实该考虑迁移了。迁移的路径比想象中要平滑。Octopress 的文章就是带 YAML Front Matter 的 Markdown 文件这套结构是 Jekyll 生态通用的。迁移到一个新的 Jekyll 主题文章基本不用改只需要重新搞一遍模板和配置迁移到 Hexo文章主体内容也能直接用只需要把 Front Matter 里的字段名做一次批量映射。我的建议是不要为了迁移而迁移。静态博客的变化速率本来就慢如果你的写作流程已经稳定运行功能没有大的缺失继续用 Octopress 完全没有问题。它就像一辆老旧但保养良好的车加速不快但从来没把你扔在半路上。等到哪天你发现自己花在博客框架上的时间超过花在写作上的时间了那才是真正该考虑换工具的节点而不是因为新东西听起来酷就动刀。最后分享一个我实际操作中的体会博客最重要的永远是内容本身框架的价值是让你在写作和折腾工具之间维持一个健康的比例。Octopress 教会我的不是它那套 rake 命令而是静态网站的工作流思维——所有东西都是文件所有操作都可以被追踪所有流程都可以自动化。这套思维方式后来我迁移到其他静态站生成器、甚至写技术文档和自动化脚本时一直都在用而且越用越顺手。
返回列表