積み上げ消化:Reactハンズオン 環境構築(npm、eslint)

 Reactハンズオン第2版の本編自体は終わったものの、付録部分の環境構築(主にコーディングで使用するツール)の部分がまだだったので今日はそこをやった。
 各種ツールはなんとなく使っていたため非常に為になる。公式ドキュメントなども読むとして…いったんは本書の書いてある内容をまとめる。
 また本書は如何せん最新の本とは言えない。eslintの設定ファイルを自動生成する際などに古さを感じる部分があった。自動生成の質問の際にフレームワークの選択肢にNextが出てこなかったのだ。

 公式ドキュメントも明日にでも読んでみよう。

npm

 npmはNode.jsのパッケージマネージャー……というと非常に簡潔なのだろう。
 Node.jsという凄い働き者に取り次いでくれる担当者がnpm、だと思っている。文字通りマネージャー的な。
 そもそもNode.jsはサーバー上でJSを実行するためのフレームワーク?らしいのだが、まぁサーバー上(便宜上このPC上)で色々頑張ってくれるもの。

 パッケージ配布のためのデータベース(npmレジストリというらしい)とパッケージ管理のためのCLI(Command Line Interface)の両方を指す。
 主にコマンドラインでnpm、npmと繰り返すためどちらかと言えば後者の側面がなじみ深い。npm コマンドで「npm君、これやっといて」みたいな。
 これを更に改良?したらしいnpnmだかとかもあるらしいし、Yarnなど他のCLIもあるらしいからややこしい。
 ひとまずNodeに取り次いでくれる人、という認識。

 その性質上Nodeがグローバルにインストールされていればnpmもどこからでも使用できる。
 npm initコマンドをプロジェクトフォルダで実行すると初期化ができ、-yのオプションで初期化の質問を省略できる。
 npmでプロジェクトを初期化するとpackage.jsonというプロジェクトの設定に関するファイルが生成される。

 

 package.jsonと依存パッケージ

 このpackage.jsonはプロジェクトの情報が格納されているが、中でも重要なのは依存パッケージのリスト

 dependenciesとdevDependenciesがそれ。
 依存パッケージとは「これがないとこのプロジェクト成り立たないよ!」という必要なのでインストールしてあるライブラリ、だと思う。

 npm install(省略はnpm i)コマンドでライブラリをインストールするとこの依存パッケージの部分にパッケージの名前とバージョンが追加される。

 開発の為だけに必要なツール(テストやコード整形に必要なものなど)は--save-devや-Dオプションをつけてインストールしよう。
 アプリが実際に動くのに必要なパッケージはオプションなし、アプリを作ることだけに必要なパッケージはオプション付きでインストールしよう。
 オプションなしだとdependenciesへ、オプションありだとdevDependenciesのフィールドへ追加される。

 既存プロジェクトの場合は、githubからcloneしたプロジェクトのルートディレクトリでnpm iを走らせるだけでいい。
 存在しているpackage.jsonの依存パッケージリストを参照し、その対応パッケージがインストールされる。
 ただ、対応パッケージとはいえ最新版が勝手にインストールされるので、固定のバージョンが使いたい場合は後述するpackage-lock.jsonを参照したインストールを試すこと。


 またpeeDependenciesという、直接依存関係にはないが、あるパッケージがインストールされているときにインストールされる必要のある依存関係リストもある。

 

 依存パッケージのアップデートがあるかは、npm outdatedで確認できるらしいが、本PCでは動かなかったっぽいので何かあるのか、それともないのか。 

package-lock.json

 npm installを実行すると、package.jsonとは別に生成されるpackage-lock.jsonは依存関係に特化したファイル
 node_modules配下の依存パッケージをすべて列挙しており、ロックファイルとも呼ばれる。
 依存パッケージだけでなく、依存パッケージが依存しているパッケージなども覚えており、名の通り依存パッケージのバージョンを固定する目的で使用される。

 npm iでは対応パッケージの最新版が勝手にインストールされるが、npm ciではこのpackage-lock.jsonで指定されたバージョンがインストールされる。
 通常、npm iを使用する都合上、こちらも更新されてしまう
 性質上、手動編集せずバージョン管理システムで管理するのが良いようだ。

 

