既存プロジェクトをStylelint v14にアップグレードするときに注意すべき点

こんにちは!のせっち@nosecchi01です。

Stylelintをv13からv14へのメジャーアップデートがありました。
かなり大幅な変更がありましたので、アップデートは慎重に行う必要があります。

特に既存プロジェクトでは、既に書いているコードがあり、調整が大変だったので、注意すべき点をご紹介します。

Stylelint v14での変更点

主な変更点はStylelint公式のMigration Guideを読むのが一番確実です。

公式で説明されている変更点は下記(意訳)となっています。

  • 標準ではcssのLintに対応しなくなり、postcssパッケージを個別にインストールする必要がある。
    • 例えばscssならpostcss-scssとstyleint-config-standard-scssが必要など
  • node.js 10は切り捨て
  • v13.7.0で非推奨となったルールが廃止
  • configOverridesが廃止
  • function-calc-no-invalid が廃止

その他にも僕が実際にアップグレードをしていく中で詰まった点がたくさんありましたので個別に紹介します。

僕はscssを使用しているので、scssに関する記述になります。

個別事象が出た場合は、主にgitthub issueを参考に対応していきます!
参考にしたissueへのリンクを合わせて載せていきます。

まずはStylelintをv14にアップグレードする

Stylelintをv14にアップグレードしていきます。

npm i -D stylelint@14

最新版が欲しい場合はstylelint@latestとしてください。

stylelint-config-recmmended-scssはstylelint-config-standard-scssに統合された

stylelint-config-recmmended-scssはstylelint-config-standard-scssに統合されました。recommended-scssを使っていた人はstandardに置き換えましょう!

## recommended-scssを削除してstandard-scssをインストール
npm rm -D stylelint-config-recmmended-scss && npm i -D stylelint-config-standard-scss

.stylelintrc.json(またはstylelint.cofig.js)も編集しておきます

{
  "extends": [
    "stylelint-config-standard-scss"
  ],
}
styleling-config-standard-scssに関して

postcssを@8以上に

このままStylelintチェックを行うと、僕の環境では下記のエラーが出ました。

TypeError: Class extends value undefined is not a constructor or null

そこで、postcssを@8以上にします。

npm i -D postcss@8
TypeError: Class extends value undefined is not a constructor or nullについてのissue

これで一応Stylelintは動きます。その代わりいっぱいエラーが出ます。(僕は出ました)

scssのlintのためにpostcss-scssも必要

scssをlintするためには、stylelint-config-standard-scssの他にpostcss-scssも必要なので入れていきます。

npm i -D postcss-scss

設定にも追記します。

{
  "overrides": [
    {
      "files": ["**/*.scss"],
      "customSyntax": "postcss-scss"
    }
  ]
}

Unknown rule系のエラー

Unknown rule function-calc-no-invalid とエラー分が出る場合、冒頭でも説明しましたが、function-calc-no-invalidはv14で廃止されたので、rulesから削除する必要があります。

{
  "rules": {
    "function-calc-no-invalid" : true // 削除
  }
}

function-calc-no-invalidは130kもあって重たいので削除されたようです。

function-calc-no-unspaced-operatorというルールがあるので、そちらを使えばいいでしょう。
(デフォルトでtrueなのでわざわざ書く必要はありません。)

エラーだらけになったら(対応方法)

Stylelint v14にすると、めちゃくちゃエラーが出ます。
v14はデフォルトのルールが厳しい印象です。

新規プロジェクトならルールに合わせて書いていくこともできるかもしれませんが、既に書いたものを全部ルール適合させていくのは大変なので、ルールを緩和します。

一気に紹介します。

rules部分の特に重要そうなところを抜粋しました。

{
  "rules": {
    "selector-id-pattern": null, // idでkebab-case以外も許容
    "selector-class-pattern": null, // classでkebab-case以外も許容
    "keyframes-name-pattern": null, // keyframesでkebab-case以外も許容
    "scss/at-mixin-pattern": null, // mixinでkebab-case以外も許容
    "scss/dollar-variable-pattern": null, // $変数でkebab-case以外も許容
    "scss/percent-placeholder-pattern": null, // %placeholderでkebab-case以外も許容
    "scss/at-extend-no-missing-placeholder": null, // @extendで%placeholder以外も許容
    "function-url-quotes": ["always", { "severity": "warning" }], // url()内が""で囲まれていなくてもwarningで止める
    "number-max-precision": [3, { "severity": "warning" }], // 小数点以下3桁以上でもwarningで止める
    "alpha-value-notation": ["number", { "severity": "warning" }], // 0.3が30%となっていてもwarningで止める 
    "font-family-name-quotes": [
      "always-where-recommended",
      { "severity": "warning" }
    ], // font-family名のルールが適合していなくてもwarningで止める
    "property-no-vendor-prefix": [
      true,
      {
        "ignoreProperties": ["appearance", "text-size-adjust"]
      } // autoprefixerで補えるprefixを書いていた場合、エラーとなるが、ignorePropertiesは無視する
    ]
  }
}

JSONでコメントアウトはNGですが、解説用に書いています。

更に抜粋して個別に解説します。

"selector-id-pattern": null, // idでkebab-case以外も許容
"selector-class-pattern": null, // classでkebab-case以外も許容
"keyframes-name-pattern": null, // keyframesでkebab-case以外も許容
"scss/at-mixin-pattern": null, // mixinでkebab-case以外も許容
"scss/dollar-variable-pattern": null, // $変数でkebab-case以外も許容
"scss/percent-placeholder-pattern": null, // %placeholderでkebab-case以外も許容

