⚙️

ESLintなどの設定をパッケージ化することで使いやすくした

2024/05/20に公開

こんにちは、@sushi-chanです。電気通信大学で学生をしています。

最近、所属する学生団体向けにTypeScriptやWebフロントエンドのプロジェクトでよく利用される以下のツールの設定をパッケージ化しました。

  • ESLint
  • Prettier
  • Stylelint
  • TypeScript(tsconfig.json)

今回はパッケージ化の背景や手法、メリットと実際にやってみて見えたものについて書いていきます。

なお、以下の点はこの記事では触れません。

  • それぞれのツールの使い方・設定方法
  • パッケージ化した設定ファイルの中身・ルールセット

背景

近年、特にWebフロントエンドの文脈においてESLintやTypeScriptの設定はどんどん複雑になっており、ベストプラクティスだと呼ばれる設定も定期的に変わっています。新しいプロジェクトを作成するとき、各種ツールの設定に1時間以上かかってしまうことも珍しくありません。[1]

この設定にかかる労力は開発者を疲弊させるのに十分であり、また初学者がLinterやFormatterを導入する際には、設定ファイルの書き方やルールの意味を理解することがハードルになってしまいます。

今私が所属している団体では開発をメインに活動するチームを立ち上げている最中であり、初学者の割合も高いです。今後このチーム内で複数のプロジェクトを進めていくにあたり、設定にかかる労力の削減と初学者の学習効率の向上のためには設定ファイルのパッケージ化が有効だと考えました。

手法

設定ファイルのパッケージ化にはいくつかの手法があります。

  • npm packageとして公開する
  • GitHub Packagesで公開する
  • GitHub上のものを直接インストールしてもらう(npm install git+...)

今回は、特別な設定なく利用できる必要があり、特にPrivateにしたりする要素もなかったのでnpm packageとして公開することにしました。

設定を置いているリポジトリでは pnpm workspacechangesets を利用しています。4種のツールの設定をまとめておくためにモノレポを利用し、changesetsでパッケージのバージョン管理とリリースを自動化することで管理の労力を減らしています。

メリット

パッケージ化のメリットとして

  • 労力の削減
  • チーム内の設定の統一
  • プロジェクト固有の設定とそうでない設定の分離

があると考えています。

労力の削減・チーム内の設定の統一

まず設定の労力が大きく削減されます。新しいプロジェクトを作成する際にやることは、ツールそのものと設定パッケージをインストールしたあと、内蔵されているプリセットを組み合わせるだけです。

ESLintを例に挙げると、呪文のような設定ファイルを書いていたのが下のようなものに変わりました。

eslint.config.mjs
import react from "@virtual-live-lab/eslint-config/presets/react";
import tailwind from "@virtual-live-lab/eslint-config/addons/tailwind";
import tseslint from "typescript-eslint";

// React + TypeScript + TailwindCSSの例
export default tseslint.config(...react, ...tailwind);

presets: フレームワークや環境ごとの設定
addons: Tailwind CSSなどのライブラリ単位の追加設定
というように設定が用意されており、必要なものを組み合わせるだけで設定が完了します。

また、この手順を踏むことでチーム内での設定の統一が自動的に達成できます。設定ファイルの内容を変更する際は、パッケージのバージョンを上げるだけでチーム全体に反映されるため差異が生じることがありません。
ツールのバージョンアップに伴う破壊的変更も、設定ファイル側のpeerDependenciesを変更すれば安全に対応できます。

プロジェクト固有の設定とそうでない設定の分離

これは実際にやるまでわからなかったメリットで、特にtsconfig.jsonで顕著に見られました。

compilerOptionsの大半は使うフレームワークや環境ごとにある程度決まっているので、それらをプリセットに入れることでtsconfig.jsonに直接書く設定はpath aliasやプロジェクト全体で有効にする型定義、includeexcludeなどプロジェクト固有の設定に絞られました。

tsconfig.json
{
  // Next.jsをCloudflare Pagesにデプロイする場合の例
  "extends": "@virtual-live-lab/tsconfig/nextjs",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
    },
    "types": ["vitest/globals", "@cloudflare/workers-types"]
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
  ],
}

このような設定方式にすると、tsconfig.jsonに直接書いてあるものには大抵何らかの明確な理由があるという状態になるので、設定の意図が明確になります。

注意するべき点

ここまでパッケージ化する利点を書いてきました。しかし、ただパッケージ化すればいいというものではなく注意するべき点があります。

ルールのメンテナンスは必須

実際に使ってみると、「このルールの設定が実情に合わないな...」などはよくあることです。この場合パッケージのルールの変更が必要なのでリポジトリにIssueを立てるなりすると思います。しかし、開発に追われているとルールのメンテナンスが後回しになりがちです。

これは「何曜日の何時にルールのメンテナンス専用の時間を設ける」という合意をチーム内で作ることである程度解消できると考えられます。[2]

意思決定の記録を残す

設定したルールがどのような意図で現在の状態になったのかという意思決定のドキュメントを残しておくことが重要です。これがないと、ルールのメンテナンスや変更を議論する際に「それによって何が嬉しくなるのか」を考えることが難しくなります。

また、ツールの導入の際にエディタの設定変更なども必要になることが多いので、そういった手順もドキュメント化しておくとよいでしょう。

取り組む範囲と目的を明確にする

この世にはたくさんのライブラリやフレームワークがあり、それに対応するツールや設定もたくさんあります。チーム内で使われているものだけだとしても、規模が大きくなってくればすべて対応、というのはいずれ難しくなるでしょう。

ルールのパッケージ化と統一によってどれだけの恩恵を受けられればいいのかを事前に決めておかないと、メンテナンスが大変になって放置されてしまう危険があります。

さいごに

今回は、ESLintなどの設定ファイルをパッケージ化するメリットや実際にやってみた結果をまとめてみました。

ツールの設定をパッケージ化することで自身の理解も深めることができた上に、明らかに設定の苦しさが軽減したことを実感しています。
今後もメンテナンスを続けて団体のメンバーの開発効率向上を目指していきたいと思います。

最後まで読んでいただきありがとうございました。

脚注
  1. 私が遅いだけな可能性もあります。実際どうなんでしょうね? ↩︎

  2. ちなみに筆者は土曜日の夜にメンテナンスを行っています。 ↩︎

GitHubで編集を提案

Discussion