2018/10/11

デザイナーにもオススメ!シンプルですぐできるSass(SCSS)開発環境構築

ファミコン風CSSフレームワーク(NES.css)を開発するために、Sassの開発環境を整えたので共有したい。

ウェブページをスタイリングするためにはCSSを使うのだが、崩壊しやすい性質を持っている。詳細度による優先付け、スタイルの上書きなど要因はさまざま。そんな脆いCSSをちょっとでもメンテしやすくするために「Sass」というCSSを拡張したメタ言語が使われる。簡単に階層構造を作れたり、ループや関数などプログラムっぽいものが書けたりと、大きなウェブページをつくるなら必須だ。

しかし、Sassを使う上で避けては通れないものがある。
SassからCSSに変換する「コンパイル」だ。

フロントエンドエンジニアならNode.jsやwebpackを使ってできてしまうだろうが、デザイナーが手を出したら「Node.jsこわい」「webpackこわい」となりかねない。以降、コマンドラインから扱う便利ツールに拒否反応を示されてしまってはもったいない。

そこでシンプルで設定ファイルが少なく、かつある程度自動でなんでもやってくれるSassの開発環境をステップバイステップで構築していく。

この記事を書くにあたり使ったツールは以下のとおり。
  • Node.js環境
    • npm@5.2.0
    • node.js@8.11.4
  • SassをコンパイルしてCSSを出力する
    • node-sass@4.9.3
    • rimraf@2.6.2
  • ベンダープレフィックスを自動的に付加する
    • postcss-cli@6.0.0
    • autoprefixer@9.1.5
  • コーディングスタイルを統一する
    • stylelint@9.5.0
    • stylelint-config-recess-order@2.0.0
    • stylelint-config-standard@18.2.0
    • stylelint-scss@3.3.1
  • 自動フォーマットする
    • prettier-stylelint@0.4.2
    • clean-css-cli@4.2.1
  • コミット時にコーディングスタイルをチェックする
    • husky@1.0.0
    • lint-staged@7.3.0
  • エディタで保存時に自動フォーマットする
    • VSCode@1.27.2
    • prettier-vscode@1.6.1


TL;DR


Node.js環境を用意し、以下の内容をpackage.jsonというファイル名で作成する。
コマンドを実行して各種ツールをインストールし、ビルドコマンドやgit commitをするだけ。
{
  "name": "SASSの開発環境",
  "scripts": {
    "watch": "npm run build:sass -- --watch",
    "build": "npm run build:clean && npm run build:stylelint && npm run build:sass && npm run build:autoprefix && npm run build:cleancss",
    "stylelint": "stylelint scss/**/*.scss",
    "build:stylelint": "npm run stylelint -- --fix",
    "build:clean": "rimraf css",
    "build:sass": "node-sass --output-style expanded --source-map true scss/style.scss css/style.css",
    "build:autoprefix": "postcss --use autoprefixer --map false --output css/style.css css/style.css",
    "build:cleancss": "cleancss -o css/style.min.css css/style.css"
  },
  "devDependencies": {
    "autoprefixer": "^9.1.5",
    "clean-css-cli": "^4.2.1",
    "husky": "^1.0.0",
    "lint-staged": "^7.3.0",
    "node-sass": "^4.9.3",
    "postcss-cli": "^6.0.0",
    "prettier-stylelint": "^0.4.2",
    "rimraf": "^2.6.2",
    "stylelint": "^9.5.0",
    "stylelint-config-recess-order": "^2.0.0",
    "stylelint-config-standard": "^18.2.0",
    "stylelint-scss": "^3.3.1"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "scss/**/*.scss": [
      "npm run build:stylelint",
      "git add"
    ]
  },
  "browserslist": [
    "> 1%"
  ],
  "stylelint": {
    "plugins": [
      "stylelint-scss"
    ],
    "extends": [
      "stylelint-config-standard",
      "stylelint-config-recess-order",
      "./node_modules/prettier-stylelint/config.js"
    ],
    "rules": {
      "at-rule-no-unknown": null,
      "scss/at-rule-no-unknown": true
    }
  }
}

