Comments
Loading Translate Section...Loading Comment Form...
Loading Comment Form...
このWebサイト、『記事もコメントも自動で翻訳される多言語コミュニティEvame』のメタフレームワークをRemixからNext.jsに移行し、インフラもRenderからVercelへ移行しました。This website, ‘Evame,’ a multilingual community with automatic article and comment translation, migrated its meta-framework from Remix to Next.js, and its infrastructure from Render to Vercel.
2週間ほどかけての大掛かりな移行でしたが、結果には満足していて、「小〜中規模なサイトならRemix / React Router、大規模なサイトならNext.jsを選ぶ価値が大いにある」という結論に至りました。It was a large-scale migration that took about two weeks, but I'm satisfied with the results. I've concluded that Remix/React Router is a great choice for small-to-medium-sized sites, while Next.js is highly valuable for larger-scale projects.
この記事では、RemixからNext.jsへの移行についてや、RemixとNext.jsの個人的な比較について書きます。どっちを使うか悩んでいる人や、移行を考えている人はぜひ読んでください!This article details the migration from Remix to Next.js and provides a personal comparison of the two frameworks. If you're struggling to choose between them or are considering a migration, please read on!
サイト方針の変更と規模の拡大Changes in Site Policy and Expansion of Scale
当初Evameは、青空文庫やプロジェクト・グーテンベルク、過去の仏典と言ったpubllic domainのテキストに対訳を付与したくて始めました。しかし開発を進めるうちに、public domainのテキストだけではなくユーザが投稿した記事にも対訳を付与できるようにしたいと考えるようになりました。そもそもEvameを作り始めた目的は知識と物語の循環であり、そのためにはユーザーが記事を投稿できるシステムが必要不可欠だと考えたからです。この方針の変更によってサイトの規模が拡大し、必要な機能が増え、大きなエコシステムを持つNext.jsに惹かれるようになりました。Initially, Evame was started to provide translations for public domain texts such as those from Aozora Bunko, Project Gutenberg, and old Buddhist scriptures. However, as development progressed, we decided to expand the translation capabilities to include user-submitted articles as well. The fundamental goal of Evame is the circulation of knowledge and stories; a system allowing users to post articles is essential to achieve this. This policy change led to an expansion of the site's scale and the need for increased functionality, drawing us to Next.js's robust ecosystem.
Remixの今後の不明瞭さUncertainty Regarding the Future of Remix
2024/11/22、Remix v2はReact Router v7とマージされました。https://remix.run/blog/react-router-v7On November 22, 2024, Remix v2 merged with React Router v7. https://remix.run/blog/react-router-v7
Remixは消え、React Routerとして続いていくのかと思っていましたが、上記ブログの著者でもあるCo-FounderがTwitterで、次はRemix v3になるという発言をしています。I initially thought Remix would disappear and continue as React Router, but the Co-Founder, also the author of the above blog post, stated on Twitter that the next version would be Remix v3.
https://x.com/mjackson/status/1870288212339634235https://x.com/mjackson/status/1870288212339634235
名前の変更はエコシステム全体に変化を余儀なくさせる大きなものです。実際、別のプロジェクトでRemix v2からReact Router v7へアップデートしたのですが、Remix関連の各種ライブラリが使えなくなり、多くの対応が必要で結構な工数がかかりました。再度名前の変更で同様の対応を迫られる可能性もあり、そうすると今回アップデートしてもまた使えなくなるライブラリが多く出るかも、といった不安がありました。A name change is a significant event that forces changes across the entire ecosystem. In fact, in another project, updating from Remix v2 to React Router v7 resulted in numerous Remix-related libraries becoming unusable, necessitating extensive adjustments and considerable work. There was concern that a repeated name change could lead to a similar situation, potentially rendering many libraries unusable again despite the current update.
React と Next.js の緊密化Closer Integration of React and Next.js
https://nextjs.org/blog/next-12https://nextjs.org/blog/next-12
ReactとNext.jsは、上記の記事にもあるようにどんどん連携を深めており、Next.jsは他のフレームワークよりも先行して多くの技術を使用しています。As indicated in the article above, React and Next.js are becoming increasingly integrated. Next.js is ahead of other frameworks in adopting many new technologies.
RSCがNext.jsでリリースされたのは2023年でもう2年近く経っているのに、まだRSCを使えるフレームワークがほとんどないことがその証明です。The fact that few frameworks support RSC, even though it was released in Next.js in 2023, almost two years ago, is evidence of this.
今後も優先的に新機能を実装できるだろう点は大きなアドバンテージだと感じました。The ability to implement new features preferentially is a significant advantage.
React 19がフルに活用できるFull Utilization of React 19
Remix / React Router v7 だと、route modulesの loader / action でデータを扱うため、コンポーネントとデータ部分が分離しがちでした。
Next.js(App Router)ではRSC (React Server Components) や Server Actions 、useActionState等を活用することで、コンポーネントとデータの距離が縮まり、開発生産性が向上しました。また、コロケーションに基づいたディレクトリ構成がRemixより行いやすくなった点も開発生産性の向上に繋がりました。With Remix/React Router v7, data handling in route modules' loaders/actions often led to a separation between components and data. Next.js (App Router), utilizing RSC (React Server Components), Server Actions, useActionState, etc., reduces the distance between components and data, improving development productivity. The ease of implementing a directory structure based on colocation, compared to Remix, also contributed to improved development productivity.
豊富なエコシステムRich Ecosystem
Next.jsの場合、Sentry、Supabase、Stripe など多くのサービスの公式例があり、周辺ライブラリも充実しています。next/font や next/image も素晴らしく、これによってLight HouseのPerformanceが100点になり、Best Practicesも100点になりました。Next.js boasts official examples for many services such as Sentry, Supabase, and Stripe, along with a comprehensive set of peripheral libraries. next/font and next/image are excellent, resulting in a perfect Lighthouse Performance and Best Practices score of 100.
移行前は以下の点数だったので、エコシステムの力を大いに感じています。(Accessibility頑張ります。)Given the scores before the migration, the power of the ecosystem is undeniable. (We will work on Accessibility!)
AIフレンドリーAI-Friendly
ClaudeやGPTに、Remixで書いてと指示を出してもNext.jsのコードを吐いてくることがよくありました。ユーザが多い分、Next.jsの場合最初から使えるコードを出してくれる割合が増えたと感じます。これもAI時代の新たなエコシステムと呼べるかもしれません。When instructing Claude or GPT to write code in Remix, it often generated Next.js code. Due to the large user base, Next.js seems to have a higher likelihood of providing directly usable code. This might be considered a new ecosystem for the AI era.
ビルドが遅いSlow Build Times
Remix は HMR が速く、ローカル開発が非常に快適でした。Next.js はファイルによってはビルドに数秒かかり、時にはリロード必須になるなど、開発体験としてはストレスがあります。Remix's HMR is fast, making local development incredibly smooth. Next.js, however, can take several seconds to build certain files, sometimes requiring a full reload, creating a stressful development experience.
メンタルモデルの複雑さComplexity of Mental Model
Remixのメンタルモデルは、loader→component→actionというシンプルでわかりやすい流れでした。Remix's mental model is simple and clear: loader → component → action.
Next.jsの場合、RSC/Server Actions/revalidatePath/revalidateTag/next/dynamic/Request Memoizationなど様々な概念が登場します。最適化されたことでLighthouseのスコアは上がりましたが、体感ではRemixの時と速度に差はありません。ユーザとしては体感速ければどうでもいいので、勝手に速くなるようにしてほしいという感想です。Next.js introduces various concepts such as RSC/Server Actions/revalidatePath/revalidateTag/next/dynamic/Request Memoization. Although optimization improved Lighthouse scores, the perceived speed doesn't feel much different from Remix. As a user, perceived speed is all that matters; I wish it could automatically optimize for speed.
黒魔術Black Magic
Remixの吐くhtmlは非常にシンプルでした。書いたものがそのまま出力されているという感じで、把握しやすかったです。The HTML generated by Remix was very straightforward and easy to understand, mirroring the code written.
Next.js はフレームワーク独自のロジックでclassNameやcanvasタグが差し込まれていたり、デバッグが複雑です。また、Edge Runtimeと絡んで、ローカルでは動くのに本番だと動かない問題にも遭遇しがちです。Next.js inserts framework-specific logic, such as className and canvas tags, making debugging complex. Issues where code works locally but fails in production are common, often related to the Edge Runtime.
最初にブランチを切ってcreate next し、ライブラリの移行から始めました。具体的には以下のライブラリを移行する必要がありました。We started by creating a new branch with `create next` and migrating libraries. The following libraries needed to be migrated:
remix-auth → auth.jsremix-auth → auth.js
react-i18next → next-intlreact-i18next → next-intl
remix-auth → auth.jsの変更には、DBスキーマの対応とORMとして使っているPrismaのEdge Runtime対応が必要で、移行全体の中でもここが一番大変でした。The change from remix-auth to auth.js required adjustments to the database schema and Prisma's Edge Runtime compatibility, proving to be the most challenging part of the migration.
DBスキーマはauth.js側に合わせたスキーマを用意し、既存データをマイグレーションし、カスタマイズを減らすことでアップデート時のリスクを抑えました。A new schema compatible with auth.js was created, existing data was migrated, and customization was minimized to reduce update risks.
Edge Runtimeは、Prisma Accelerate はまだ事例が少なく、ローカルと本番の差異が大きそうで懸念があり、Drizzle への移行は自由度が高い一方で工数が大きいので、結果、Neon + Prisma を選択して最小限の工数に留めました。For Edge Runtime, Prisma Accelerate lacked sufficient examples, and the difference between local and production environments was concerning. While migrating to Drizzle offered greater flexibility, it would have been significantly more work. Therefore, Neon + Prisma was chosen to minimize effort.
次に、既存の Remix のルーティングや loader / action 部分を、Next.js App Router での RSC / Server Actions に置き換えました。
ここではAIが非常に役に立ちました。と言ってもuseActionStateやServer ActionはまだAIには書けないので自力で頑張る必要があります。Next, the existing Remix routing and loader/action components were replaced with Next.js App Router's RSC/Server Actions. AI was very helpful here; however, useActionState and Server Actions still require manual work.
Server Actions に共通ロジックを持たせない工夫Avoiding Shared Logic in Server Actions
すべての Server Actions が外部公開されるため、認証コードをいちいち書く必要があります。できるだけ認証ロジックをまとめた関数や、Middleware で対応できないか検討しましょう。Since all Server Actions are publicly accessible, authentication code is necessary. Consider whether authentication logic can be consolidated into functions or handled with middleware.
RSC コンポーネントのテストTesting RSC Components
RSC は 現状テスト手法が確立されていないので、ビジネスロジックや認証ロジックを分け、Unit テスト可能にするのがおすすめです。Testing methodologies for RSC are not yet well-established. Separating business logic and authentication logic to allow for unit testing is recommended.
useActionState の型付けTyping useActionState
useActionStateの返り値に型情報を付与する仕組みはまだ確立されていません。自前で定義するのが現状ベターです。個人的には以下のようにしています。(about_hiroppyさんのtweetを参考にしています。)A mechanism for adding type information to the return value of useActionState is not yet established. Defining it manually is currently the best approach. Personally, I do it like this (referencing a tweet by @about_hiroppy).
export type ActionResponse<T = void, U = Record<string, unknown>> = {
success: boolean;
message?: string;
data?: T;
zodErrors?: typeToFlattenedError<U>["fieldErrors"];
};
form の型検証Form Validation
Server Action 内でバリデーションするといいです。個人的にはzodで以下のようにしています。It's best to perform validation within the Server Action. I personally use zod as follows:
const editPageContentSchema = z.object({
slug: z.string().min(1),
title: z.string().min(1).max(100),
pageContent: z.string().min(1),
});
const parsedFormData = editPageContentSchema.safeParse({
slug: formData.get("slug"),
title: formData.get("title"),
pageContent: formData.get("pageContent"),
});
小〜中規模のアプリSmall to Medium-Sized Applications
そこまで最新の React 機能を活用しなくても良ければ、Remix / React Router はシンプルで高速な開発体験を得やすい。メンタルモデルも明快。If you don't need to utilize the latest React features, Remix/React Router offers a simple and fast development experience with a clear mental model.
toBやSPAなら個人的にはRemix / React Router。For B2B and SPAs, I personally prefer Remix/React Router.
中〜大規模 or エコシステムを活かしたい場合Medium to Large-Scale or Leveraging the Ecosystem
Next.jsを選べばサービス・ライブラリとの連携がしやすく、将来的な React のアップデートにも先行して対応できる。Choosing Next.js facilitates integration with services and libraries and allows for proactive adaptation to future React updates.
toCやSSRをしたいならNext.js。For B2C and SSR, choose Next.js.
個人的には「リリースして伸びてきたら Next.js に移行」というアプローチも十分アリだと思います。Remix/React Routerならcloudflareを使えばコストもかなり抑えられます。ただし、移行時はやはり工数も掛かるので、将来的な拡張を見据えている場合は最初から Next.js を使う選択肢も強いです。Personally, I believe the approach of migrating to Next.js after the initial release and growth is also viable. Remix/React Router keeps costs low with Cloudflare. However, migration requires considerable effort, so choosing Next.js initially is a strong option if you anticipate future expansion.
フレームワーク、DB、インフラの移行と大掛かりな変更だったのですが、重要な部分にテストコードを書いていたことや、DB周りのコードをCQRSで分離していたことで、認証周り以外は比較的スムーズでした。改めて、コードの品質やアーキテクチャに投資することが大事だと実感しています。The migration of the framework, database, and infrastructure was a significant undertaking, but having test code in key areas and separating the database code with CQRS made the process relatively smooth, except for the authentication part. I have again realized the importance of investing in code quality and architecture.
このサイト「Evame」は、書いた記事やコメントをAIが自動翻訳してくれる多言語コミュニティです。僕もこの移行記を日本語で書き、英語圏にシェアできるようになりました。Evame is a multilingual community where AI automatically translates articles and comments. This migration allowed me to write this migration report in Japanese and share it with the English-speaking world.
もし興味があれば、ぜひ好きな言語で記事を書いて、世界中に発信してみてください!If you're interested, please write articles in your preferred language and share them with the world!
https://evame.tech/jahttps://evame.tech/ja
以上が、Remix / React Router v7 から Next.js へ移行した感想と比較、そして移行手順です。何か参考になる部分があれば嬉しいです!This concludes my thoughts and comparison of the migration from Remix/React Router v7 to Next.js, along with the migration steps. I hope this is helpful!