コマンドの定義と実行

 npm {コマンド}で何かしらのサブコマンドを実行するのは言うまでもないが、頻出するコマンドは自身で定義し実行することができる

 コマンド定義をする場所はpackage.jsonのscriptsフィールド。 

 ここに"CLI上で呼び出す際のコマンド : "実際に呼び出されるコマンド"と定義する。
 ここで定義したものを呼び出す際はnpm run {コマンド名}で呼び出せる。

 プロパティの値にはシェルで実行可能なコマンド、もしくはnod_modules配下にインストールされているCLIを文字列として指定する必要がある。

 つまり、実行できるかインストールしてあるCLIのコマンドを”文字列”として保存しておく。
 一部コマンドはrunを省略できる、らしいが……何が定義済みかそうではないかは分からない。runひとまずつけときゃ問題ないかな?

 

パラメータ

 先ほど定義したコマンドを実行する際にパラメータを渡すこともできる
 scriptsフィールドでコマンドを定義する際に事前にパラメータを渡すこともできる。

 事前に定義せずコマンドプロンプト上で呼び出す際にパラメータを渡すにはパラメータの前にさらに--をつける。つまり、

 npm run {コマンド} -- --{パラメータ}で呼び出したコマンドにパラメータを渡せる

 npm run {コマンド} --{パラメータ}ではnpm本体にパラメータが渡ってしまい、予期せぬ動きとなる。

 

npx

 npmコマンドに次いで頻出していたnpxコマンド。

 scriptsで定義せずにCLIを直接呼び出せるコマンド。ローカルにインストールされていないCLIもリモートで呼び出して実行してくれる

 npmはNode.jsのパッケージマネージャーなので、npmはNode本体を一度呼ぶ…と解釈している。npm run {コマンド名}はnpmがNodeを呼んでNodeがまたCLIを呼ぶ、みたいな感じだろうか。これはNodeではなくインストール済みのCLIを直接呼ぶ。

 単純に事前定義されていないNode以外のCLIを呼び出す際のコマンドと覚えてもよさそうだ。
 npm runコマンドは性質上、一度インストールしなければいけない。インストールするということは使う頻度に関係なく依存パッケージが肥大化してしまう
 そこまで使わないコマンド、依存パッケージに列挙するほどでもないコマンドを実行したい場合はnpxコマンドで呼び出そう
 npmバージョンが7以降ならnpm execコマンドがnpxのアイリアスとしてあるらしい。

 

参考リンク

npmおよびnpxの公式ドキュメント

 https://docs.npmjs.com/

後悔パッケージ検索用のwebサイト 

https://www.npmjs.com/

 

Eslint

 EslintはJavaScriptの静的解析ツールで、構文の誤り(シンタックスエラー)を検出するために使われる

 設定は手動で記述も可能だが、自動生成も可能。npx eslint --initで自動生成が走り、いくつかの質問に答えるだけでファイルが自動生成される。

 .eslintrc.jsファイルに各種設定が格納される

 

envフィールド

 これ以降は.eslintrc.jsのフィールドの話。

 envフィールドはJavaScriptの実行環境を指し、ブラウザやNode等複数の値を設定できる

 デフォルトではブラウザでの実行がtrueになっており、またes2021もtrueになっているためブラウザやES2021で提供されているAPI各種が使用できる。
 設定可能なすべての値のリストは公式ドキュメント参照。

https://eslint.org/docs/user-guide/configuring/langage-option#specifying-environments

 

extends

 extendsフィールドは継承する他の設定ファイルの記述が行える

 ESLintは複数の設定ファイルを持てる上、それらの設定をマージして使用できる。

 実際に継承するファイルは、ローカルファイルへのパスか、共有設定を指定する

 またextendsに設定したい共有設定はローカルへインストールされている必要がある。


 デフォルトではeslintの推奨ファイルが指定してあり、ここにReactの推奨ファイルを追加するとしよう。
 その場合"plugin:react/recomend"と記述することで、reactの推奨設定ファイルが共有される。

 

 npmで公開されている設定ファイルはeslint-config-が名前の頭についており(プレフィックス)、様々なファイルが公開されている。

 このプレフィックスは省略可能なため、先の例のreactの前にはプレフィックスがない訳だ。

 また設定ファイルの中で共有したい設定をスラッシュの後に記述する必要がある。詳しいことは分からないが、recommended(推奨)でよさそう?

 詳しくはESLintの開発者ガイドを参照とのことらしい。