# 依存ライブラリのインストール
$ npm install

# SASSをビルドする
$ npm run build

# ファイルを監視し、リアルタイムでビルドする
$ npm run watch

# コミット時に自動でスタイルチェックする
$ git add .
$ git commit -m "○○機能の追加"



追記: 2019/08/05
ライブラリのバージョンアップにより一部動かなくなった箇所を修正した。またlint-stagedがnode@8.12以上のバージョンを要求するようになったので合わせてアップデートしてほしい。
{
  "name": "sass-project",
  "scripts": {
    "watch": "npm run sass -- --fix",
    "build": "npm run stylelint && npm run clean && npm run sass && npm run autoprefix && npm run minify",
    "sass": "node-sass --output-style expended --source-map true scss/style.scss css/style.css",
    "clean": "rimraf css",
    "autoprefix": "postcss --use autoprefixer --map false --output css/style.css css/style.css",
    "stylelint": "stylelint ./scss/**/*.scss --fix",
    "minify": "cleancss -o css/style.min.css css/style.css"
  },
  "devDependencies": {
    "autoprefixer": "^9.6.1",
    "clean-css-cli": "^4.3.0",
    "husky": "^3.0.2",
    "lint-staged": "^9.2.1",
    "node-sass": "^4.12.0",
    "postcss-cli": "^6.1.3",
    "prettier": "^1.18.2",
    "rimraf": "^2.6.3",
    "stylelint": "^10.1.0",
    "stylelint-config-recess-order": "^2.0.3",
    "stylelint-config-standard": "^18.3.0",
    "stylelint-prettier": "^1.1.1",
    "stylelint-scss": "^3.9.3"
  },
  "browserslist": [ ">= 1% in JP", "ie >= 10" ],
  "stylelint": {
    "plugins": [ "stylelint-scss", "stylelint-prettier" ],
    "extends": [ "stylelint-config-standard", "stylelint-config-recess-order" ],
    "rules": { "prettier/prettier": true, "at-rule-no-unknown": null, "scss/at-rule-no-unknown": true }
  },
  "husky": { "hooks": { "pre-commit": "lint-staged" } },
  "lint-staged": { "scss/**/*.scss": [ "npm run stylelint", "git add" ] }
}



Node.js環境を用意する


先にあげたツールはすべてNode.js上で動作するものなので、まずNode.jsの環境を用意する。多くの場合は、バージョン管理ツール(nvmやnodebrewなど)を使うのだが、複雑になってしまうので簡単な方法を紹介する。

nodejs.orgからLTS版をダウンロードし、インストールする。
# npmのバージョン確認
$ npm -v
5.6.0

$ node -v
v8.11.4



Sassをコンパイルする


Sassには2種類の構文方式がある。
  • sass記法
    • セミコロンレス(;が不要)
    • ブレースレス( {}が不要 )
  • scss記法
    • CSSとほぼ同じ

個人的に移植が簡単なscss記法のほうが好みなので、以降scss記法を使う。
.
|- scss // <-- ここに*.scssファイルを入れる
|   |- style.scss
|- css  // <-- ここにビルドされた*.cssファイルが入る
// style.scss
$default-font-size: 16px;
$color: #333;
$base-color: #f7f7f7;

body {
  font-size: $default-font-size;
  color: $color;
  background-color: $base-color;
}

次に、先ほど作成したstyle.scssをコンパイルするための設定を行う。
まずは、Sassのコンパイルに必要なnode-sassをインストールする。

# npmの初期設定(package.jsonを作成する ※あとから変更可能)
$ npm init

# node-sassをインストールする
$ npm install -D node-sass

次にコンパイルするためのスクリプトを定義する。
package.jsonのscriptsに書くことで、npm run {script-name}で実行することができる。

// package.json
{
  // 略
  "scripts": {
    "build:sass": "node-sass --output-style expanded --source-map true scss/style.scss css/style.css"
  }
  // 略
}

