こんにちは。BASE で Design Group に所属している三佐和です。主に ネットショップ作成サービス「BASE」 のフロントエンドを担当しています。
背景
BASE のデザインチームはここ最近で人数が急激に増え、活動が活発になってきており、その中のプロジェクトの一つとして、現在スタイルガイドの刷新に取り組んでいます。
しかし、人数が増えていく一方で、コーディングのルールの統一をコードレビューや個人の裁量に任せていたり、マークアップからリリースするまでに時間がかかってしまうことが問題になってきていました。 そこで、新しいスタイルガイドでは、デザイナーやエンジニアの作業工数を短縮し、より効率よく開発を進めるために、コーディングルールの整備とリグレッションテストを導入することにしました!
やったこと
- stylelint を使ってコーディングルールを管理
- BackstopJS でテストを行うことでデグレを防ぐ
前提として、 nodejs や yarn などの一般的なフロントエンド開発環境が整っているものとします。
stylelintを導入
stylelint を使って、これまで個人の裁量で保たれていたコーディング規約への準拠を機械的に行えるようにします。
導入
- stylelint-scss(SassのSCSS記法のためのプラグイン)
- stylelint-order(プロパティをアルファベット順に並び替えるプラグイン)
- stylelint-config-standard(CSSのコーディング規約集)
- prettier-stylelint(コードフォーマッターprettierとstylelintを組み合わせて使用する)
yarn を使ってインストールします。
$ yarn add -D stylelint stylelint-scss stylelint-order stylelint-config-standard prettier-stylelint
設定
既存のコーディングルールに合わせて、.stylelintrc
を設定していきます。
BASE の場合はプロパティをアルファベット順にソートしたかったので、stylelint-order
を使用したりしています。(私はいままで abc の歌を歌いながら順番にプロパティを並べていました........)
// .stylelintrc { "parser": ["css"], "plugins": ["stylelint-scss", "stylelint-order"], "extends": ["stylelint-config-standard", "./node_modules/prettier-stylelint/config.js"], "rules": { "indentation": 4, // インデント "order/order": [ "custom-properties", "declarations" ], // アルファベット順でソートする "order/properties-alphabetical-order": true, // アルファベット順でソートする "length-zero-no-unit": true, // 値が「0」なら単位を省略する "number-leading-zero": "always", // 小数点の頭の「0」は省略する "color-hex-length": "short", // HEX形式のカラーコードは3文字で表記する "shorthand-property-no-redundant-values": true // ショートハンドでプロパティを書く } }
設定ができたら、package.json
の scripts
にコマンドを追加して、 yarn lint-sass
で実行できるようにします。
// package.json // ... "scripts": { "lint-sass": "prettier-stylelint --quiet --write src/sass/**/*" } // ...
実際の使用方法
まずは思うがままに sass(scss) を記述します。
.btn--submit { color: $white; background-color: $green; border: none; }
めちゃくちゃですね!でも大丈夫です、lint を実行すると...
$ yarn lint-sass
こうなります。
.btn--submit { background-color: $green; border: none; color: $white; }
完璧ですね!もう歌は歌わなくても大丈夫になりました!
結果
常にコーディングルールを意識する必要がなくなったので、マークアップのスピードも上がりました!
2. BackstopJSを導入
BackstopJS を使って、戻りが発生しないよう、動作チェックする仕組みを作ります。
導入
- BackstopJSをインストール
stylelintと同様に、yarn を使ってインストールします。
$ yarn add -D backstopjs
backstop.json
にオプションを設定し、スナップショットを撮る- スナップショットを使ってテストする
設定
backstop.json
に必要なオプションを設定していきます。
// backstop.json { "viewports": [ { "label": "sp", "width": 320, "height": 480 }, { "label": "pc", "width": 1024, "height": 768 } ], "scenarios": [ { "label": "reference", // スナップショットの名前 "url": "テストするURL", "hideSelectors": [], "removeSelectors": [], "selectors": [ "#test-sandbox" // スナップショットを撮影する部分 ], "readyEvent": null, "delay": 500, "misMatchThreshold" : 0.1, "onBeforeScript": "", "onReadyScript": "" }, { "label": "test", // スナップショットの名前 "url": "テストするURL", "hideSelectors": [], "removeSelectors": [], "selectors": [ "#test-sandbox" // スナップショットを撮影する部分 ], "readyEvent": null, "delay": 500, "misMatchThreshold" : 0.1, "onBeforeScript": "", "onReadyScript": "" } ], "paths": { "bitmaps_reference": "./backstop_data/bitmaps_reference", "bitmaps_test": "./backstop_data/bitmaps_test", "compare_data": "./backstop_data/bitmaps_test/compare.json", "casper_scripts": "./backstop_data/casper_scripts" }, "engine": "phantomjs", "report": ["CLI", "browser"], "cliExitOnFail": false, "casperFlags": [], "debug": false, "port": 3001 }
設定ができたら gulpfile
にタスクを追加します。
// gulpfile.coffee // ... exports.backstopref = () => connect.server({root: './build', livereload: true}) backstopjs('reference').then () -> connect.serverClose() exports.backstop = () => connect.server({root: './build', livereload: true}) backstopjs('test').then () -> connect.serverClose() // ...
そして、package.json
の scripts
にコマンドを追加して、 yarn backstop-ref
で参照用画像の作成、 yarn backstop-test
でテストが実行できるようにします。
// package.json // ... "scripts": { "backstop-ref": "gulp backstopref", "backstop-test": "gulp backstop", } // ...
実際の使用方法
はじめに、テストの元データになる参照用の画像を作ります。
$ yarn backstop-ref
BackstopJS は、この画像をもとに比較テストを行ってくれるので、予期せぬ変更を行ってしまった場合にテストが失敗し、それに気づくことができます。
試しに、このボタンの border-radius
を 8px
から 0px
へ変更してみましょう。
そしておもむろにテスト実行用のコマンドを叩きます。
$ yarn backstop-test // ... compare | ERROR { requireSameDimensions: false, size: isDifferent, content: 0.32%, threshold: 0.1% }: reference bbq_reference_0_test-sandbox_0_sp.png compare | ERROR { requireSameDimensions: false, size: isDifferent, content: 0.32%, threshold: 0.1% }: test bbq_test_0_test-sandbox_0_sp.png compare | OK: reference bbq_reference_0_test-sandbox_1_pc.png compare | OK: test bbq_test_0_test-sandbox_1_pc.png report | Test completed... report | 2 Passed report | 2 Failed report | Writing jUnit Report report | Writing browser report report | jUnit report written to: ~~/backstop_data/ci_report/xunit.xml report | Resources copied report | Copied configuration to: ~~/backstop_data/html_report/config.js COMMAND | Executing core for `openReport` openReport | Opening report. report | *** Mismatch errors found *** COMMAND | Command `report` ended with an error after [0.51s] COMMAND | Error: Mismatch errors found. at ~~/backstopjs/core/command/report.js:113:17 at <anonymous>:null:null COMMAND | Command `test` ended with an error after [5.371s] COMMAND | Error: Mismatch errors found. at ~~/backstopjs/core/command/report.js:113:17 at <anonymous>:null:null [15:02:59] 'backstop' errored after 5.38 s
差分が発生したので、テストが失敗し、レポート用の HTML が出力されました。
これを開いてみると、差分のある箇所がピンク色になっています!分かりやすいですね!
結果
作業を開始する前にスナップショットを作成しておくことで、行った作業でのデグレに早く気づいたり、防ぐことできるようになりました。
まとめ
今回、stylelintやBackstopJSを利用したことで、実装者の負担が以前よりも軽くなりました!
実装者が増えても差分が生まれにくく、デザインの一貫性を保つことができる仕組みを考え、引き続きスタイルガイドを作成していきたいと思います。また同時に、それらをメンテナンスしやすい環境も整えていきたいと思います!