あなたも作れる!Redmine テーマ - 追補編
本記事は Redmine Advent Calendar 2019 の 14 日目です。redmine.tokyo 17 登壇で発表した「あなたも作れる!Redmine テーマ」を掘り下げる追補編となります。めちゃくちゃ長いです。年末の夜長にでもお読みください。
環境構築
テーマ開発にあたり、開発環境をすべて自前で構築するのは厳しいのでスターターを用意した。
しかしこれを動かすための環境を理解するのは登壇とスライドだけでは厳しそう。というわけで、より詳細に説明してゆく。
ターミナル
スターターに関する操作は CLI (Command Line Interface) となる。CLI 操作するツールは様々な呼ばれ方をするが、ここではターミナルに統一。俗称として「黒い画面」とか言われたりもする。
OS | ターミナル | 説明 |
---|---|---|
Windows | コマンド プロンプト | OS 標準付属ツール。後継の PowerShell や Windows Terminal が利用できるなら、操作性 (コピペなど) の観点からそちらのほうがよい。 |
〃 | PowerShell | OS 標準付属ツール & 言語。2019/12 時点で OS 標準付属にこだわるならオススメ。 |
〃 | Windows Terminal (Preview) | 現在の Windows には標準付属しないが、Microsoft がコマンド プロンプトや PowerShell (CLI ツール) を踏まえてモダーンなターミナルを提供するため開発しているもの。 |
〃 | その他 | 参考 Windowsで使えるターミナルとシェルのまとめ - Qiita |
macOS | Terminal.app | OS 標準付属ツール。割と多機能なのでこだわりがなければこれで。 |
〃 | iTerm2 | 定番のサードパーティー製ツール。私はこれを利用している。redmine.tokyo 17 登壇時のデモで見せたのもこれ。 |
Linux | ディストリビューションに応じてお好みで。 |
CLI について難しそうと感じるかもしれない。しかしスターターとしては README に書いてあるとおりコマンドをコピペして実行するだけで済む。実際に操作してみれば、拍子抜けするぐらい簡単だったりする。
この「コピペできる」というのが CLI のよいところ。説明もしやすく、操作そのものがテキストだからコピペしたり自分の環境に書き換えるといったことも可能。
これが GUI だと文章で説明するのは難しく、画像や動画を駆使してもユーザー環境ごとの外観差やマウス操作のミス (特にドラッグ アンド ドロップは事故りやすい) などによりサポート負担が大きい。
もし CLI を苦手とするなら、ぜひスターターを入門のきっかけにしてほしい。いま流行りの RPA 的な業務の自動化なども CLI の知見が役立つはず。ちょっとしたツールを作るとしても GUI (= 絵がある) は面倒だが、CLI ならずっと簡単だ。
ターミナルと CLI 説明に関する余談。これらについて解説された技術記事で
$ コマンド
# コマンド
のように先頭へ $
や #
などが記載されているを不思議に思ったことがあるかもしれない。これはプロンプトであり、その行がコマンド入力を受け付けている (いた) ことを表す。$
が一般ユーザー、#
は管理者であることが多い。$
が %
だったり >
なのもたまに見かける。
実際にコマンドを実行する際は、これらの記号を入力しなくてよい。それにも関わらずなぜ記載するのかというと、私の場合は CLI の入力と結果を区別しやすくするためである。例えば
$ コマンド 1
結果出力 1
結果出力 2
$ コマンド 2
結果出力 1
結果出力 2
のようになっていれば、複数のコマンドとそれぞれの結果出力を視認しやすい。本記事でも CLI 解説ではこの表記でゆく。この書き方に名前があるのかは知らないが、これまで私の読んできた技術書やブログなどでもよく目にする方法で、簡潔かつ分かりやすいため採用している。
Node.js
スターターにおける CSS 生成やテーマをリリースするための処理は Node.js を通して実行される。インストールは何通りかあるので、好みの方法を選ぼう。以下にそれぞれの方法についてまとめる。
方法 | 難易度 | 説明 |
---|---|---|
公式インストーラー | 低 | Node.js に公開されているもの。他の方法に比べてインストールが簡単。スターター的にバージョンは LTS と最新版のどちらでも OK。特にこだわりがなければ最新版で。 |
パッケージ管理 | 中 | 自分の利用している OS にあわせて、お好みで。私は macOS で Homebrew を利用している。他には apt、dfn、yum、Chocolatey など。 |
nodenv | 高 | 複数の Node.js バージョンを管理するツール。主にプログラマー向け。 |
Node.js はプログラミング入門としてもオススメ。こうしたスクリプト言語は他にも Perl、Python、Ruby など数多いが、Node.js は JavaScript で書ける点がよい。
JavaScript は Web ブラウザー向け標準言語なので、そちらの知見も活かせる。また言語としても ES2015 以降は相当にモダーンとなった。
ここ 5 年ぐらいの私は、ちょっとした自動化ツールなどは Node.js 向けに書いている。ファイル操作と通信があるだけでも、大抵の用途には十分すぎるぐらいだ。
Docker + compose
Docker はコンテナと呼ばれる単位の仮想環境 (小さい OS) を動かすためのソフトウェア。
仮想環境といえば VMware とか VirtualBox、これらの管理と操作を便利にしてくれる Vagrant なんかが有名だ。Redmine 界隈だと Redmine view customize plugin で有名な onozaty さんが Vagrant 向けに Redmine 用の仮想環境を作っている。
私も以前はこれを利用していた。ではなぜ Docker に移行したのか。それは設計的な違いから Docker のほうが仮想環境のサイズが小さく、起動も高速だから。もう一つ Redmine テーマを開発していて CSS 更新を反映させる際に、
- Vagrant + VirtualBox は Web ブラウザーのリロードだけではダメで、Redmine や仮想環境の再起動が必要
- Docker は Web ブラウザーのリロードだけで OK
という開発体験の改善もあった。これは私の環境 (macOS) に依存する問題かもしれないが、原因不明で対策方法も思いつかない。そんな折にサイズと起動速度の面から Docker を試したらこの問題が解決したので、移行することにした。
仮想環境について。
Redmine を動作させるためには本体だけでなく、Ruby、Rails、HTTP サーバーと DBMS など様々なミドルウェアが必要になる。こうしたものを自前で揃えたり、動作させるサーバーを用意するのは大変だ。自分の PC へ入れるにしても、ミドルウェアは環境への影響が大きいため問題が起きたときが怖い。
そこで仮想環境の出番がくる。これを動かすためのソフトウェアは必要となるが、その中のものを気にしなくて済むメリットのほうが大きい。また Docker や Vagrant は他人が作った仮想環境を再利用できる点も便利。特にこだわりがなければ、誰かの手による鉄板構成をそのまま使うほうが簡単で安全だ。
Docker Compose について。
Docker の扱うコンテナ (仮想環境) を複数、組み合わせたくなることがある。Redmine の場合、本体に必要な構成は固定的だが DB 部分は好みが分かれるので個別に扱いたい。そして Docker 公式 Redmine イメージもそれを想定した設計になっている。
こうした複数のコンテナを組み合わせて管理するツールとして Docker Compose がある。設定ファイル (YAML) に組み合わせるコンテナを定義すれば、自動的に協調動作させてくれるスグレモノ。スターターでは Docker + Docker Compose を前提とした設定ファイルを用意した。
version: "3"
services:
redmine:
container_name: redmine
image: redmine:4.0.5-passenger
restart: always
ports:
- 8080:3000
environment:
TZ: Asia/Tokyo
REDMINE_DB_MYSQL: mysql
REDMINE_DB_DATABASE: redmine_mytheme
REDMINE_DB_USERNAME: redmine_mytheme
REDMINE_DB_PASSWORD: redmine_mytheme
REDMINE_DB_ENCODING: utf8mb4
depends_on:
- mysql
volumes:
- ./src/assets:/usr/src/redmine/public/themes/mytheme
mysql:
container_name: mysql
image: mysql:5.7
restart: always
environment:
TZ: Asia/Tokyo
MYSQL_ROOT_PASSWORD: P@ssw0rd
MYSQL_DATABASE: redmine_mytheme
MYSQL_USER: redmine_mytheme
MYSQL_PASSWORD: redmine_mytheme
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
この例だと Passenger で動作する Redmine 4.0.5 と MySQL 5.7 を組み合わせている。Redmine 側の volumes
によって開発環境で生成されたテーマのファイルが Docker コンテナへ晒される。スターターではテーマ名を mytheme
にしているが、これを変えたければ YAML ファイル内のそれを一括変換すればよい。
Docker 関連のインストールについて。
昔は Docker と docker-compose を個別にインストールしたものだが、macOS と Windows であれば現在は Dock Desktop だけで全て揃う。
私も macOS 版を利用している。ただし Windows だと Hyper-V を有効化する必要があるそうで、これが問題になるかもしれない。
- Docker for Windowsをインストール
- 【入門】はじめての Docker Desktop for Windows のインストールと CentOS の仮想環境構築のセットアップ - Qiita
- Windows 10 での Hyper-V の有効化 | Microsoft Docs
残念ながら Hyper-V は Windows 10 Home だとサポートされず、Pro 以上が必要になる。登壇時はこれに気付かず「Windows でも簡単にセットアップできます」的な発言をしてしまい、申し訳ない。
これに関しては Docker Desktop WSL 2 を利用することが対策になるかもしれない。
- Docker Desktop WSL 2 backend | Docker Documentation
- Docker Desktop for WSL2 を使い快適にWindowsでサーバ開発をしよう! - Qiita
WSL2 は Hyper-V の応用だが、直に依存しているわけではないので Windows 10 Home でも有効化できる。ただし WSL2 自体がデフォルトで有効になるのは 2020/5 と言われているので、現時点だと Preview 版になってしまう。
こうした問題を抱えてまで Windows で開発するか?というのがあるため、Windows でスターターを使いたいユーザー向けに Vagrant 版の提供を検討している。希望されるユーザーが多ければ対応するので、本記事を読まれた後にアカベコ宛へ意見をください。特になければ現状どおり Docker のみのままにします。
作ってみる
スターターを動作させるための環境が整ったら、実際にテーマ開発してみよう。といっても
- SCSS とは一体...
- SCSS 編集にはどんなツールを使えばいいのか?
というユーザーも居ると思うので、これらも掘り下げる。
SCSS
CSS は CSS3 以降、ずいぶんと機能強化された。最近ではカスタムプロパティとして変数がサポートされたりしている。それでもセレクターの適用範囲に関する問題は CSS 標準だと解決されそうにない。
セレクターの優先順位は宣言位置と詳細度で決まる。しかしこれらだけでは規模の拡大にともない管理しにくくなる。後に宣言されたものが優先されるため、前に宣言されたものの都合が悪くなると後に宣言されたもので上書きしたり、詳細度を高めるために id
や class
を追加してお茶を濁すというのはよく見られる。
また、これらを無視する恐るべき !important
がある。これは宣言位置や詳細度に関わらず、その定義を強制的に最優先する。そのためこれを上書きするために打ち消し用の !important
を追加して...という連鎖へ陥りがち。これを見かけたら地獄開始の合図だと警戒しよう。
この問題はプログラミング言語だとスコープ機能によって対策される。ファイルや指定された名前空間などの単位下に宣言されたものは、外部に影響しない。この機能によりソフトウェアの規模が拡大しても個々を疎結合にできる。一応、CSS でも :scope
として提案されたが採用は進まず、利用するには厳しい。
その他、様々な CSS に不足している機能の補完や拡張を目的として Sass、Stylus などが開発された。これらは CSS を拡張した記法で書き、それを CSS に変換する。開発中は便利な書き方をして、エンド ユーザー向けには CSS として出力すればよいという設計。
こうした言語とツールのうち 2019 現在も開発が継続されていて普及しているものとして、スターターでは Sass を採用した。ただし Sass 標準の記法はかなり癖がある。そのため記法については CSS 標準に近い SCSS を選んだ。ややこしいのだけど
- Sass の方言として SCSS がある
- SCSS は CSS と互換性がある
と認識してもらえればよい。
では SCSS がどうやってスコープ問題を解決するのか。CSS 標準でもスコープ風に詳細度をコントロールするため
.header {
display: flex;
justify-content: space-between;
}
.header .logo {
width: 1.5rem;
height: 1.5rem;
}
.header .menu {
text-align: center;
}
のように書くことがある。単なる定義と命名ルールなのでプログラミング言語におけるスコープ機能のような強制力と安全性はないが、それは仕方ない。SCSS の場合、これを以下のように書ける。
.header {
display: flex;
justify-content: space-between;
.logo {
width: 1.5rem;
height: 1.5rem;
}
.menu {
text-align: center;
}
}
定義をネストさせることで、親子関係が強制化された。親となる .header
の名前を変更した場合も .logo
と .menu
は自動的にそちらへ属し、CSS に変換されれば CSS 標準の記法に基づいた出力を得られる。これを利用すれば宣言順と詳細度を気にするのはルート部分だけで済む。スコープ問題への対処としては不完全だが、壊れにくくなった。
もう一つ便利な機能として &
による連結がある。例えば CSS の疑似要素。これを
.menu:before {
}
.menu:after {
}
としているなら SCSS では
.menu {
&:before {
}
&:after {
}
}
のように &
を付けることで親へ連結してくれる。疑似要素や親子関係が増えるほど便利さを実感する機能だ。
SCSS には他にも便利な機能がたくさんある。記法自体は CSS 標準に寄せつつ、こうした拡張機能を使って楽をしよう。
エディター
特にこだわりがなければ Visual Studio Code (以下、VS Code) を推奨する。SCSS 編集に便利なプラグインとして以下を入れておこう。
プラグイン | 説明 |
---|---|
Sass | SCSS の構文強調や入力補完を提供してくれる。 |
Bracket Pair Colorizer 2 | {} などの括弧が見やすくなる。 |
Prettier | SCSS の記法を整形してくれる。例えばインデントを揃えるなど。 |
colorize | CSS の色指定 #FFF などを見やすくしてくれる。 |
SCSS を CSS に変換する
ターミナルを起動してスターターの場所まで移動する。もし一度も npm i
していないなら、これも実行しておく。
$ cd スターターのパス
$ npm i
次に SCSS ファイル監視モードを起動。
$ npm start
これでスターター内の SCSS ファイルを更新して保存すると自動的に CSS が生成される。もし SCSS の記法に誤りがあればターミナルにエラーが表示されるので修正しよう。
監視モードを終了するにはキーボードの control + C を押す。ターミナルや OS のショートカット キーをいじっていなければ、Windows、macOS、Linux 共通でこの操作が効くはず。
テーマをプレビューする
無事に Docker + Compose をインストールできたら、テーマをプレビューするためにターミナルから Docker コンテナ上の Redmine を起動する。初回だとコンテナのイメージをダウンロードするので少し待つ。
$ cd スターターのパス
$ docker-compose up -d
成功したなら Web ブラウザーで http://localhost:8080/ を開く。すると Redmine が表示されることを確認できるはず。Redmine の管理画面を開くと、表示画面のテーマ欄から作成しているテーマ (スタータの初期状態なら mytheme
) を選べるので変更しておく。
Docker コンテナを終了させる場合は以下を実行する。
$ docker-compose stop
テーマを編集する
ここまでの環境が整ったら、以下のようにテーマを編集してゆく。
- スターターの SCSS ファイル監視モードを起動
- スターターの Docker コンテナを起動
- Web ブラウザーで http://localhost:8080/ を開く
- SCSS ファイルを編集して保存
- Redmine を表示している Web ブラウザー上のタブを再読み込み
- Redmine 上で変更が反映されていることを確認
これを納得ゆくまで繰り返す。
編集したい箇所を調べる
さあこれでテーマ作れるぞ!となりそうだが、実際にはどのように SCSS を書けばよいか迷うはず。Redmine 上で変更したい場所はわかるのだが redmine.org などを見ても標準 CSS の詳細解説はないため、自分で調べなくてはならない。ここではその方法について説明しておく。
スターターの初期状態では、その時点で最新の Redmine 標準 CSS を同梱して読み込んでいる。場所は src/scss/defult
。ファイルの内訳は以下。
ファイル | 内容 |
---|---|
application.css | 通常表示用。 |
responsive.css | ページ幅が狭い場合の表示用。 |
これらを開きながら、Redmine を Chdome や Firefox などの Web ブラウザーで開こう。スターターのプレビューを起動できているならそれを、Docker の問題などで見られないなら他の Redmine を開く。
次に Web ブラウザーの開発者ツールを表示する。そして Redmine の変更したい箇所を開発者ツール上で選択しよう。以下は Firefox の開発者ツールで Redmine のヘッダー部分を選択している状態。
ヘッダー部分の HTML は <div id="header">
、CSS としては application.css
29 行目の #header
であることがわかったのでエディターで開いてみると、こんな感じになっていた。
#header {min-height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 20px 6px; position:relative;}
この中から背景色を赤に変えたいなら、スターターの App.scss
を以下のように定義する。
// build: application.css
@import "../../node_modules/normalize.css/normalize";
@import "./default/application";
#header {
background-color: #FF0000;
}
#header
が追記した部分。これより前の @import
で標準の application.css
を読み込んでいるため「宣言順として追記部分は後 = 定義を上書き」となる。こんな感じで変更したい箇所を特定、上書きというのを繰り返しながらテーマを作り上げてゆく。
標準 CSS は Redmine 上の大まかな部分単位でまとまっているため、大雑把にあたりを付けて Web ブラウザーの開発者ツールと突き合わせれば、構造も把握しやすいはず。
スターターの更新反映
Redmime のアップデートにあわせてスターターの標準も CSS 更新している。それを反映する場合は以下をダウンロードして自分の環境へ上書きしよう。
- Redmine 標準 CSS redmine-theme-starter/src/scss/default
- Docker Compose 設定 redmine-theme-starter/docker-compose.yml
これでベースになる CSS とプレビュー用 Redmine の両方が最新版へ更新される。
フルスクラッチ
スターターでは基本的に標準 CSS から差分で上書きすることを想定している。しかし慣れてきたり度胸のあるユーザーは、もっと大規模に書き換えたくなるはずだ。
その場合は App.scss
と Responsive.scss
で application.css
と responsive.css
を @import
している部分を削除し、かわりに標準 CSS の内容をコピペする。不要なら normalize.css
の行も消してよい。
これでスターターの SCSS が Redmine 標準 CSS 相当になったので、後は自身の SCSS/CSS 技術力にあわせて自由に編集してゆこう。私が minimalflat2 を開発した時はこんな感じで始めた。
しかし問題点として Redmine の更新追従がある。私の場合、
- redmine.org の Download から Redmine 標準イメージ ZIP を入手
- ZIP を展開して標準 CSS を入手
- 前回 1 〜 2 を実行して入手したものと差分を比較
- 差分を自作テーマの SCSS へ反映
という感じで作業している。差分比較は macOS の Xcode に付属する FileMerge。他のツール、例えば Windows なら WinMerge を利用してもよい。
ツールで見つかった差分については以下のようにチェック。
- 自作テーマで上書きしていないならそのまま最新をコピペ
- 上書きしている場合はその内容を踏まえて反映
この作業をやりやすくするため、フルスクラッチで作成するとしてもセレクターの宣言位置は Redmine 標準へ合わせておいたほうがいい。minimalflat2 では当初、宣言位置も独自に整理していたが差分チェックの面倒さにより Redmine 標準を踏襲するように修正した。
テーマをリリースする
納得のゆくテーマができたら、本番の Redmine へインストールするためのイメージを作成しよう。まずはテーマの名前とバージョンを編集するためにスターターの package.json
ファイルを開き、以下を編集する。
{
"name": "mytheme",
"description": "Starter kit for theme of Redmine.",
"version": "1.0.0",
"author": "author"
}
設定 | 内容 |
---|---|
name | テーマ名。リリースするテーマのフォルダー名に使用される。安全のため、使用する文字は英数へ限定することを推奨。 |
description | テーマの説明。ユーザーには見えないので面倒ならそのままでもよい。 |
version | バージョン番号。リリースするテーマを ZIP 圧縮した際のファイル名に使用される。 |
author | 作者。ユーザーには見えないので面倒ならそのままでもよい。 |
これらを設定したらターミナルを開き、以下を実行する。
$ cd スターターのパス
$ npm run release
少し待つとスターターのディレクトリー内に mytheme-1.0.0.zip
といった名前の ZIP ファイルが出力される。これがテーマのリリース用イメージになるので、自分の Web サイトに公開するなどして配信しよう。
私が作成している minimalflat2 というテーマでは、このように生成した ZIP を GitHub の Releases で配信している。
自分の作成したテーマを宣伝する手段として Redmine 公式のコミュニティー サイトである redmine.org にも告知しよう。ここに Theme List という Wiki ページが用意されているので、既にある記述を参考に自作テーマの紹介を書いてゆく。
まとめ
昨年の Redmine Advent Calendar 2018 でテーマ作成の話を書き、これを下地として redmine.tokyo 17 で登壇した。
そして本記事にいたる。足掛け 1 年、テーマについて解説したわけだが、これで一人でも Redmine テーマ開発者が増えたら幸いだ。
本記事をきっかけにテーマ開発を試みて、つまずくことがあったら Twitter のアカベコまでどうぞ。可能な限り相談にのります。
Redmine Advent Calendar 2019、15 日目は taikiix さんです。