上記は、scss/style.scssというファイルをコンパイルし、css/style.cssという名前で出力するという設定。scss記法で書いたものを通常のCSSっぽいスタイルで出力したいので--output-style expandedを指定し、ついでに--source-map trueを指定してデバッグしやすいようにソースマップも出力する。

実行してみると、cssディレクトリ内にstyle.cssというファイルが作られる。
# コンパイルスクリプトを実行する
$ npm run build:sass


コンパイルするときに出力先(今回の場合は./css)にゴミが残るのは嫌なので、rimrafという「rm -rf」コマンド(指定ディレクトリの全削除)を実行できるツールも導入しておく。
# ramrafをインストールする
$ npm i -D ramraf


package.jsonに手を加え、出力先ディレクトリを削除してからCSSファイルを出力させる。
{
  // 略
  "scripts": {
    "build": "npm run build:clean && npm run build:sass",
    "build:sass": "node-sass --output-style expanded --source-map true scss/style.scss css/style.css",
    "build:clean": "rimraf css"
  },
  // 略
}

# CSSディレクトリを削除してから、Sassをコンパイルする
$ npm run build


これでSassのコンパイルはできたのだが、毎回npm run buildコマンド打つのは面倒だし、リアルタイムにコンパイルしてブラウザで確認したいときがある。そこで、ファイル変更を監視して自動コンパイルしてくれるwatchスクリプトを用意する。
{
  "scrips": {
    // 略
    "watch": "npm run build:sass -- --watch"
    // 略
  }
}
# ファイル変更を検知して、Sassをコンパイルする
$ npm run watch

このスクリプトを実行しておけば、ファイルを保存したときにSass→CSSに自動でコンパイルしてくれる。



ベンダープレフィックスを自動的に付加する


いまだに一部のプロパティにはベンダープレフィックス(-ms-, -webkit-, -o-など)を必要とする場合がある。ただ、これをいちいち調べて手動で付加するのは面倒だ。

そんなときには、PostCSSとそのプラグインのAutoprefixerを使う。対象にするブラウザはBrowserslistで指定する。当記事ではシェアが1%以上のブラウザを対象にする。
# PostCSSをインストールする
$ npm i -D postcss-cli

# プラグインAutoprefixerをインストールする
$ npm i -D autoprefixer

次にpackage.jsonに手を加え、出力先ディレクトリの削除 → Sassのコンパイル → ベンダープレフィックスの付加をできるようにする。
{
  // 略
  "scripts": {
    "build": "npm run build:clean && npm run build:sass && npm run build:autoprefix",
    "build:sass": "node-sass --output-style expanded --source-map true scss/style.scss css/style.css",
    "build:clean": "rimraf css",
    "build:autoprefix": "postcss --use autoprefixer --map false --output css/style.css css/style.css"
  },
  "browserslist": [
    "> 1%"
  ],
  // 略
}

# CSSディレクトリ削除 → SASSコンパイル → ベンダープレフィックス付加
$ npm run build

css/style.cssを読み込んで、ベンダープレフィックスを付加して、css/style.cssに出力(上書き)するというスクリプトだ。browserslistに"> 1%"と指定するだけで、シェア1%以上あるブラウザを対象にしてくれる。

IE9対応するなら"Explorer 9", 最新の2バージョンを対象にするなら"last 2 versions"といった具合に指定できる。詳細についてはbrowserslistのリポジトリを確認ください。



コーディングスタイルを統一する


10人いれば10通りのコーディングスタイルがあるように、チーム開発になるとコードがカオスになりがちだ。コーディング規約を定めて「運用でカバー」は大抵うまくいかない。コード内に秩序をもたらすには、ルールを「強制」させることである。

そこでstylelintを使ってコーディングスタイルを統一、もとい強制させる。
# stylelintをインストールする
$ npm i -D stylelint

# SCSS用のプラグインをインストールする
$ npm i -D stylelint-scss

# 標準的なルールを使う
$ npm i -D stylelint-config-standard

# プロパティの順序を強制する
$ npm i -D stylelint-config-recess-order

