又再把Blog搬家了

Reading time ~7 minutes

一直把Blog當作紀錄一些事情用的地方, 想法, 或是學習過的一些東西, 雖然不是很頻繁的在寫, 不過也寫了好幾年了, 從以前到現在, 換過好幾次平台, 從自己架的wordpress, 到posterous, blogger, 一直到現在用的Tumblr, 這中間最喜歡的還是posterous, 不過它已經不存在了, 而Tumblr也用了好一陣子了, 雖然加減湊合著用好像還OK, 不過編輯上也一直不是那麼順手, 尤其是貼source code, 因此也一直想把它換掉

medium 呢? medium我還沒很有動力去搞懂它, 會在上面看一些文章沒錯, 但把Blog移到上面去, 好像也沒啥動力

考慮了好一陣子, 不過最後還是把整個Blog遷移了, 反正現在有一個自己的domain (blog.jln.co), 搬家不用改地址!

遷移之前, 想了幾個我的需求:

需求

  1. 有方便的編輯器可以用, 最好可以支援mark down, 打html有點麻煩, WYSIWYG編輯器通常效率也不高
  2. 貼code好貼, 也方便閱讀
  3. 模版好編輯, 至少我要能知道怎麼改模版
  4. 好預覽
  5. 能同步到各個social network, 至少Facebook, Twitter, 也能同步到我原本的Tumblr和blogger
  6. 要能夠友善支援Open graph和Twitter card, 對每次share的FB的醜醜文字版型實在不喜歡
  7. 好轉移, 好備份, 有版本控制更好!

解決方案

現成的blog service, 好的什麼都要錢(ghost, wordpress), 免費的大概也都被我用過了, 自己架, 又得管server, 後來想想, blog都是靜態的網頁, 也真的不需要一個很複雜的系統, 這時候就想到一個解決方案, 那就是Github

Github有一個Github pages的服務, 可以讓你host你的靜態網頁, 所以只要有一個方法可以把Blog轉成靜態網頁就可以了, 這個還蠻Geek的方式感覺就蠻適合我的

找到了幾個方法轉blog:

  1. Jekyll
  2. Octopress
  3. Hexo

Octopress是已經完結不再維護了, 所以就Jekyll和Hexo兩個在抉擇, 兩者都有蠻多的主題跟模版功能, 也有不少plugins

Hexo是台灣精品, 而且是nodekjs寫的, 語言上我比較熟, 要改比較好改,而Jekyll是Ruby寫的, 我跟Ruby很不熟, 但它跟Github pages結合緊密, 而且已經有tool可以從Tumblr移轉內容過來了, 最後我選擇了Jekyll, 選擇Jekyll的原因是

  1. Github page直接原生支援, 只要把md檔push上去後, 就會自動產生網頁(不過後來我還是先在自己電腦產生完再push, 後面再說原因)
  2. 找到一個適合的也不太難改的theme, 就懶得去翻Hexo的了, 而且找到的那個對Open graph和Twitter card的支援也不錯, 不用改太多
  3. 原生的Tumblr import tool

不過整個也花了不少個晚上修改, 又花了一個晚上才能寫完這篇紀錄 @@

安裝Jekyll

網路上可以找到很多安裝Jekyll的文章, 這邊就不說太多, 我試了兩個不同的作法:

作法 1

這是最基本的作法

  1. 先用 gem install jekyll 安裝jekyll
  2. jekyll new myblog 在myblog目錄產生一個基本的網站
  3. jekyll s 會在 localhost:4000 開啟一個服務, 這時就透過browser可以看看你的blog長怎樣了

這方法的缺點是, 套用主題時, 還得改一堆東西, 有點麻煩

作法 2
  1. 一樣先裝jekyll
  2. 找到一個人家做好的theme (我是用hpstr這個), clone下來改, 因為大部分的都已經把他用的plugin之類的都先寫好在config了, 就省不少事, 建議找theme要注意其對應的Jekyll版本, 像我裝的Jekyll是3, 所以找的是適合3的
  3. gem install bundler 安裝bundler
  4. bundle install 來安裝相關的plugins
  5. jekyll s 看結果

我後來採用的是作法2, 踩在人家的肩膀上比較快 :P

設定github pages

這部份沒什麼難度, 創建一個專案名稱叫做 你的名字.github.com , 把相關檔案放到這邊去就行了

Github pages支援兩種方式, 一種是純粹的靜態網頁, 就是把html跟其他相關檔案丟到這邊就好(master branch), 另一種方式就是Jekyll, Jekyll的部分只要把前一個動作的檔案放進來就好, 它會自己幫你產生對應的靜態網頁

不過第二種方法的缺點是因為Github pages只支援幾種Jekyll plugins, 而且不支援自訂的plugins(放在 _plugins 目錄下的), 就算你在你自己電腦裡面跑完把產生後的 _site 目錄一起放上去也是沒用的