デフォルトではなんとkebab-case以外全部エラーになるようになってしまいました。これは厳しすぎますね…!

kebab-caseというのはapply-formのように、単語をハイフンで繋げる命名規則です。
lowerCamel(applyForm)や、BEM(apply__form)はエラーとなり、これだと厳しいのでnullとして全部許容します。

他の命名規則で統一したい場合は、正規表現で書くことでルールを厳格に指定できます。

たとえば、lowercaseとkebab-caseのみ許容する場合、

{
  "rules": {
    "selector-class-pattern": "^[a-z][a-z0-9-]+$",
    "selector-id-pattern": "^[a-z][a-z0-9-]+$"
  }
}

BEMを許容する場合、

{
  "rules": {
    "selector-class-pattern": "^[A-Z][a-zA-Z0-9_-]+$",
    "selector-id-pattern": "^[A-Z][a-zA-Z0-9_-]+$"
  }
}
正規表現でのエラー判定について詳しく知りたい方はこちらのissueをどうぞ

ただ、エラー文も正規表現で出るようになって初見の人にはわかりにくいので、僕は一律nullとしています。

次です。

"scss/at-extend-no-missing-placeholder": null, // @extendで%placeholder以外も許容

@extendでは必ず%placeholderで書かないといけなくなりました。

// 正しい
%card {
  // 共通のスタイルを指定
}
.card {
  @extend %card;
}
.card--reverse {
  @extend %card;

  flex-direction: row-reverse;
} 

下記のように書くとNGとなります。

// NG
.card {
  // 共通のスタイルを指定
}
.card--reverse {
  @extend .card; // %placeholderで書かないとNG

  flex-direction: row-reverse;
} 

共通のスタイルを書きつつ、差分スタイルを@extend以下で書くとエラーとなります。

上記の例でいうと、.cardも利用しているのでわざわざ%placeholderで同じことを書く必要はないと思うのですが…。

ということでこのルールはnullとしました。

"function-url-quotes": ["always", { "severity": "warning" }], // url()内が""で囲まれていなくてもwarningで止める

background-image: url("image.jpg");のようなurl()内では””(クォート)で囲まれていないとエラーになります。

僕はなぜか””を書かない癖がついてしまっていて、既存プロジェクトを全部直すのは大変なのでwarningで止めることにしました。{ "severity": "warning" }を使うと、エラーをwarningにしてくれます。

"number-max-precision": [3, { "severity": "warning" }], // 小数点以下3桁以上でもwarningで止める

デフォルトだと小数点2桁以上書いたらエラーです。

"alpha-value-notation": ["number", { "severity": "warning" }], // 0.3が30%となっていてもwarningで止める 

alpha-value-notationというのはa { color: rgb(0 0 0 / 0.3) }の0.3の部分です。
モダンな書き方だと、0.3ではなく、30%と書く(percentage)そうですが、0.3(number)に慣れているのでnumberとして、たとえpercentageで書いたとしてもwarningで止めるようにしました。

"font-family-name-quotes": [
  "always-where-recommended",
  { "severity": "warning" }
], // font-family名のルールが適合していなくてもwarningで止める

これは複雑なのでまずは公式を見てください!

要はsans-serifserifのような汎用フォントはクォートで囲んではいけない、ということが守れていればいいので、選択肢の中から好みのルールを選べばいいです。

僕はalways-where-recommendedがしっくり来たのでこれにしました。

"property-no-vendor-prefix": [
  true,
  {
    "ignoreProperties": ["appearance", "text-size-adjust"]
  } // autoprefixerで補えるprefixを書いていた場合、エラーとなるが、ignorePropertiesは無視する
]

“property-no-vendor-prefix”はautoprefixerで補完されるprefixは書いてはいけない、というルールです。
–fixを付けてsytlelintを実行すれば自動修正されます。

ただ、自動修正すると今度は、declaration-block-no-duplicate-propertiesになってしまうのでやっかいです。

// 修正前
.hoge {
  transform: translateY(90deg);
  -webkit-transform: translateY(90deg); // property-no-vendor-prefixでエラー
}

// 修正後
.hoge {
  transform: translateY(90deg);
  transform: translateY(90deg); // declaration-block-no-duplicate-propertiesでエラー
}

ignorePropertiesを書いておくと、指定したプロパティは無視してくれます。
どっちしろ修正が大変なケースではignorePropertiesをうまく活用した方がいいときもあるでしょう。

既存プロジェクトは{ “severity”: “warning” }を活用する

既存プロジェクトでは、各scssファイルを修正してエラーを取っていく作業は非常に骨が折れます。

修正間違えをして、表示が崩れてしまっては元も子もないので、{ "severity": "warning" }をうまく活用して、まずはエラーゼロの状態を目指しましょう。

最終的にはルールを緩和するのか、ルールに合わせてscssファイルを修正するのかゆっくり検討すればいいです。

おまけ:Vueファイルの対応

.vueファイル内のscssをLintする場合も一工夫必要になりました。
まずはパッケージをインストール。

npm i -D postcss-html stylelint-config-html

configファイルも編集します。

module.exports = {
  extends: [
    "stylelint-config-standard-scss",
    "stylelint-config-html/vue" // 追加
  ],
}

これで.vueファイルのscssもLintしてくれるようになります!

お疲れ様でした!

この記事を書いた人

のせっち

福岡県出身。早稲田大学卒。創業100年の鉄鋼商社でバンコク駐在最年少抜擢。毎日擦り切れるまで働かなくても幸せに生きている人々を見てフリーランスになりました。
- WordPressが得意!
- 初心者向けGulp教材は購入者100部以上!