次にpackage.jsonの修正と、Stylelintの設定を行う。
{
  // 略
  "scripts": {
    "build": "npm run build:stylelint && npm run build:clean && npm run build:sass && npm run build:autoprefix",
    "stylelint": "stylelint scss/**/*.scss",
    "build:stylelint": "npm run stylelint -- --fix",
    // 略
  },
  // 略
  "stylelint": {
    "plugins": [
      "stylelint-scss"
    ],
    "extends": [
      "stylelint-config-standard",
      "stylelint-config-recess-order",
    ],
    "rules": {
      "at-rule-no-unknown": null,
      "scss/at-rule-no-unknown": true
    }
  }
}

stylelintのpluginsにはSCSS用のプラグインを、extendsには標準ルールとプロパティ順序のルールを追加する。このままではSCSSの@mixin@functionを使ったときに「CSSにない構文です」とエラーになってしまう。そこでrules内でデフォルトのat-rule-no-unknownを無効化し、scss用のscss/at-rule-no-unknowsを有効にする。

ビルドスクリプトを実行すると、コーディングスタイルチェック&整形 → 出力先ディレクトリ削除 → Sassコンパイル → ベンダープレフィックス付加が行われる。
$ npm run build


自動フォーマットする


stylelintに--fixフラグを付けて実行することで、ルールに反する記述を自動的にフォーマットしてくれる。ただそれだけでは、コーディングスタイルを強制するにはちと甘い。

そこで、より強制力を強化するためにPrettierというコードフォーマッターを使う。このツールによりstylelintでは対応しきれなかった部分まで整形させる。

さらにclean-cssというツールを使い、不要なコメントの削除やMinify(ファイル圧縮)をする。
# StylelintでPrettierを使うためのプラグインをインストールする
$ npm i -D prettier-stylelint

# clean-cssをインストールする
$ npm i -D clean-css-cli

次にpackage.jsonの修正と、stylelintの設定を変更する。
{
  // 略
  "scripts": {
    "build": "npm run build:stylelint && npm run build:clean && npm run build:sass && npm run build:autoprefix && npm run build:cleancss",
    // 略
    "build:cleancss": "cleancss -o css/style.min.css css/style.css"
  },
  // 略
  "stylelint": {
    "plugins": [
      "stylelint-scss"
    ],
    "extends": [
      "stylelint-config-standard",
      "stylelint-config-recess-order",
      "./node_modules/prettier-stylelint/config.js"  // <-- 追加
    ],
    "rules": {
      "at-rule-no-unknown": null,
      "scss/at-rule-no-unknown": true
    }
  }
}

このビルドスクリプトを実行すると、Prettierでフォーマット → Stylelintでコーディングスタイルのチェック&整形 → CSSディレクトリ削除 → Sassコンパイル → ベンダープレフィックス付加 → ファイル圧縮がされる。
# ビルド実行
$ npm run build

# ビルド後のディレクトリ
.
|- scss
|    |- style.scss
|- css
     |- style.css
     |- style.min.css
     |- style.css.map



コミット時にコーディングスタイルをチェックする


いくらスクリプトを用意しても、実行してくれなかったら意味がない。秩序の破壊は絶許案件なので、コミット直前に最終防衛ラインを張る。

gitのpre-commitフックを使ってコミット直前にコーディングスタイルをチェックし、もしチェックがエラーになったらコミットはキャンセルする方法だ。

そのために、huskylint-stagedを使う。
# huskyをインストールする
$ npm i -D husky

# lint-stagedをインストールする
$ npm i -D lint-staged

次にpackage.jsonに手を加え、コミット前にstylelintでチェックさせる。
{
  // 略
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "scss/**/*.scss": [
      "npm run build:stylelint",
      "git add"
    ]
  },
  // 略
}

これで、pre-commit時にlint-stagedを実行、scssディレクトリ内の全scssファイルを対象に、stylelintによるチェックと自動フォーマットを行い、エラーがなければコミットできるようになった。


全体図


当記事に書かれていることをやっていくと、最終的に以下のようなpackage.jsonができあがる。

