地方でリモートワーク

リモートワーク、プログラミング、エンジニア、地方

Remix v2をReact Router v7にUpgradeしました!

Remix v2で開発しているアプリをReact Router v7にUpgradeしました!

Upgradeのガイドが用意されているのでこのとおりにやれば大丈夫なのですが、 少しつまづいてしまったのでメモです。

reactrouter.com

ほとんどの修正をcodemodというライブラリを使って自動で修正できます。 そのため非常に楽にUpgradeできました。

codemod.com

前提

ちなみに私が開発しているアプリは、 サーバーのプロセスに定期バッチを仕込むために RemixデフォルトのRemix App Serverから Expressに変更しています。 いちおう情報として載せますが、 これによってUpgradeでつまづいたわけではありません。

またWSL2環境で作業しています。

Feature Flagを使用する

まずはガイドの手順のとおり、Feature Flagを有効にします。 これは手作業でやらなければならないようです。

reactrouter.com

codemodで自動で修正する

大量の修正が自動で入るので、あらかじめgit commitしておきましょう。

codemodをつかってパッケージの更新とインポートの更新を自動で行います。

reactrouter.com

codemod.com

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はシンプルで使いやすいので、今後の追加機能もとても楽しみです。