yarnを使ったパッケージインストール時に警告をちゃんと読んでおくと余計なトラブルを避けられる 〜react-leafletで苦労した話〜
はじめに
yarn install/add 実行中の警告表示を特に気にしていなかったことで、あとで余計な調査が発生したという経験をしたため、反省の意味を込めて記事にしました。
next.js + react-leafletを使うときに困った事例
このお話は2022/4初旬に遭遇したものですが、現在は関連パッケージの更新が完了しており、同じ状況にはなりません。
記事中のコマンド群やソースコードは記事執筆にあたり再現性があるように調整しています。
準備
とあるwebページ制作案件でページ内に地図を表示するという要件があったため、 next.js(v12.1.4) + react-leafletを利用する機会がありました。
当時やったこととしては、以下のコマンドを使いnext.jsに対してreact-leafletを追加し、ページ内に地図を埋め込んでいくというものでした。
$ npx create-next-app sample-page --typescript
# 当時はバージョン指定無しで3.2.5が入りました。状況再現のためバージョン指定のコマンドを記載。
$ yarn add leaflet react-leaflet@3.2.5
yarn addを実行したとき、実は以下のようなwarningが出ていたのですが、当時は気づくこともなく作業を進めていました。
[3/4] 🔗 Linking dependencies...
warning " > react-leaflet@3.2.5" has incorrect peer dependency "react@^17.0.1".
warning " > react-leaflet@3.2.5" has incorrect peer dependency "react-dom@^17.0.1".
warning "react-leaflet > @react-leaflet/core@1.1.1" has incorrect peer dependency "react@^17.0.1".
warning "react-leaflet > @react-leaflet/core@1.1.1" has incorrect peer dependency "react-dom@^17.0.1".
問題発生
いざreact-leafletのコンポーネントをページに埋め込んで見ると以下のエラーが表示されました。
そのときのコードは以下の通りです。
# index.tsx
import type { NextPage } from 'next'
import { useMemo } from 'react'
import dynamic from 'next/dynamic'
const Home: NextPage = () => {
const Map = useMemo(
() =>
dynamic(() => import('../components/map'), { // react-leafletはCSRでしか動かないためdynamicを使用する
loading: () => <p>loading</p>,
ssr: false
}),
[]
)
return (
<div style={{ height: '100%', width: '500px' }}>
<Map></Map>
</div>
)
}
export default Home
# components/map.tsx
import { MapContainer, TileLayer } from 'react-leaflet'
import 'leaflet/dist/leaflet.css'
function Map(): JSX.Element {
return (
<MapContainer
center={[35.689527394778, 139.6894541598]} // 新宿中央公園を表示する
zoom={15}
scrollWheelZoom={false}
style={{ width: "300px", height: "300px" }}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://tile.openstreetmap.jp/{z}/{x}/{y}.png"
/>
</MapContainer>
)
}
export default Map
エラーには「Map container is already initialized」とあるので、Mapコンポーネントが2回以上レンダリングされているように見えますが、
なぜそうなっているのか、はじめは分かりませんでした。
加えて、yarn dev
だとエラーとなるのですがyarn build && yarn start
の場合はエラーとならず地図が表示されていました。
謎は深まるばかり。。。
解決までにやったこと
- mapコンポーネントにconsole.logを差し込む
=> console.logが2回実行されているため、mapコンポーネントが2回レンダリングされているのは確定。 - dynamicの書き方が悪くて複数回コンポーネントが表示されてしまっている?
=> 先人の知恵をググったりstackoverflowなどでも調べたが、どうやらこの書き方は正しそう。。 - 試しにHomeコンポーネントにもconsole.logを差し込む
=> ここでもconsole.logが2回実行されている。ってことは、next.js自体が全てのコンポーネントを2回レンダリングするようにできている?と推測。 - next.jsの機能でコンポーネントを2回レンダリングする理由を調べていく
=> どうやらreactのStrictModeが原因。開発モードのみで有効となる機能であるため、本番モードならエラーにならないという事象とも合致。 -
next.config.jsのreactStrictModeをfalseに修正する(解決方法1)
=> 地図が正しく表示されるようになった! - この解決方法はあまりよくなさそうなので、react-leafletのgithubにissueが上がってないか見にいく
=> react18に対応してほしいというissueを発見 -
react-leafletのv4.0.0-beta.1の存在を知り、こっちを使ってみる(解決方法2)
=> StrictModeがtrueの状態でも地図が正しく表示されるようになった。そのうちv4の正式バージョンがリリースされるとのことだったので、これにて解決。
色々とやっているうちに3時間くらい経過していました。
最終的にはこんな感じに表示されます。
後で気付いたこと(本記事で書きたかったこと)
yarnで表示されていたwarning表示
それから1ヶ月ほど経過したある日、同リポジトリを別の開発用PCで起動させるためパッケージのインストールなどをしていたところ、記事の冒頭に貼ったyarnのwarning表示がふと目に入りました。
[3/4] 🔗 Linking dependencies...
warning " > react-leaflet@3.2.5" has incorrect peer dependency "react@^17.0.1".
warning " > react-leaflet@3.2.5" has incorrect peer dependency "react-dom@^17.0.1".
warning "react-leaflet > @react-leaflet/core@1.1.1" has incorrect peer dependency "react@^17.0.1".
warning "react-leaflet > @react-leaflet/core@1.1.1" has incorrect peer dependency "react-dom@^17.0.1".
そこには明らかに、react-leaflet@3.2.5はreact17までしか対応していないことを意味するエラーが出ていました。
もしもこれを初期段階で気付いていれば、以下の流れでスムーズに対応でき、時間をかなり節約できていたと思います。
warningを見る -> react18に対応したreact-leafletが無いかgithubを見にいく -> react-leaflet v4の存在を知る&v3で起きている問題点を認識する -> next.jsに組み込む
yarnとnpmのパッケージインストール時の挙動の違い
今回next.jsを使うにあたりyarnを使っていましたが、もしもnpmを使っていた場合以下のようになります。
$ npx create-next-app sample-page2 --typescript --use-npm
$ npm install leaflet react-leaflet@3.2.5
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: npm-src@0.1.0
npm ERR! Found: react@18.1.0
npm ERR! node_modules/react
npm ERR! react@"18.1.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.1" from react-leaflet@3.2.5
npm ERR! node_modules/react-leaflet
npm ERR! react-leaflet@"3.2.5" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/nyarome/.npm/eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/nyarome/.npm/_logs/2022-05-07T05_48_30_419Z-debug-0.log
npmの場合はパッケージの依存性に不整合がある場合エラー表示をしてくれるようです。
これだけ分かりやすく表示してくれれば、見落とすことはまずないでしょう。
まとめ
- yarnを使ってパッケージをインストールする際は警告表示が出てないかをよく見る
- 一旦放置しても大丈夫なのか、解決しないといけないのかを判断する癖をつける
- 使いたいライブラリがフレームワークの新バージョンに対応しているか導入前によく確認する必要がある
- 今回はnext.jsの新バージョンに関するものでしたが、よくある話なので注意
- 公式のissueをよく読むと大概記載されている
あとがき
最初の段階でwarningに目を通せていたら解決までの時間は節約できましたが、代わりにnext.jsのことを少し余分に学ぶことができました。
ライブラリ選定をするときの基本だと思う(やれてなかったですが)ので、考え方の参考にしていただければと思います。
Discussion