{
  "name": "SASSの開発環境",
  "scripts": {
    "watch": "npm run build:sass -- --watch",
    "build": "npm run build:clean && npm run build:stylelint && npm run build:sass && npm run build:autoprefix && npm run build:cleancss",
    "stylelint": "stylelint scss/**/*.scss",
    "build:stylelint": "npm run stylelint -- --fix",
    "build:clean": "rimraf css",
    "build:sass": "node-sass --output-style expanded --source-map true scss/style.scss css/style.css",
    "build:autoprefix": "postcss --use autoprefixer --map false --output css/style.css css/style.css",
    "build:cleancss": "cleancss -o css/style.min.css css/style.css"
  },
  "devDependencies": {
    "autoprefixer": "^9.1.5",
    "clean-css-cli": "^4.2.1",
    "husky": "^1.0.0",
    "lint-staged": "^7.3.0",
    "node-sass": "^4.9.3",
    "postcss-cli": "^6.0.0",
    "prettier-stylelint": "^0.4.2",
    "rimraf": "^2.6.2",
    "stylelint": "^9.5.0",
    "stylelint-config-recess-order": "^2.0.0",
    "stylelint-config-standard": "^18.2.0",
    "stylelint-scss": "^3.3.1"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "scss/**/*.scss": [
      "npm run build:stylelint",
      "git add"
    ]
  },
  "browserslist": [
    "> 1%"
  ],
  "stylelint": {
    "plugins": [
      "stylelint-scss"
    ],
    "extends": [
      "stylelint-config-standard",
      "stylelint-config-recess-order",
      "./node_modules/prettier-stylelint/config.js"
    ],
    "rules": {
      "at-rule-no-unknown": null,
      "scss/at-rule-no-unknown": true
    }
  }
}

そして使えるスクリプトは以下の通り

  • npm run watch
    • ファイルの変更を検知して自動でコンパイルする
  • npm run build
    • 以下の順でスクリプトを実行する
      1. npm run build:clean
      2. npm run build:stylelint
      3. npm run build:sass
      4. npm run build:autoprefix
      5. npm run build:cleancss
  • npm run stylelint
    • scssのスタイルチェックを行う
  • npm run build:stylelint
    • scssのスタイルチェックを行い、ルールに外れた箇所を自動で修正する
  • npm run build:clean
    • 出力先のcssディレクトリを削除する
  • npm run build:sass
    • scssファイルをcssファイルにコンパイルする
  • npm run build:autoprefix
    • cssファイルにベンダープレフィックスを自動で付加する
  • npm run build:cleancss
    • cssファイルをMinifyする




おまけ: VSCodeで保存時に自動フォーマットする


自分の知らないところでコードが変更されるのは嫌だ! と思うことがある。もちろん私も。
しかし、これまでに紹介したものはコマンドを実行するだの、コミット前に自動チェックされるだの、目の届かない(届きにくい)ところで動いているので、どう変更されたか把握しづらい。

ということで、VSCodeでファイルを保存したときに自動フォーマットする設定をしてみる。


まず、Prettierの拡張機能(prettier-vscode)をインストールする。
次にUser Settings、またはWorkspace Settingsで、保存時に自動フォーマットする設定を行う。User Settingsはすべてのワークスペース(プロジェクト)で有効になる設定。Workspace Settingsは特定のワークスペースでのみ有効になる設定なので、用途にあわせて使い分けてほしい。

今回はWorkspace Settingsを使うので、ワークスペースに.vscode/settings.jsonを作成し、以下の設定を書いて保存する。
.
|- .vscode
    |- settings.json
// .vscode/settings.json
{
  "editor.formatOnSave": true,
  "prettier.stylelintIntegration": true
}

一旦、VSCodeを再起動すれば完了!
保存と同時に自動フォーマットしてくれる。


ちなみにPrettierやStylelintがグローバル、またはカレントプロジェクトにインストールされていないと動かないので注意!!



良き、CSSライフを!



以上

written by @bc_rikko

2 件のコメント :