從Tumblr匯入之前文章

這部份沒太複雜, 是透過jekyll-import

安裝jekyll-import一樣可以透過gem install來安裝, 但建議不要這樣做, 是因為他用的Tumblr API是JSONP但程式卻將它當一般JSON在解碼, 會出錯, 這部份在最新版的code有解決(害我還去追了source code), 所以抓source回來自己build比較安全

裝好之後執行:

#!/bin/sh
ruby -rubygems -e 'require "jekyll-import";
    JekyllImport::Importers::Tumblr.run({
      "url"            => "http://blog.jln.co",
      "format"         => "html", # or "md"
      "grab_images"    => true,  # whether to download images as well.
      "add_highlights" => false,  # whether to wrap code blocks (indented 4 spaces) in a Liquid "highlight" tag
      "rewrite_urls"   => false   # whether to write pages that redirect from the old Tumblr paths to the new Jekyll paths
    })'

它就會把文章抓回到 _post的目錄下

Open graph & Twitter card

如果把內容分享到Facebook或是Twitter上只有短短的文字, 不是很好看, 所以希望在這部份能夠至少加上一張圖

hpstr這個theme已經有在 ** _includes/head.html ** 寫好OG跟Twitter card相關的tag了, 圖片(og:image)的部分, 他的規則/順序是:

  1. Front matter 裡面設定的
  2. _config.xml 裡的logo設定

我希望是更自動一點, 而不是自己去設定, 所以找到一個plugin : jekyll-auto-image, 這個plugin聰明一點, 他的順序是:

  1. 內文內出現的第一張圖
  2. _config.xml 裡面設定的圖

但這樣還稍嫌單調一些, 我想要達成的是:

  1. 內文內出現的第一張圖
  2. 根據標籤選的對應的圖(比如說把我go語言相關的設成Gopher的圖片), 這樣不會每個都一樣, 比較有變化一點
  3. 預設的圖

再加上auto image裡面關於image的設定跟我用的theme有所衝突, 這就需要把原本的auto image改一下了

我新增一個rb檔, 放在 ** _plugins **目錄下, 內容如下:

require "jekyll"

module Jekyll

  class AutoImageGenerator < Generator

    def generate(site)
      @site = site

      site.pages.each do |page|
        img = get_image(page)
        page.data['image1'] = img if img
      end
      # Now do the same with posts
      site.posts.docs.each do |post|
        #puts "hola"
        #puts Jekyll::VERSION
        #puts post.class
        #puts post.inspect
        #puts post.data.inspect
        #puts "-----"      
        #puts post.output
        #puts "----"
        img = get_image(post)
        post.data['thumb'] = img if img
      end
    end # generate

    def get_image(page)

      if page.data['thumb']
        return page.data['thumb']
      end
      # convert the contents to html, and extract the first <img src="" apearance
      # I know, it's not efficient, but rather easy to implement :)

      if page.class == Jekyll::Document # for jekyll 3.0 posts & collections
        htmled = Jekyll::Renderer.new(@site, page, @site.site_payload).convert(page.content)
      else
        htmled = page.transform # for jekyll 2.x pages
      end

      img_url = htmled.match(/<img.*\ssrc=[\"\']([\S.]+)[\"\']/i)
      return img_url[1] if img_url != nil

      tags = page.data['tags']
      imagemap = @site.config['imagemap']
      if tags != nil && imagemap != nil
        tags.each do |t|
          if imagemap[t.downcase] != nil
            url = imagemap[t.downcase]

            if !url.match(/^http/)
              url = '/images/' + url
            end
            return url
          end
        end
      end

      return @site.config['logo'] if @site.config['logo'] != nil
      return nil
    end

  end # class
end # module

這版就有達到我想要的目的, 但這不代表問題解了, 反而是問題的開始, 前面有說過github只支援特定的plugins, 所以怎樣這段改過的plugin都不會被它執行到, 唯一能做的解法就是改用靜態網頁的方式

jekyll產生的靜態網頁都放在 _site 目錄下, 所以真的要進master branch只有這裡面的, 其他都不用, 所以要先在本地端用 jekyll b去產生相關的靜態網頁到 _site裡再上傳

那怎測試呢? 一開始為了測試方便我都以本地端的server做測試, 但如果要測試Facebook share的話則需要能夠讓Facebook 連過來抓取網頁來分析, 但這點在區網不是很方便, 所以就帶入了 ngrok 這個工具, 這工具就是提供給你一個外部的網址, 你在本地端跑了ngrok這程式後, 就有一個可以對應你本地端的server, 還蠻好用的

自動發布到社群網站

這當然是用ifttt囉, 因為有用到jekyll-feed這個plugin, 所以會產生一個feed.xml的檔案, 所以就利用ifttt的feed channel來設定觸發

結語

本來明明不想花太多功夫的, 結果不但花了很多功夫, 還花了一頁來紀錄這篇 orz