アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

Redmine テーマのつくりかた

December 17, 2018イベントRedmine, Theme

本記事は Redmine Advent Calendar 2018 の 17 日目です。Redmine テーマ開発について書きます。

Redmine テーマとは?

Redmine を機能拡張する方法としてプラグインとテーマが提供されている。

プラグインは Redmine の API や DB を直に参照・操作可能なので高度な用途に向く。テーマは CSS と画像、JavaScript など Web フロントエンド技術のみで開発され、外観の変更や Web ブラウザーで可能な範囲の簡単なカスタマイズを担当する。

プラグインは高度な機能拡張を可能とする反面、開発の難易度も高い。バグや Redmine 本体との互換問題が起きるとシステムそのものが動作しなくなる危険性もある。そのため上級者向きといえよう。エンド ユーザーとして利用するにしても慎重な管理を要求される。

テーマの機能は Web ブラウザーの範疇に限定されるものの、プラグインに比べて開発の難易度は低い。バグや互換性の問題が起きたとしても Redmine の外観が崩れるぐらいで済む。プラグインほど気負わず開発・利用可能なため、カジュアルに Redmine 拡張を試したい向きにもオススメ。

かくいう私も以下のテーマを開発している。

本記事では私の経験や知見を踏まえた Redmine テーマ開発手法をとりあげる。

Starter Kit

テーマ開発の説明にあたり Starter Kit を用意した。README に従ってセットアップすればテーマ開発環境を構築できる。

以降の内容は Starter Kit プロジェクトを AtomVisual Studio Code に開いた状態でお読みいただくと理解しやすいはず。

Redmine テーマ構成ファイル

Redmine テーマを構成するファイルについて。

特別なフォルダーはルート直下の stylesheets/ が CSS 用、javascripts/ は JavaScript 用。それぞれ以下の固定ファイルを配置する。テーマとしては最低限 application.css があればよい。その他は必要なら定義。

ファイル 役割
application.css Redmine の外観を定義する CSS。
responsive.css Redmine の表示された Web ブラウザー表示幅が一定量を下回った際の外観を定義する CSS。
theme.js Web ブラウザー機能の範疇で動的な処理を実行するための JavaScript。

画像などがあれば適宜、追加してゆく。その際の構成はテーマのフォルダー内で完結すること。Redmine 標準テーマだと画像は images/ に配置して CSS からは ../images/add.png という感じの相対パスで参照している。

CSS

CSS を開発する方法は主に

  1. 標準テーマ CSS を自作テーマ CSS の先頭に @import して必要なスタイルを上書き
  2. 標準テーマ CSS を自作テーマにコピーして編集

となるだろう。方法 1 は可動している Redmine の標準テーマ CSS を

@import url(../../../stylesheets/application.css);

/* 以下に必要なスタイルを上書き */

のように取り込むため、上書き部分の量や構成にもよるが壊れにくい。問題が起きたら上書き部分を削除すれば標準へ戻せる。標準テーマとの差分が少なくて @import のパフォーマンス問題を許容できるならオススメ。

方法 2 は 1 の @import なし版。パフォーマンスが気になるとか、標準に対して大胆に改造する場合によい。

Sass (SCSS)

CSS 開発において直に編集してもよいが AltCSS を利用すると便利だ。AltCSS は CSS を拡張したメタ言語。CSS 標準にない機能や記法を利用しながら編集して CSS に変換する。今回は最も普及しているであろう Sass の SCSS 記法を採用。ファイルの拡張子は *.scss としておく。

Sass は様々なプログラミング言語用のパッケージを提供しているが、今回は Web フロントエンド開発でよく使われる Node.js 版を選択。Node.js で利用するライブラリーやツールは npm 形式で配布されており Sass は node-sass - npm になる。

Starter Kit の CSS/SCSS ファイル関連は以下のように構成。

.
└── src/
    ├── assets/
    │   ├── images/
    │   └── stylesheets/
    │        ├── application.css
    │        └── responsive.css
    └── scss/
        ├── App.scss
        ├── Responsive.scss
        └── default/
            ├── application.css
            └── responsive.css

