Remix v2で開発しているアプリをReact Router v7にUpgradeしました!
Upgradeのガイドが用意されているのでこのとおりにやれば大丈夫なのですが、 少しつまづいてしまったのでメモです。
ほとんどの修正をcodemodというライブラリを使って自動で修正できます。 そのため非常に楽にUpgradeできました。
前提
ちなみに私が開発しているアプリは、 サーバーのプロセスに定期バッチを仕込むために RemixデフォルトのRemix App Serverから Expressに変更しています。 いちおう情報として載せますが、 これによってUpgradeでつまづいたわけではありません。
またWSL2環境で作業しています。
Feature Flagを使用する
まずはガイドの手順のとおり、Feature Flagを有効にします。 これは手作業でやらなければならないようです。
codemodで自動で修正する
大量の修正が自動で入るので、あらかじめgit commitしておきましょう。
codemodをつかってパッケージの更新とインポートの更新を自動で行います。
npx codemod remix/2/react-router/upgrade
しかしここでエラーが発生しました。
Error: ENOENT: no such file or directory, scandir '/home/user/.codemod'
どうやらcodemodはホームディレクトリ以下に.codemod
ディレクトリを作成しておく必要があるようです。
$ mkdir $HOME/.codemod
上記コマンドでディレクトリを作成します。
気を取り直して再度コマンドを実行してみると以下の警告が出ました。
Error: libsecret-1.so.0: cannot open shared object file: No such file or directory Codemod CLI uses "keytar" to store your credentials securely. Please make sure you have "libsecret" installed on your system. Depending on your distribution, you will need to run the following command Debian/Ubuntu: sudo apt-get install libsecret-1-dev Fedora: sudo dnf install libsecret Arch Linux: sudo pacman -S libsecret
codemod は、ユーザーの認証情報を安全に保存するために「keytar」というモジュールを使用しています。
このモジュールは内部で libsecret を必要とします。
しかし、システムにこのライブラリがインストールされていないため、エラーが発生しているようです。
この警告を解消するために以下のコマンドでlibsecretをインストールしました。
sudo apt-get install libsecret-1-dev
しかし、これをインストールしてしまうとno such file or directory
エラーでコマンドが実行できなくなってしまいました。
エラー情報もこれだけで、にっちもさっちもいかなくなってしまいました。 ワークアラウンドとしてDockerでコンテナを立てて、コンテナ内でlibsecretをインストールせずにcodemodを実行しました。
react-routerとreact-router-domのバージョンの互換性修正
修正が完了したのでサーバーを起動してみたところ、 以下のようにreact-routerとreact-router-domの互換性がないためエラーが発生しました。
✘ [ERROR] No matching export in "node_modules/react-router/dist/development/index.mjs" for import "UNSAFE_logV6DeprecationWarnings" node_modules/react-router-dom/dist/index.js:13:36: 13 │ import { UNSAFE_mapRouteProperties, UNSAFE_logV6DeprecationWarnings, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, Router, UNSAFE_useRoutesImpl, UNSAFE_NavigationC... ╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ✘ [ERROR] No matching export in "node_modules/react-router/dist/development/index.mjs" for import "UNSAFE_useRoutesImpl" node_modules/react-router-dom/dist/index.js:13:134: 13 │ ...nWarnings, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, Router, UNSAFE_useRoutesImpl, UNSAFE_NavigationContext, useHref, useResolvedPath, useLocation, useNavig... ╵ ~~~~~~~~~~~~~~~~~~~~ ✘ [ERROR] No matching export in "node_modules/react-router/dist/development/index.mjs" for import "UNSAFE_useRouteId" node_modules/react-router-dom/dist/index.js:13:246: 13 │ ...tionContext, useHref, useResolvedPath, useLocation, useNavigate, createPath, UNSAFE_useRouteId, UNSAFE_RouteContext, useMatches, useNavigation, useBlocker } from 'react-ro... ╵ ~~~~~~~~~~~~~~~~~ ✘ [ERROR] No matching export in "node_modules/react-router/dist/development/index.mjs" for import "AbortedDeferredError" node_modules/react-router-dom/dist/index.js:14:9: 14 │ export { AbortedDeferredError, Await, MemoryRouter, Navigate, NavigationType, Outlet, Route, Router, Routes, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext, UNSAFE_L... ╵ ~~~~~~~~~~~~~~~~~~~~ ✘ [ERROR] No matching export in "node_modules/react-router/dist/development/index.mjs" for import "UNSAFE_useRouteId" node_modules/react-router-dom/dist/index.js:14:237: 14 │ ...text, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, UNSAFE_useRouteId, createMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromE... ╵ ~~~~~~~~~~~~~~~~~ ✘ [ERROR] No matching export in "node_modules/react-router/dist/development/index.mjs" for import "defer" node_modules/react-router-dom/dist/index.js:14:340: 14 │ ...reateMemoryRouter, createPath, createRoutesFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redi... ╵ ~~~~~ ✘ [ERROR] No matching export in "node_modules/react-router/dist/development/index.mjs" for import "json" node_modules/react-router-dom/dist/index.js:14:383: 14 │ ...sFromChildren, createRoutesFromElements, defer, generatePath, isRouteErrorResponse, json, matchPath, matchRoutes, parsePath, redirect, redirectDocument, renderMatches, rep... ╵ ~~~~
いったんreact-routerとreact-router-domをuninstallしてlatestをインストールすることでエラーを解消しました。
$ npm uninstall react-router react-router-dom $ npm install react-router@latest react-router-dom@latest
これで無事起動できました!
まとめ
Remix v2でアプリを開発して1か月程度しか経過していないのに、 すぐにReact Router V7にUpgradeしなければならなかったので、 「これが今後も続くのか..」と思っていました。 これくらい簡単にUpgradeできるならよいですね。 Remixはシンプルで使いやすいので、今後の追加機能もとても楽しみです。