CUBE SUGAR CONTAINER

技術系のこと書きます。

python-livereload で Re:VIEW の執筆を捗らせてみる

普段、Sphinx でドキュメントを書くときは sphinx-autobuild というツールを使っている。 このツールを使うと、編集している内容をブラウザからリアルタイムで確認できるようになる。

blog.amedama.jp

今回は、上記のような環境が Re:VIEW でも欲しくて python-livereload というパッケージで実現してみた。 ちなみに、python-livereload は、前述した sphinx-autobuild が内部的に使っているパッケージの一つ。 利点としては、ブラウザ側に livereload 系のプラグインを入れる必要がない点が挙げられる。 これは、Web サーバの機能の中で livereload に使うスクリプトを HTML に動的に挿入することで実現している。

使った環境は次の通り。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G103
$ python -V          
Python 3.7.4

もくじ

Re:VIEW の原稿を用意する

まずは Re:VIEW の環境を用意しておく。 詳しくは以下のエントリを参照のこと。

blog.amedama.jp

python-livereload をインストールする

続いて python-livereload をインストールする。

$ pip install livereload

インストールすると livereload コマンドが使えるようになる。 基本的な機能であれば、このコマンドで完結することもある。

$ livereload --help
usage: livereload [-h] [--host HOST] [-p PORT] [-t TARGET] [-w WAIT]
                  [-o OPEN_URL_DELAY] [-d]
                  [directory]

Start a `livereload` server

positional arguments:
  directory             Directory to serve files from

optional arguments:
  -h, --help            show this help message and exit
  --host HOST           Hostname to run `livereload` server on
  -p PORT, --port PORT  Port to run `livereload` server on
  -t TARGET, --target TARGET
                        File or directory to watch for changes
  -w WAIT, --wait WAIT  Time delay in seconds before reloading
  -o OPEN_URL_DELAY, --open-url-delay OPEN_URL_DELAY
                        If set, triggers browser opening <D> seconds after
                        starting
  -d, --debug           Enable Tornado pretty logging

今回は、監視対象のファイルを指定する部分がちょっと複雑になったのでスクリプトから使うことにした。

監視・ビルド用のスクリプトを用意する

続いては python-livereload を使うスクリプトを用意する。 これは、ファイルを監視して、変更があったときはビルドを実行するというもの。

以下のようなスクリプトを用意した。 HTML の入ったディレクトリ以外を監視して、変更があったら rake web を実行するというもの。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os

from livereload import Server
from livereload import shell


def main():
    # livereload が Web サーバでホストするパス
    serve_path = 'webroot'
    # HTML をビルドするコマンド
    build_func = shell('rake web')
    # 監視対象のファイルパス
    watch_targets = ['*', '*/*']

    # パスがないときはあらかじめビルドしておく
    if not os.path.exists(serve_path):
        build_func()

    # 監視を開始する
    server = Server()
    for watch_target in watch_targets:
        server.watch(filepath=watch_target,
                     ignore=lambda path: path == serve_path,
                     func=build_func)
    server.serve(root=serve_path,
                 open_url_delay=1)


if __name__ == '__main__':
    main()

用意したスクリプトを実行すると、Web サーバが立ち上がって自動的にブラウザを開く。 監視対象の何らかのファイルを変更すると、ドキュメントがビルドされ直してブラウザがリロードされる。

$ python autobuild.py
[I 191009 00:17:14 server:296] Serving on http://127.0.0.1:5500
[W 191009 00:17:14 server:304] Use `open_url_delay` instead of `open_url`
[I 191009 00:17:14 handlers:62] Start watching changes
[I 191009 00:17:14 handlers:64] Start detecting changes
[I 191009 00:17:20 handlers:135] Browser Connected: http://127.0.0.1:5500/

ばっちり。

Rake のタスクにする

スクリプトとして実行するのでも良いんだけど、Rake のタスクにしておいた方が使うとき便利かもしれない。

次の通り Rake の設定ファイルを用意する。

$ cat << 'EOF' > lib/tasks/autobuild.rake 
require 'rake'

desc 'watch the directory and build if any files changed'
task :autobuild do
  sh('python autobuild.py')
end
EOF

これで rake autobuild するとスクリプトが実行されるようになる。

$ rake autobuild

捗りそうだ。

補足

本当は Ruby で完結させたくて、最初はその道を模索した。 ただ、ブラウザのプラグインを必要としない livereload 系の実装が Ruby には見当たらなくて。 加えて、Ruby に不慣れということもあって不本意ながら Python が混ざることになってしまった。 けどまあ、手間をほとんどかけずに実現できたのは良かったかな。