それぞれのフォルダーについて解説する。

フォルダー 役割
src/ 開発者が編集する CSS やソース コードなどを格納。
src/assets/ 開発時にテーマとして解釈されるフォルダー。後述するローカル HTML を配置したり Docker コンテナ上の Redmine からテーマ フォルダーとして参照される場所。
src/assets/images/ テーマの画像ファイル置き場。
src/assets/stylesheets/ テーマの CSS ファイル置き場。SCSS から変換されたものの出力先。
scss/ SCSS ファイル置き場。App.scssapplication.cssResponsive.scssresponsive.css に変換される。
scss/default/ Redmine 標準 CSS 置き場。これらは SCSS ファイルから参照される。

Sass の提供する便利機能のうち、特に便利なのが @import によるファイル参照と結合。前述のように CSS 標準の @import は対象を動的に参照するため、CSS ファイルとして別れていてもダウンロードを並列化できずパフォーマンスを損なう可能性がある。

Sass の @import はコンパイル時に参照を解決するため、出力された CSS ではファイル間が @import した順番で結合された状態となる。これを前提として Redmine 標準 CSS を取り込むとか、SCSS ファイルが肥大化してきたら別ファイルに分割して後から結合といった運用を実現。

theme.js

CSS ではカスタマイズしきれない部分、例えばページの要素を増減するなどの処理は theme.js に実装する。Starter Kit では以下に配置されているものを編集。

.
└── src/
    └── assets/
         └── javascripts/
              └── theme.js

最近の代表的な Web ブラウザーにおける JavaScript は非常に機能が充実している。そのため外部ライブラリーやツールを使用せずとも実用十分だが、要素の操作などを簡単に処理したければ Redmine 付属の jQuery も利用可能。

Starter Kit の theme.js では以下のようにしている。

(function ($) {
  if (!($)) {
    return
  }

  // Cutomize

})(window.jQuery)

// Cutomize というコメント以降に $ で jQuery の機能を呼び出しながらカスタマイズしてゆく。この処理では jQuery がグローバル定義されていることを判定。Redmine に付属しなくなったらカスタマイズはキャンセルされるようにしてある。

開発スタイル

Starter Kit の提供する機能を利用したテーマ開発スタイルについて。

セットアップ

Starter Kit のセットアップ手順。Windows のコマンド プロンプトや PowerShell、macOS であれば Terminal を使用する。以降、これらをまとめて CLI と呼ぶ。

  1. Node.js 最新版をインストールまたは更新
  2. Starter Kit を入手、Git がなくても GitHub から ZIP 形式で取得可能
  3. CLI 上で cd コマンドにより Starter Kit フォルダーへ移動
  4. CLI 上で npm i コマンドを実行

これで Starter Kit に必要な環境が揃ったはず。

タスク実行

Starter Kit は package.json というファイルに開発で必要とされる機能をタスクとして定義。これらは CLI から npm run タスク という形式で呼び出す。以下にタスクをまとめる。

タスク 機能
start SCSS ファイルの変更監視と自動 CSS コンパイル、プレビューを起動。キーボードから Ctrl + C を押すことで終了する。
release テーマのリリース用イメージを出力。

他にも細かなタスクはあるが、基本的にこれらだけで実用十分なはず。開発中は npm run start で SCSS 編集しながらプレビューで確認。十分な品質となったら npm run release でリリース用イメージを生成 (テーマを ZIP に固めたもの)、それを Web に公開する。

なお start は特殊なタスクで run を省略して npm start でも実行可能。

自動 CSS コンパイルとプレビュー

start タスクで実行される処理について。

SCSS ファイルの変更を監視しており、編集して保存すると自動的に CSS コンパイルされる。プレビューは Redmine の代表的なページを対象に HTML 化したものを Web ブラウザーに表示。CSS がコンパイルされると Web ブラウザー上のプレビューも自動更新される。

