仕事で初めてStylelintを使うのですが、今まで使ったことがなく、なんとなくしか理解できていなかったので今回ドキュメントを読みながら使い方についてまとめてました。
また、合わせて普段拡張機能で使っていたPrettierと合わせて使う方法についてもまとめてみました。
拡張機能とnpmでインストールするPrettierって何が違うのかも良く分かっていなかったのでそのあたりも調査したので同じようになんとなく使っているかたの参考になれば幸いです。
本記事の信頼性
30歳から異業種への転職をして、Shopify Experts企業で1年半ほどフルリモートで勤務していました。
現在は名古屋の自社開発企業のフロントエンドエンジニアしています。フリーランスとしても活動しています。
Stylelintとは
公式ドキュメントには下記のようなことが書いてあります。
- CSSやSCSSの構文をチェックするツールです。
- 自動修正機能
- 共有可能な設定
では、どんな構文をチェックすることができるのかというと、
- 1行あけるのかどうか
- カラーコードのcolor: red;の指定の可否
- プロパティの順番
などです。CSSはかなり色々な記述ができるので、実装者によってバラバラになりがちなことを統一することができます。
- CSSやSCSSの記述にルールを設けることで、コードの品質を高めることができる。
- プロパティの記述方法や順番などを気にせずにもっと本質的な実装部分について時間を使える。
- チーム間でルールを共有することができる。
- コードレビューするときに、コーディング規約に沿って実装されているのかについてチェックする必要がなくなる。
正しく使うことができれば、受けられる恩恵はかなりありそうです。
ゼロからStylelintを使ってみる
まずは、新規プロジェクトに対して、Stylelintを使ってみよう思います。
ベースはStylelintの公式サイトに沿って行っていきます。
プロジェクトの作成とインストールする
今回は、okalog-stylelint
とはフォルダを作成します。
下記コマンドでstylelint
とstylelint-config-standard
のパッケージをインストールします。
npm install --save-dev stylelint stylelint-config-standard
そうすると、下記のようにファイルやnode_modules
フォルダがインストールされてきます。
okalog-stylelint
├ node_modules
├ package-lock.json
└ package.json
package.jsonの中身を確認すると、インストールされたパッケージのバージョンを確認することができます。
{
"devDependencies": {
"stylelint": "^15.1.0",
"stylelint-config-standard": "^30.0.1"
}
}
まだ、これだけでは、stylelintを使用することができないので、設定ファイルを作成します。
.stylelintrc.json
ファイルをプロジェクト直下に作成して下記のように記述します。
{
"extends": "stylelint-config-standard"
}
stylelint-config-standartって何?
stylelintの基本的な設定を記述しているものになります。
Githubを見ると下記のような記述があり基本設定内容を確認することができます。
設定の中身を確認する(クリックすると確認できます。)
'use strict';
module.exports = {
extends: 'stylelint-config-recommended',
rules: {
'alpha-value-notation': [
'percentage',
{
exceptProperties: [
'opacity',
'fill-opacity',
'flood-opacity',
'stop-opacity',
'stroke-opacity',
],
},
],
'at-rule-empty-line-before': [
'always',
{
except: ['blockless-after-same-name-blockless', 'first-nested'],
ignore: ['after-comment'],
},
],
'at-rule-no-vendor-prefix': true,
'color-function-notation': 'modern',
'color-hex-length': 'short',
'comment-empty-line-before': [
'always',
{
except: ['first-nested'],
ignore: ['stylelint-commands'],
},
],
'comment-whitespace-inside': 'always',
'custom-property-empty-line-before': [
'always',
{
except: ['after-custom-property', 'first-nested'],
ignore: ['after-comment', 'inside-single-line-block'],
},
],
'custom-media-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
{
message: (name) => `Expected custom media query name "${name}" to be kebab-case`,
},
],
'custom-property-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
{
message: (name) => `Expected custom property name "${name}" to be kebab-case`,
},
],
'declaration-block-no-redundant-longhand-properties': true,
'declaration-empty-line-before': [
'always',
{
except: ['after-declaration', 'first-nested'],
ignore: ['after-comment', 'inside-single-line-block'],
},
],
'font-family-name-quotes': 'always-where-recommended',
'function-name-case': 'lower',
'function-url-quotes': 'always',
'hue-degree-notation': 'angle',
'import-notation': 'url',
'keyframe-selector-notation': 'percentage-unless-within-keyword-only-block',
'keyframes-name-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
{
message: (name) => `Expected keyframe name "${name}" to be kebab-case`,
},
],
'length-zero-no-unit': [
true,
{
ignore: ['custom-properties'],
},
],
'media-feature-name-no-vendor-prefix': true,
'number-max-precision': 4,
'property-no-vendor-prefix': true,
'rule-empty-line-before': [
'always-multi-line',
{
except: ['first-nested'],
ignore: ['after-comment'],
},
],
'selector-attribute-quotes': 'always',
'selector-class-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
{
message: (selector) => `Expected class selector "${selector}" to be kebab-case`,
},
],
'selector-id-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
{
message: (selector) => `Expected id selector "${selector}" to be kebab-case`,
},
],
'selector-no-vendor-prefix': true,
'selector-not-notation': 'complex',
'selector-pseudo-element-colon-notation': 'double',
'selector-type-case': 'lower',
'shorthand-property-no-redundant-values': true,
'value-keyword-case': 'lower',
'value-no-vendor-prefix': [
true,
{
// `-webkit-box` is allowed as standard. See https://www.w3.org/TR/css-overflow-3/#webkit-line-clamp
ignoreValues: ['box', 'inline-box'],
},
],
},
};
上記の設定をベースにCSSをチェックすることになります。
次にstyle.cssを作成して適当に下記のような記述をしてみてコマンドを叩いて見ます。
.hoge {
color: red;
}
.fuga {
color: yellow;
}
.piyo{
color: blue;
}
npx stylelint "**/*.css"
Expected empty line before ruleというエラーが出ており、設定元が表示されておりますね!
エラー内容: Expected empty line before rule
ルール: rule-empty-line-before
エラーを読むと、空白行を入れるというのがわかりますね。stylelint-config-standardで設定されている内容は下記の部分です。
'at-rule-empty-line-before': [
'always',
{
except: ['blockless-after-same-name-blockless', 'first-nested'],
ignore: ['after-comment'],
},
],
※設定されている内容は公式で確認可能なので興味あれば読んでみてください。
4行目の方にだけ空白行を入れて再度コマンドを叩いてみるとエラーが解消されたのがわかりますね。
.hoge {
color: red;
}
.fuga {
color: yellow;
}
.piyo{
color: blue;
}
けど、プロジェクトで
最初にも言ったように、このルールはstylelint-config-standard
に沿って設定されています。
プロジェクトによっては、CSSのクラス間に余白は入れたくないなどといったことがでてくると思います。
そのときには、下記のようにルールを追加することで設定を変更することができます。
{
"extends": "stylelint-config-standard",
"rules": {
"rule-empty-line-before": null
}
先程まででていたエラーがでなくなると思うので、試してみてください^^
ちなみに、全て自分で設定を書いていくという場合には、extendsの部分は記述せずにrulesのところにだけ設定を加えていけます。既存プロジェクトとかにも導入するのであれば、意外とこれのほうがいいのかなー思ったりしています。
{
"rules": {
"rule-empty-line-before": null
}
}
また、ここまではエラー内容が確認できる状態だけのコマンドでしたが、実はオプションをつけることで自動で修正してくれます。
npx stylelint "**/*.css" --fix
CSSの順番を変更する「stylelint-config-recess-order」
CSSってどの順番で書いても問題なく動きますよね。いいっちゃいいのですが、ここも揃っているとよりリーダブルなコードになります。そのためのパッケージが用意されているので入れておきましょう。
npm install --save-dev stylelint-config-recess-order
次に、stylelintrc.json
に"stylelint-config-recess-order"
を追加します。
"extends": ["stylelint-config-standard", "stylelint-config-recess-order"]
適当にstyle.cssにCSSを書いてみます。
.hoge::before {
content: "";
display: inline-block;
}
.hoge {
flex-direction: column;
display: flex;
background-color: yellow;
color: red;
}
.fuga {
color: yellow;
}
.piyo {
color: blue;
}
コマンドを叩くと、
おぉ自動で並び替えてくれました!これはよい!!!!
デフォルトはプロパティ順になっています。recessというものに基づいているようですが詳しくは理解できていません…
VSCodeの拡張機能「Stylelint」を導入する
上記まででも便利ですが、怠惰なエンジニアはこう思うわけです。
毎回コマンド入力するのがめんどくさい
いちいちコマンド入力するのめんどくささいですよね...。そんなときは、VSCodeの拡張機能がオススメです。
ExtensionsからStylelintと検索してインストールしてください。
インストール後、一度読み込むためにリロードする必要があるのでリロード(再起動)してください。
そうすると、いままでコマンド叩くことでしか確認することができなかったエラーが確認できるようになります。
ちなみに、このときに入れた拡張機能Stylelintはconfigファイル(.stylelintrc.json
)を参照するので設定値を変えれば拡張機能が検出してくれるエラー内容も変わります。
これでより良い開発体験を得ることができそうです。
Prettierを導入してフォーマットをする
次にPrettierを導入してフォーマットをしていきます。
他の方が書いた古い記事などを見ながらやると混乱してしまったので、公式を確認するようにします。
ということで、これからはPrettierのみを入れれば問題ないようです。
では、prettier
を入れていきます。
npm install --save-dev prettier
一度、package.jsonを確認します。
{
"devDependencies": {
"prettier": "^2.8.4",
"stylelint": "^15.1.0",
"stylelint-config-standard": "^30.0.1"
}
}
ここでコマンドを叩いてみます。
npx prettier --write .
説明のためにnpx prettier --write .
コマンドを実行したのですが、本来であればnode_modules
などはフォーマットの対象外にします。その際に、自動でフォーマットさせたくないファイルを.prettierignore
ファイルで指定しておくことができます。
node_modules
package-lock.json
のように記述しておくといいはず…です!
あれっstyle.cssにはまだstylelintのエラーが残っている…
そうです、実は先程やったフォーマットは別にstylelintに沿った形でフォーマットしているわけではないので別途パッケージを入れる必要があります。
npm install --save-dev stylelint-prettier
下記にも追加します。
{
"plugins": ["stylelint-prettier"],
"extends": ["stylelint-config-standard"],
"rules": {
"prettier/prettier": true
}
}
コマンドを叩きます。
npx prettier --write .
正しくフォーマットされたようです!よさそうです^^
ただ、プロジェクトによって設定を変えたいときがあると思います。
そのときには、.prettierrcファイルを作成して上書きすることで設置を変更することが可能です。
基本デフォルトで良さそうですが、僕はprintWidthだけ変えています。
{
"printWidth": 120
}
VSCodeの拡張機能「Prettier」を導入する
Stylelintのときと同様に、毎回コマンド叩くのはめんどくさいですよね。
VSCodeを使っていれば拡張機能が用意されています。検索でPrettier
と入れれば拡張機能がでてくるのでインストールします。
次に、保存時に変更が効くようにしておきます。
Format on Save
で検索して、チェックを入れます。default formatter
をPrettierに変更する。
実際にフォーマットされるのか見てみます。
かなり快適になりました!
コマンドをまとめる
VSCodeで基本は整形されるようになったし、Stylelintでもチェックできるようになりましたが、チーム開発の際には同じエディターを使っている保証はありません。
なので、必ずnpmコマンドで実行するようにしたほうが安全です。
stylelint "*/.css"
とprettier --write .
をまとめるために、pacakge.json
に追記します。
{
"scripts": {
"format": "stylelint style.css --fix && prettier --write ."
},
"devDependencies": {
"prettier": "^2.8.4",
"stylelint": "^15.1.0",
"stylelint-config-standard": "^30.0.1",
"stylelint-prettier": "^2.0.0"
}
}
これで下記コマンドでエディターに依存せずに同じようにファイルを管理することができます。
実際に実行した結果です。
既存プロジェクトに導入してみる
こちらも合わせて本記事に書いていこうと思ったのですが、冗長になりすぎそうなので、別記事を書いていきます。
また、記事が書けたらアップしますのでお待ち下さい。
まとめ
自分でまとめていくことでかなり理解を深めることができました。
品質を担保したコードを書けるようにするというよりも、仕組みで対応できるようにすることが重要だと思うようになったのでこれからのプロジェクトには導入していこうと思います。
また、今回はSCSSやCSSの順番を整形するパッケージなどについては書ききれていないので別の記事で書いていこうと思います。
参考記事
こちらの記事非常にわかりやすかったので紹介になります。