BASE開発チームブログ

フリーミアムなネットショップ構築サービス BASE( https://thebase.in )の開発チームによるブログです。開発メンバ積極募集中! https://www.wantedly.com/companies/base/projects

stylelintとBackstopJSで安全にcssを書ける環境を作った

20180605164447

こんにちは。BASE で Design Group に所属している三佐和です。主に ネットショップ作成サービス「BASE」 のフロントエンドを担当しています。

背景

BASE のデザインチームはここ最近で人数が急激に増え、活動が活発になってきており、その中のプロジェクトの一つとして、現在スタイルガイドの刷新に取り組んでいます。

しかし、人数が増えていく一方で、コーディングのルールの統一をコードレビューや個人の裁量に任せていたり、マークアップからリリースするまでに時間がかかってしまうことが問題になってきていました。 そこで、新しいスタイルガイドでは、デザイナーやエンジニアの作業工数を短縮し、より効率よく開発を進めるために、コーディングルールの整備とリグレッションテストを導入することにしました!

やったこと

  1. stylelint を使ってコーディングルールを管理
  2. BackstopJS でテストを行うことでデグレを防ぐ

前提として、 nodejs や yarn などの一般的なフロントエンド開発環境が整っているものとします。

stylelintを導入

stylelint を使って、これまで個人の裁量で保たれていたコーディング規約への準拠を機械的に行えるようにします。

導入

  • 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.jsonscripts にコマンドを追加して、 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.jsonscripts にコマンドを追加して、 yarn backstop-ref で参照用画像の作成、 yarn backstop-test でテストが実行できるようにします。

    // package.json
    // ...
    "scripts": {
        "backstop-ref": "gulp backstopref",
        "backstop-test": "gulp backstop",
    }
    // ...
    

    実際の使用方法

    はじめに、テストの元データになる参照用の画像を作ります。

    $ yarn backstop-ref
    

    20180605170855

    BackstopJS は、この画像をもとに比較テストを行ってくれるので、予期せぬ変更を行ってしまった場合にテストが失敗し、それに気づくことができます。

    試しに、このボタンの border-radius8px から 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 が出力されました。

    20180605164934

    これを開いてみると、差分のある箇所がピンク色になっています!分かりやすいですね!

    結果

    作業を開始する前にスナップショットを作成しておくことで、行った作業でのデグレに早く気づいたり、防ぐことできるようになりました。

    まとめ

    今回、stylelintやBackstopJSを利用したことで、実装者の負担が以前よりも軽くなりました!

    実装者が増えても差分が生まれにくく、デザインの一貫性を保つことができる仕組みを考え、引き続きスタイルガイドを作成していきたいと思います。また同時に、それらをメンテナンスしやすい環境も整えていきたいと思います!