そのため SCSS ファイルを編集するエディターと Web ブラウザーのウィンドウを横へ並べると開発しやすい。エディターはお好みで。私の推奨は以下。

これらに Sass (SCSS) 関連プラグインを入れることで構文強調や CSS プロパティーの入力補完などが効くようになる。こうした機能は開発を快適にしてくれるので、ぜひ。

注意点。プレビュー用 HTML は私が Redmine から取得した時点のもの。つまり厳密には Redmine 本体のものと異なるし本体の更新に追従できていない可能性がある。大まかな外観をプレビューするにはよいが、最終的には Redmine 本体で確認したほうがよい。

Redmine 上の動作確認

テーマが Redmine 上で実際に動作することを確認したい。しかし開発中のものを本番環境で試すのはリスクが高く、検証用にサーバーを用意するのも面倒だ。

という開発者のために Starter Kit では DockerDocker Compose により手元で気軽に Redmine 動作環境を構築できるようにしてある。手順は以下。

  1. DockerDocker Compose をインストール
  2. CLI 上で cd コマンドにより Starter Kit フォルダーへ移動
  3. CLI 上で docker-compose up -d コマンドで Redmine 起動、停止は docker-compose stop

この状態で Web ブラウザーから http://localhost:8080/ にアクセスすると Redmine が表示されるはず。ちなみに初期状態の Redmine における user/pass は admin/admin のみとなっている。admin で Sign In したら管理画面からテーマを変更してみよう。mytheme という候補があるので選択すると開発中しているテーマが Redmine へ適用される。

Docker 上の Redmine テーマ フォルダーは Starter Kit の src/assets と連携するように設定済み。そのため SCSS を CSS にコンパイルしたり src/assets 内の構造を変更すれば、そのまま反映される。なにかテーマを変更したら Web ブラウザーから Redmine ページを表示更新することで最新の状態を確認可能。

Docker 関連の設定は以下を参考にした。これまで Redmine 用 Docker イメージは sameersbn/redmine を使用していたのだが、本家となる redmine のほうがバージョン追従や継続性の面でよかろうと判断して移行。

もし Redmine が表示されないようなら Docker コンテナが落ちているかもしれない。コンテナの起動状況は docker ps コマンドで確認。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
d56a255d3cb3        redmine:passenger   "/docker-entrypoint.…"   11 minutes ago      Up 2 seconds        0.0.0.0:8080->3000/tcp   redmine
c299c663ee67        mysql:5.7           "docker-entrypoint.s…"   14 minutes ago      Up 3 seconds        3306/tcp, 33060/tcp      mysql

こんな感じで redminemysql が両方とも存在すれば成功。ないものがあれば docker logs redmine のようにすると対象コンテナのログが表示される。そのメッセージを参考に環境や設定を見直したり、Docker イメージのバグと予想されるなら作者に修正要望を出すなどすること。

リリース用イメージ生成

CLI 上で npm run release を実行することでテーマのリリース用イメージが生成される。その詳細について。

  1. テーマ名でリリース用フォルダーを作成
  2. src/assets に置かれた静的な画像と theme.js をリリース用フォルダーにコピー
  3. プロジェクト直下の CHANGELOG.mdLICENSE ファイルをリリース用フォルダーにコピー
  4. SCSS をリリース用フォルダーに CSS コンパイル出力
  5. リリース用フォルダーを ZIP 圧縮

これらの処理により Web ページなどで配布するためのイメージができあがる。テーマの名前とバージョンはプロジェクトのルートにある package.json の当該設定を編集することで更新可能。

{
  "name": "mytheme",
  "version": "1.0.0"
}

上記ならテーマは mytheme フォルダー、それを圧縮した ZIP ファイルは mytheme-1.0.0.zip というファイル名。私はこのように生成した ZIP を GitHub の Releases ページへアップロードすることでテーマ配信している。

まとめ

この記事により一人でもテーマ開発者が増えることを願っている。質問などがあれば Twitter で声をかけてください。