4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

弥生Advent Calendar 2021

Day 12

Reactのコンポーネントライブラリの開発では、ライブラリの依存関係の指定に気を付けなければいけないという話

Last updated at Posted at 2021-12-11

はじめに

Reactのコンポーネントライブラリを初めて開発しました。
今回はライブラリの依存関係で少し詰まった際に調べた内容を中心にお話しします。

コンポーネントライブラリ開発で参考にした記事

以下の記事を参考に作成しました。大変分かりやすかったです。

コンポーネントライブラリ開発プロジェクトの構成

  • この後の説明をスムーズにするために、プロジェクトの構成を記載しておきます。
root
├ sample-app (動作確認用プロジェクト)
│   ├ src
│   │ └ index.js
│   └ package.json
└ palette-component (コンポーネントライブラリプロジェクト)
    ├ src
    │ ├ canvas.tsx (ライブラリに含めるコンポーネント)
    │ ├ palette.tsx (ライブラリに含めるコンポーネント)
    │ └ index.tsx (コンポーネント参照用ファイル)
    └ package.json

コンポーネントライブラリ開発で詰まったポイント

動作確認中にReactからエラーで怒られてしまう

  • 以下の手順で動かしている際に、突然Reactからエラーで怒られてしまいました。
  1. palette-componentプロジェクトを編集してビルド
  2. sample-appプロジェクトにpalette-componentのビルドを参照させて、コンポーネントライブラリを呼び出すように実装
  3. sample-appプロジェクトを起動
  • 以下のエラーが出て怒られてしまいました・・・・。
 Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
  • エラーが出たタイミングとしては、palette-componentプロジェクト側でuseStateを使い出したタイミングでした。

エラーが出た原因

  • palette-componentプロジェクトと、sample-appプロジェクトはそれぞれのnode_modules内のReactを参照していました。
root
├ sample-app (動作確認用プロジェクト)
│   ├ src
│   │ └ index.js ((1)のreactを参照しながら、(2)のreactを参照しているCanvasコンポーネントとPaletteコンポーネントを呼び出す)
│   ├ node_modules
│   │ └ react (1)
│   └ package.json
└ palette-component (コンポーネントライブラリプロジェクト)
    ├ src
    │ ├ canvas.tsx ((2)のreactを参照しながら、Canvasコンポーネントを提供する)
    │ ├ palette.tsx ((2)のreactを参照しながら、Paletteコンポーネントを提供する)
    │ └ index.tsx 
    ├ node_modules
    │ └ react (2)
    └ package.json
  • sample-appには、自身が持っているReactとpalette-componentが持っているReactの2つが含まれてしまったため、「フックへのルール違反:重複した React のコピー」となってしまったようです。
  • sample-appで呼び出す際は、Canvasコンポーネントも、Paletteコンポーネントも(1)のreactを参照して動くようになっていないとエラーが出て正常に動かすことができないようです。

解決方法

  • 以下の記事を参考に解決しました。

  • sample-appプロジェクトが参照しているnode_modulesのreactreact-domnpm linkコマンドを叩き、palette-componentプロジェクトでnpm link reactnpm link react-domコマンドを叩くことで、sample-appプロジェクトとpalette-componentプロジェクトが参照するReactを統一することができます。

    • 私はyarnを使っているため、「yarn link」コマンドを使って解決しました。

ライブラリの依存関係にご注意!

コンポーネントライブラリを開発している際、パッケージの依存関係についてあまり意識せず開発を進めていました。そのため以下のような状態でした。

  • palette-componentプロジェクトのpackage.jsonのdependenciesにreactreact-domが入っている
package.json
"dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
  }

この状態だとライブラリを呼び出すプロジェクトは以下のような構成になるため、ライブラリを使う人が私と同じ苦しみを味わうことになります。

some-app (ライブラリを呼び出すアプリ)
  ├ src
  │ └ index.js ((1)のreactを参照しながら、(2)のreactを参照しているCanvasコンポーネントと、Paletteコンポーネントを呼び出す)
  ├ node_modules
  │ ├ react(1)
  │ └ simple-palette-component ((2)のreactを参照しながらCanvasコンポーネントとPaletteコンポーネントを提供するライブラリ)
  │   └ node_modules
  │     └ react(2)
  └ package.json

今回は開発中にエラーが出たのでたまたま気がつく事が出来ましたが、ライブラリのように、他のプロジェクトから参照することを前提としている場合は特に依存関係には気をつけたほうが良さそうですね。

今回の件でかなり反省した私は、package.jsonで定義できる依存関係の定義について、改めてnpmが公式にまとめているものを見てみることにしました。
 

dependencies

依存関係のあるパッケージをバージョンを指定する事ができるみたいですね。
太字で「開発中だけに使うものはここに置くなよ」って書いてありますね。ゴメンナサイ。

devDependencies

開発中にのみ使用し、自分が作ったモジュールを誰かが使う際は不要である依存関係のあるライブラリ等を記載する場所みたいですね(テストツールとか)。
対象となるパッケージのルートフォルダでnpm linkとかnpm installを叩くことで代替が可能とも書いてあります。なるほど。

peerDependencies

「このモジュールを使う際は、このpeerDependenciesのライブラリ・ツールが使われる前提ですよ。」ということを示すためのものらしいです(難しい・・・。)。
npmのバージョンによって挙動が変わるらしく、npmのバージョン3~6ではpeerDependenciesは自動ではインストールされない仕様でしたが、npmのバージョン7からは自動でインストールされる仕様に変わったようです。
peerDependenciesに指定するライブラリやツールのバージョンの指定はある程度幅を持たせることを推奨していますね。
パッケージを公開したりしない限りはあまり使わない印象です・・・ということは、今回は関係ありそうですね。

(他にもpeerDependenciesMetaとか、optionalDependenciesとかありますが・・・今回は割愛させていただきます・・)

Reactのコンポーネントライブラリの依存関係はどう定義すべきか

  • 今回の場合、どう依存関係を解決すればよいのか・・ちょっと考えてみることにしました。

    • reactとかreact-domはインストール先のメインのプロジェクトが参照するnode_modules内のものを参照したい
      • useStateを使うので、Reactのver.16.8.0以降を使用してほしい
    • ただ、コンポーネントライブラリ開発中はテストもしたいので、開発環境でもreactとかreact-domを使わないわけではない
  • うーん、なんとなくこうじゃないかなぁ・・・

package.json
"devDependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
  }
"peerDependencies": {
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0",
  }

React周りはだいたい同じですね。

(本当は有名なコンポーネントライブラリがどうしているかを参考にして、自作コンポーネントライブラリのpackage.jsonがどうあるべきかを考えたのはここだけの話です。)

まとめ

  • いつもはコンポーネントライブラリを活用してWebアプリの開発をすることが多かったので、ライブラリの依存関係についてあまり考えることはありませんでした。これからは、前よりライブラリの依存関係には気を付けて開発することができそうです!

おまけ

palette2.gif

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?