eslint-plugin-vue で来たる Vue.js 3 のリリースに備えよう

フロントエンドチームの右京です。 Vue.js 3 が八月上旬にリリース予定ということで、BASE でもバージョンアップに向けて少しづつアクションを始めています。 Vue.js 3 では多くの機能が追加され開発の幅が広がりますが、一方で削除や非推奨となる機能も多く頭を悩まされている方もいるのではないでしょうか、BASE もそうです。

この記事では ESLint とその Vue.js 向けプラグインの eslint-plugin-vue を利用した、deprecated となる機能へのアプローチを紹介します。

なぜ eslint-plugin-vue か

ESLint には Vue.js の SFC のためのプラグインとして eslint-plugin-vue が開発されていて、BASE でもこれを利用しています。 このプラグインには vue/no-deprecated- で始まるルールがいくつかあります。これは非推奨になった機能を使用しているかどうかを検出するためのルールです。

これまでは Vue.js 2.6 で非推奨になった slotscope に関する以下のルールのみでした。

  • vue/no-deprecated-slot-attribute
  • vue/no-deprecated-scope-attribute
  • vue/no-deprecated-slot-scope-attribute

しかし、最近リリースされ開発の勧められている v7.0.0-alpha.x で多数のルールの追加が行われています。

例えば BASE の場合、Vue.js 3 の移行で特に課題だったのが filter の廃止です。 金額の変換に多くの filter を使用していたため、範囲も広く置き換え方法を模索していたところでした。 eslint-plugin-vue では、これを vue/no-deprecated-filter ルールを適用することで検出することできます。

f:id:yaakaito:20200716130323p:plain

f:id:yaakaito:20200716130258p:plain

このほかにも多数のルールが現在進行形で追加されています。 ルールの一覧は 7.0.0-alpha.x タグの docs や、@ota-meshi さんによる日本語での解説から参照できます。

BASE では多数あるルールの中でも、特に効果の大きそうな <template> に関するルールを中心に追加していくことにしました。 <script> 部分には vue-class-component を使用していることもあり、一旦優先するべきところではないと判断しています。

Monorepo と GitHub Actions を利用した別ラインでの継続的な改修

現行の Vue.js 2.x での開発ももちろん行われているため、突然 ESLint のルールを変更するのはハードルが高く感じ、しばらくの間は既存のルールを共存させることにしました。

これを実現するため、 yarn workspace で Monorepo として 7.0.0-alpha.x をインストールし、普段使用しているものとは別のルールを適用できるようにしています。

.
├── packages
│   └── eslint-for-vue3
│       ├── node_modules
│       │   └── eslint-plugin-vue // 7.0.0.alpha-x
│       ├── .eslintrc.js // Vue 3 に向けた設定
│       └── package.json
├── node_modules
|   ...
│   ├── eslint
│   └── eslint-plugin-vue // 普段使っているバージョン
├── src // lint する対象
├── .eslintrc.js // 普段使っている設定
├── package.json
└── yarn.lock

eslint-for-vue3package.json で 7.0.0-alpha.x を dependencies に追加します。そして、この Monorepo のコンテキストで ESLint を実行する scripts を設定しています。

{
  "name": "@base/eslint-for-vue3",
  "private": true,
  "dependencies": {
    "eslint-plugin-vue": "7.0.0-alpha.9"
  },
  "scripts": {
    "lint": "eslint -c ./.eslintrc.js --ext .vue ../../src"
  }
}

.eslintrc.js には普段使用しているルールに加えて、vue/no-deprecated-* のルールを追加しています。

module.exports = {
    extends: "@baseinc/eslint-config-base",
    rules: {
        'vue/no-deprecated-slot-attribute': 2,
        'vue/no-deprecated-scope-attribute': 2,
        'vue/no-deprecated-slot-scope-attribute': 2,
        'vue/no-deprecated-filter': 2,
        'vue/no-deprecated-v-bind-sync': 2,
        'vue/no-deprecated-v-on-number-modifiers': 2,
        'vue/no-deprecated-events-api': 2,
        'vue/no-deprecated-functional-template': 2,
        'vue/no-deprecated-html-element-is': 2,
        'vue/no-deprecated-vue-config-keycodes': 2,
        'vue/no-deprecated-dollar-listeners-api': 2,
        'vue/no-deprecated-v-on-native-modifier': 2,
        'vue/no-deprecated-dollar-scopedslots-api': 2,
    }
}

この状態で以下のコマンドで、普段使っているものとは別のルールを適用した ESLint を実行できます。

$ yarn workspace @base/eslint-for-vue3 run lint

対応が終了したらこの .eslintrc.js を普段使うものに昇格させ、Monorepo を削除してしまえばあとの片付けも簡単です。

GitHub Actions でデイリービルドを構築し、モチベーションを高める

フロントエンドチームでは毎日十四時ごろからスタンドアップミーティングを行っており、これに合せて ESLint を実行するような GitHub Action を設定しています。日々進捗を確認する機会を設けることで、Vue.js 3 へのモチベーションも高めるようにしています。

name: lint for Vue.js 3

on:
  schedule:
    - cron: 0 5 * * *

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-node@v1
      with:
        node-version: '12.x'
    - uses: actions/cache@v1
      with:
        path: node_modules
        key: ${{ runner.os }}-lintvue3-${{ hashFiles('**/yarn.lock') }}
        restore-keys: |
          ${{ runner.os }}-lintvue3-
    - run: yarn install --pure-lockfile --ignore-optional --network-concurrency 1
    - run: yarn workspace @web/eslint-for-vue3 run lint
    - if: failure()
      env:
        SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
      run: |
        curl \
          -X POST\
          --data-urlencode "payload=\
              {\
                \"text\": \":bomb: Vue.js 3 マデアト:  https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID} \",\
              }"\
          ${SLACK_WEBHOOK}

以上です。

まとめ

ESLint を利用した比較的気軽に導入できる Vue.js 3 への対応方法を紹介しました。 もちろんこのエラーがなくなったからといって Vue.js 3 への対応が終了するわけではありませんが、対応のとっかかりなどになれば幸いです。

ちなみにですが、特に Vue.js の比率の高いリポジトリにこれを実行した結果は以下でした。

✖ 500 problems (500 errors)