こんにちは。BASE で Design Group に所属している 三佐和 です。主に ネットショップ作成サービス「BASE」 のフロントエンドを担当しています。 背景 BASE のデザインチームはここ最近で人数が急激に増え、活動が活発になってきており、その中のプロジェクトの一つとして、現在スタイルガイドの刷新に取り組んでいます。 しかし、人数が増えていく一方で、コーディングのルールの統一をコードレビューや個人の裁量に任せていたり、マークアップからリリースするまでに時間がかかってしまうことが問題になってきていました。 そこで、新しいスタイルガイドでは、デザイナーやエンジニアの作業工数を短縮し、より効率よく開発を進めるために、コーディングルールの整備とリグレッションテストを導入することにしました! やったこと stylelint を使ってコーディングルールを管理 BackstopJS でテストを行うことでデグレを防ぐ 前提として、 nodejs や yarn などの一般的なフロントエンド開発環境が整っているものとします。 stylelintを導入 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を利用したことで、実装者の負担が以前よりも軽くなりました! 実装者が増えても差分が生まれにくく、デザインの一貫性を保つことができる仕組みを考え、引き続きスタイルガイドを作成していきたいと思います。また同時に、それらをメンテナンスしやすい環境も整えていきたいと思います!