以下の質問を受けた。

--watch を使うと jekyll build の部分が異常に遅くなるらしい。 初回は遅くないのですが、ファイル変更を検知した時が遅い。

pygments を有効にしていると遅くなるらしい。

--watch を使うとファイルの生成する部分がメインスレッドでないのがあやしい。pygements は popen とかつかって実行されるっぽいし。 とはいえ、原因を特定するまではいけなかった。

仕方ないので無理矢理ごまかす方法を考えた。

以下のような Rakefile を用意してみた。

require 'directory_watcher'
require 'jekyll'

desc 'preview'
task preview: [:watch]  do
  sh 'bundle exec jekyll serve'
end

task :watch do
  options = Jekyll.configuration({})
  source = options['source']
  destination = options['destination']

  dw = DirectoryWatcher.new(source, :glob => Jekyll::Command.globs(source, destination), :pre_load => true)
  dw.interval = 1

  dw.add_observer do |*args|
    t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
    print Jekyll.logger.formatted_topic("Regenerating:") + "#{args.size} files at #{t} "
    sh 'bundle exec jekyll build'
    puts  "...done."
  end
  dw.start
end

ほとんど Jekyll::Commands::Build からもってきた。 ファイルの変更を検知して jekyll build を実行しています。

問題が起きる最小セットをつくってのJekyll 本家に Issue を作成したいと思う。

おまけ

で紹介したのを組み合せるとにこんな感じになります。

require 'bundler/setup'
require 'thread'
require 'launchy'
require 'directory_watcher'
require 'jekyll'

desc 'preview'
task preview: [:watch]  do

  Thread.new do
    sleep 2
    Launchy.open 'http://localhost:4000/'
  end

  sh 'bundle exec jekyll serve'
end

task :watch do
  options = Jekyll.configuration({})
  source = options['source']
  destination = options['destination']

  dw = DirectoryWatcher.new(source, :glob => Jekyll::Command.globs(source, destination), :pre_load => true)
  dw.interval = 1

  dw.add_observer do |*args|
    t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
    print Jekyll.logger.formatted_topic("Regenerating:") + "#{args.size} files at #{t} "
    sh 'bundle exec jekyll build'
    puts  "...done."
  end
  dw.start
end