この記事は新歓ブログリレー2023の11日目の記事です。
こんにちは。21Bのmehm8128です。
新入生の皆さん、ご入学おめでとうございます。
さて、今回は特に新入生向けというわけではないのですが、最近やったことの紹介としてESLintのプラグインを作ってみた話をします。
ESLintとは
新入生でESLintを知っている人は少ないと思うので説明します。
僕はSysAd班でフロントエンドを主に書いています。分かりやすいように一番根本のところを言うとHTML/CSS, JavaScriptですね。これでも分からない人向けに説明すると、Webサイト・Webアプリの見た目の部分を作っています。
で、ESLintを導入しているとJavaScriptのコードを書くときに、書いたコードを静的に解析して、あらかじめ決めたルールに従っていないコードだとエラーや警告を出してくれて、バグを防いだり複数人で開発するときに統一感のあるコードを書くことができるようになります。
「あらかじめ決めたルール」はnpm, GitHub等で色々とコードが公開されていて好きなものを導入できるようになっているのですが、今回はそのルールを自分で作ってみたという話をしてきます。
作ったもの
これです。公開した週は150回もインストールされて驚きました。今でもほんの少しですがインストールされているっぽいですね(追記: バージョン上げたら新たに120インストールされました。バージョン上がったパッケージを監視してる民でもいるんですかね)。
https://www.npmjs.com/package/eslint-plugin-no-relative-path
ESLintはそれぞれのルールを作り、それらをまとめてプラグインというものにする(という認識なのですが合ってますかね)のですが、今回は2つルールを作ってプラグインにしてみました(2つ目は後から思いついて入れたおまけですが)。
メインのルールは相対パスでのimportを禁止するものです。
SysAd班活動を始めた初期のコードなのであんまり見せたくないのですが、以下のリンクを見ると分かりやすいと思います。
https://github.com/traPtitech/Jomon-UI/pull/6/commits/b4034626b8a4b133f4f77999d20a8e7397cb2da4#diff-403066c9f83fae483d771e15cda7a245f07c566235e465eb21acd6ba6461eaa4
../
という形式でのimportを許してしまうと、ネストが深くなったときに../../../../../
のように見た目が汚くなってしまうので、/@/
とするとsrcディレクトリから辿れるという設定にして、その書き方で統一するようにしています(ただ、この書き方だと逆に存在しないファイル名にしてしまっていてもエラーを吐いてくれないときがあるので一長一短な気もしています、何か改善方法があったりするんですかね)。
で、VSCodeの設定を変えていなかったり、たまに間違えたりして相対パスで書いてしまっているときに統一してくれるように、今回このようなルールを作ってみました。今までちょっと調べた感じそういうのがなかったので、no-restricted-imports
というところに書くことでエラーだけは出してくれるようにしていたのですが、今回これを作ったことでファイル保存時に自動で修正もしてくれるようになりました(実は既に同じようなのが存在していることを後から知りました。https://www.npmjs.com/package/eslint-plugin-no-relative-import-paths)。
そして、もう1つルールは、traP
という単語の大文字小文字が間違っていたときに自動で直してくれるものです。P
だけ大文字であとは小文字なので、新入生の皆さんはこの機会に覚えていただきたいです。部員の中でもたまにtrap
, Trap
, TraP
などと表記する人がいますが、ちゃんとtraP
と表記するようにしましょう。今回は練習のためにこちらもファイル保存時に勝手に直してくれるようにしましたが、こちらはしっかり自分で直すような設定にしてもよかったかもですね。
ちなみにtraPの読みや由来についてはこちらの質問箱で回答しています。他にも質問がありましたらどんどん投稿してください!
https://twitter.com/traPtitech/status/1633981561724080128?s=20
仕組み
では本題の、仕組みを説明します。
リポジトリの基本構成自体はこれを使わせてもらいました。コマンドを叩くだけでファイルが色々と生成されて、それらのファイルにコードを書くだけでいい感じにプラグインを作れるようになっています。
https://github.com/eslint/generator-eslint
相対パスのimportを防ぐ方のルールの場合、コードを書いたのは主に以下の2つです。
https://github.com/mehm8128/eslint-plugin-no-relative-path/blob/master/lib/rules/no-relative-path.js
https://github.com/mehm8128/eslint-plugin-no-relative-path/blob/master/tests/lib/rules/no-relative-path.test.js
1つ目はルール自体を定義していて、もう1つはそれが正しく動くことをチェックするためのテストファイルです。テストにはmochaというものを使っているらしいです。テストもある程度generator-eslintで骨組みは書いてくれているので、知らなくても楽に書くことができました。
では1つ目のルールの定義について詳細を説明します。
基本的にはESLintがソースコードからAST(抽象構文木)というものを勝手に作ってくれるので、そのどの種類のノードを受け取るか、受け取ったノードがどのような状態であればエラーを出すか(、オプショナルなものとしてエラーが出ている状態でESLintが走ったらどのように修正するか)を定義するだけです。
書いたコードがどのようなASTに変換されるのかは以下のサイトで確認できます。
https://astexplorer.net/
どの種類のノードを受け取るか、を書くときに特殊なフォーマットで書くのですが、以下のサイトを使えます。
http://estools.github.io/esquery/
具体的な使い方等に関してはこの記事の最後に載せる、参考記事を読んでみて下さい。
今回だとimport文であればそのimport pathを受け取り、import pathが相対パスであればエラーを出し、その状態でESLintが走ったら絶対パスに書き換えるようにしています。
最初に説明したように/@/
に書き換えるのですが、プロジェクトの設定によっては/@/
の形式でない場合もあると思うので、eslint.json
等、ESLintの設定ファイルで形式を設定できるようにもしてあります(https://github.com/mehm8128/eslint-plugin-no-relative-path/blob/6c34039ce6c08eae8e9389048152f6533efc983e/lib/rules/no-relative-path.js#L13-L22)。
最後に
ESLintとかJavaScriptとか分からないなーとか興味あるなーとかもっと勉強してみたいなーとか、なにかWebサイトやWebアプリを作ってみたいなーとか思った方でも思わなかった方でも、是非traPに入部してください!
SysAd班では毎年以下のような新入生向けのイベント・講習会を開催しており、数ヶ月で圧倒的成長することができます。僕も大学に入ってから本格的にプログラミングを始めたのですが、Webエンジニアになろう講習会に参加したことで先輩方から色々教えていただいてこのような記事を書けるくらいにまで成長することができました。
また、今回主に参考にさせていただいた記事は以下のものです。
https://techblog.yahoo.co.jp/javascript/how-to-create-eslint-rules/
https://blog.sa2taka.com/post/custom-eslint-rule-with-typescript/
https://zenn.dev/kazuwombat/articles/2a870356528783
実はプラグインの最後の更新から1ヶ月経ってしまった(追記:記事書いた後で更新しました)のですが、覚えているうちに記事を書けてよかったです。
明日の担当はわらびくんです。お楽しみに!