気になっているフロントエンドのエコシステムに触れる
pnpm
メモ
高速に動作する理由。
- 異なるバージョンのパッケージに依存している場合は、更新されたファイルのみがストアに追加されます。たとえば、100 個のファイルがある依存において、 新しいバージョンがそれらのファイルのうち 1 つだけに変更を加えた場合、 pnpm update は存関係全体を複製するのではなく、ストアにその新しいファイルのみを加えます。
- すべてのファイルは、ディスク上の 1 つの場所に保存されます。 パッケージが インストールされると、そのパッケージのファイルは 1 か所からハードリンクされ、追加のディスク領域を消費しません。 これにより、同じバージョンの依存をプロジェクト間で共有できます。
-
node_modules/.pnpm/
配下にパッケージの実態がまとまっている。(参考)- あるパッケージをインストールしたときに、npm ならそのパッケージの依存パッケージが
node_modules/
直下にフラットに展開される。 - pnpm では
node_modules/.pnpm/
に依存パッケージが展開され、node_modules/
直下は追加したかったパッケージのみが展開される。- また、
node_modules/
直下に展開されるパッケージはnode_modules/.pnpm/
配下の実態へのシンボリックリンクになっている。(参考)
- また、
- あるパッケージをインストールしたときに、npm ならそのパッケージの依存パッケージが
- pnpm の厳格さの理由
- Node.js v16.13 からパッケージマネージャーのバージョン管理をする Corepack が提供されているので pnpm のバージョン管理に利用する。
- npm, yarn との比較
-
よく利用するコマンドの対応表
-
npm ci
はpnpm i --frozen-lockfile
?
-
- package.json で
pnpm.overrides
を指定すると全てのパッケージが同じバージョンの依存パッケージを使うように強制したりできる。(リファレンス) - ワークスペースプロトコル(
workspace:
)で指定されたパッケージは必ずローカルで解決される。(リファレンス) -
pnpm --filter ${packageName}
で指定のパッケージに対してコマンドを実行できる。-
web
パッケージのdev
コマンドを実行。$ pnpm --filter web dev
-
ui
パッケージにreact
を追加。$ pnpm add --filter ui
- ルートパッケージから
babel-loader
を削除。(-w
オプション)$ pnpm rm -w babel-loader
-
.npmrc
-
enable-pre-post-scripts=true
を指定しないと pre, post のプレフィックスが付与されたスクリプトを実行しない。 -
hoist
- 依存を
node_modules/.pnpm
に巻き上げるかの設定。
- 依存を
-
hoist-pattern
- どのパッケージを
node_modules/.pnpm
に巻き上げるかの設定。デフォルトは全てのパッケージ。
- どのパッケージを
-
public-hoist-pattern
- どのパッケージを
node_modules
に巻き上げるかの設定。デフォルトは['*eslint*', '*prettier*']
のパッケージ。 - eslint, prettier, storybook などの多くの依存があるパッケージのパターンを指定することで、依存をすべて package.json に記述しなくても、依存を解決してくれる。
- storybook の addon は種類が多く全てインストールすると管理が面倒なのでパターンを追加しておくと良さそう。
.npmrcpublic-hoist-pattern[]=@storybook/addon-*
- どのパッケージを
-
shamefully-hoist
-
shamefully
は「不名誉な方法で、または、不名誉な程度の。」という意味らしいので、あまり望ましくないオプションっぽい。 - 以下の2つに違いがあるのか?(おそらく大きく異ならない)
-
turborepo
特徴
- JavaScript / TypeScript の高性能なビルドシステム
- 特徴
- 差分ビルド
- コンテンツをハッシュにして差分があるか検証する
- 並列実行、CPUがアイドル状態にならないように
- ランタイム、ソースコードに干渉しない
- プラガブルなアーキテクチャで良いと思った
- タスクの依存関係をパイプラインとして定義できる
- リモートにキャッシュを配置することも可能
設定
チュートリアルから移植するのがイメージしやすいためやってみる
$ npx create-turbo@latest
メモ
monorepo
特定の技術ではないが monorepo について書く。
メモ
- フロントエンドの設計をしっかり考えなければいけなくなるので難しい。
- ビルド、テスト、Lint の設定が複雑になる。
- 色々新しい技術に触れるのは楽しい。
TypeScript, ESLint
-
@
から始まる alias の設定を tsconfig.json に定義して vite, eslint からは tsconfig.json の設定を参照してパスを解決するようにする。
要確認
eslint-plugin-import
no-unresolved
Q. package.json の export
は .
以外は実態と異なるパスを指定するパスが解決できず ESLint エラーが発生する?
{
...
"exports": {
".": "./dist/index.js", // OK
"./dist/*": "./dist/*", // OK
"./lib/*": "./dist/*" // NG
}
...
}
A. 実行時は動作するが、ESLint のプラグイン eslint-plugin-import の対応が追いついていないためエディターではエラーが表示される。
vite でアプリケーションを起動して ESLint のプラグインも導入しているがなぜ実行時はエラーにならず動作するのか不明。
参考:https://github.com/import-js/eslint-plugin-import/issues/2389
peerDependencies
monorepo の構築やライブラリの開発を今までしてこなかったので、あまり知らなかった。
npm のドキュメントの翻訳を見ても分からなかったのでこちらの記事で理解した。
必要になるのは「プラグインモジュール」と「シングルトンモジュール」として扱う場合。
- プラグインモジュール
- 単体では機能せず、メインとなるパッケージのインストールが必須であることを明示したい場合。
- シングルトンモジュール
- あるモジュールがアプリケーション全体で一つであるようにしたい場合。
- pnpm では peerDependencies を依存関係のセットごとにインストールする?
指定した項目の peerDependencies が存在しなくても警告を無視する。
{
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": ["@babel/*", "@eslint/*"]
}
}
}
lint-staged の設定ファイルは string
, string[]
のいずれかで記述すると、デフォルトでコマンドの後ろにコミットされたファイルパスの一覧がスペース区切りで追加されるように見える。
ファイルパスの一覧を追加したくない場合は関数で記述すれば良い。
pnpm の機能で eslint を public-hoist しないと VSCode の ESLint 拡張機能が動作しないことがあるので、eslint 関連は public-hoist した方が良さそう。
VSCode の ESLint の出力を見ると依存パッケージが見つからないなどのエラーが表示されていた。
tsup
- セットアップに手間がなく開発体験が良かった。
- (体感だが)動作も高速だった。