https://eslint.org/docs/developer-guide/working-with-plugins#configs-in-plugins

 

parseOptions

 ESLintはデフォルトではES5までしかパース(文字列変換、だよな?)できない。と書いてあるけど現状ecmVersion : latestとなっているため最新版まで勝手にパースしてくれそう
 パースの設定を記述するフィールドなことには変わらない。

 より新しい構文やJSXなどをパースするためにはこのフィールドに適切な設定を記述する必要がある

 一応注意だが、ReactのパースとJSXのパースは別設定なので気をつけよう。

 またECMAScriptの構文パースとAPIのパースも別。これらは別途設定しよう。

 読み込む構文やAPIはどこまで新しいのを対応しますか?ということなのだろう

 

plugins

 ESLintはデフォルトではJSをパース(とチェック?)するだけ。つまるところここ(extendsフィールド)に何かを記述しないとReactなどをチェックしてくれない
 よってJS以外(Reactなど)のチェックをするかどうかの場所。

 

 手動で記述もできるが、ルールが定義されたプラグインを使用できる

 npmで公開されたプラグインにはeslint-plugin-のプレフィックスがある。extensでの共有設定と同じくこれを省略して記述できる。

 デフォルトではReactを使うと答えたためか、reactが記述されている。プレフィックスが省略されているが、ちゃんと記述するとeslint-plugin-reactとなる。

 またローカルにインストールされている必要があるため注意。

 

rules

 ここにはルール名とその設定値を記述する。

 設定値はoff(または0)で無効化、warn(もしくは1)で抵触した警告は出すが処理は続行、error(もしくは2)で抵触した場合エラーを出力し処理を中断、となる。
 デフォルト出力の段階ではこのrulesは空だが、extendsで外部ファイルを継承しているため、それをそのまま使用している。

 extendsで継承したファイルの設定以外を追記するところ、といったところなのかもしれない。
 継承した設定の上書きなどもできる。

 

実行と.eslintignore

 チェックはよく使うのでpackage.jsonのscriptsフィールドに記述しておいても良いだろう。
 サンプルでは"lint" : "eslint ."と事前に定義している。
 npm run lintを打てば、npx eslint .と同じ処理が実行される、というわけだ。

 gitなどもそうだが、パラメータに「.」と渡すことでカレントディレクトリ配下の各ファイル(ESLintの場合はJSファイルだが)が対象となり処理が実行される。

 git同様、特定ファイルを処理対象から除外できる。.eslintignoreファイルでそれらの設定は管理。

 また構文チェックと共にユニットテストも行う場合もあるらしい。複数処理はscriptsフィールドに&&で複数のコマンドを実行するように定義するっぽい。

 

参考リンク

ユーザーガイド

https://eslint.org/docs/user-guide/

開発者ガイド

https://eslint.org/docs/developoer-guide/

 

 本日の備忘録はこんな感じ。

 本書の付録はあとPrettierとwebpack、babelとあるが、これらを使えてもあくまでフロントエンドのコーディングのツールをある程度理解したに過ぎない。

 CSSメタ言語などもあるし、フレームワークのNextだって本書では触りしかやらないし、実際になんのライブラリが有用でどう使えてそれらは商用利用できるかどうかと知るべきことはたくさんある。

 良くも悪くもネットで人がつながる時代、技術は日進月歩で進む。HTMLやCSS、JSだって自分は多少理解しているが、こうしているうちにも段々と新機能が開発され、標準化されていく。
 付随するものと分野が多い、多いが、こうやってちょっとずつ知見を増やしていきたい。
 如何せんインプットも早いほうではなかったのにこうやってアウトプットまでやると時間が本当になくなる。

 効率化しないといけない。