Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Remixの凄みを紹介したい
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
AijiUejima
May 26, 2022
Technology
24k
16
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Remixの凄みを紹介したい
AijiUejima
May 26, 2022
More Decks by AijiUejima
See All by AijiUejima
エッジはフロントエンドなのか? バックエンドなのか? について考えてみる
aiji42
7
6.1k
Cloudflare Workersで構築する非同期ジョブシステム
aiji42
7
3.1k
VRTツールのダークホース Lost Pixelを紹介したい
aiji42
5
3.3k
オリジンサーバに手を付けないパーフォマンス改善
aiji42
5
1.9k
Cloudflare Fonts試してみた🔤
aiji42
2
900
Hyperdrive試してみた🛸
aiji42
3
1.6k
Workers Browser Rendering API について
aiji42
0
680
VercelとNext.jsの機能を最大限に活用したA/Bテスト手法
aiji42
6
1.8k
Cloudflare WorkersとKVで キャッシュを非同期に更新する | Cloudflare Meetup Nagoya
aiji42
1
1.1k
Other Decks in Technology
See All in Technology
Claude Code の Sandbox 機能を Anthropic Sandbox Runtime(srt) で試そう!/lets-play-anthropic-sandbox-runtime
tomoki10
1
610
AGENTS.mdとSkillsで始めるAIエージェント活用
sonoda_mj
3
210
【Cyber-sec+】経営層を"動かす"ための考え方
hssh2_bin
0
190
アンオフィシャルな、オフィシャルからのお願い
wyamazak_devrel
0
110
【Snowflake Summit 2026 Recap!!】Snowflake Summit Deep Dive: Security & Governance
civitaspo
1
190
Agent Skills設計で柔軟性と硬さのバランスが難しい話
nassy20
0
130
20260619 私の日常業務での生成 AI 活用
masaruogura
1
210
AIはどのように 組織のアジリティを変えるのか?
junki
3
880
Bedrock AgentCore RuntimeでAuth0 Changelog調査AIをアップグレードした話
t5u8a5a
1
160
Kubernetesにおける学習基盤とLLMOpsの概要
ry
1
310
あなたの知らないPDFのアクセシビリティ
lycorptech_jp
PRO
0
200
2026TECHFRESH畢業分享會 - Lightning Talk - 資料也要 CI/CD? 用 Airbyte 自動化資料同步
line_developers_tw
PRO
0
1.1k
Featured
See All Featured
Become a Pro
speakerdeck
PRO
31
6k
Bash Introduction
62gerente
615
220k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
420
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
610
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
840
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
200
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.3k
Practical Orchestrator
shlominoach
191
11k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
560
How to audit for AI Accessibility on your Front & Back End
davetheseo
0
430
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
180
Transcript
📀 Remix の凄みを紹介したい @aiji42_dev
Who am I ? Uejima Aiji | Twitter: @aiji42_dev 🏢
株式会社エイチームライフデザイン 🧘 リードエンジニア 🥑 最近の活動 CloudflareでISRを実現したり CSRなサイトをPrerenderでSSRぽくしたり PrismaからSupabase APIを叩くミドルウェア作っ たり 社内でフロントエンド版ISSUCON開催したり
今日はRemix を紹介したい パブリックされてから半年間、個人でも社内でもRemixを使い倒したので
この発表をぜひ聞いて欲しい人 Remixって最近良く聞いたり目にしたりするなー 🤔 Next.js大好き!正直コレ一本で食っていけるよね 😎 この発表を聞くと、たとえRemixを使用しなくても実装の仕方の幅が広がることでしょう 最近Next.jsがなんか新しいLayoutに関するRF公開したよね そうです、実はRemixがその先駆けです Cloudflareってなんか最近勢いあるよね、なんか試してみようかな 🌩
CloudflareはRemixを語る上で切り離せない話題です
その前にお断り この発表ではJamstackにもCMSにも触れません 🙇 しかし、Remixが解決しようとしていることは、 今後のReactやフロント界隈の方向性に少なからず影響を与えており、 多くの人に触れてほしい知ってほしいという気持ちで、この発表に臨んでいます。
What is Remix ? React SSRフレームワーク React Routerの開発チームが開発を主導 昨年11月末にv1がリリースされたタイミングでパブリックに Cloudflare
Workersで稼働させられたり、Denoをサポートしていたり 📀 のアイコンがよく使われる
Remix の特徴 ① loader と action
loader とaction Next.js の getServerSideProps や API Routes のようなもの loader
action ページコンポネントと同一ファイルに定義可能 GETアクセス時のデータフェッチを定義 ページ(コンポネント)からはuseLoaderDataで取得し、 useFetcherで再フェッチ可能 POSTやDELETEなどのミューテーションを定義する useSubmit やuseFormAction、form要素からリクエストする // app/routes/posts/$slug.tsx export const loader = async ({ params }) => { const post = await db.post.findUnique({ where: params.slug }) return { post } } export const action = async ({ request, params }) => { if (request.method === 'POST') { await db.post.create({ ... }) } if (request.method === 'DELETE') { await db.post.delete({ ... }) } if (request.method === 'PATCH') { await db.post.update({ ... }) } } const Page: FC = () => { const { post } = useLoaderData() return ... } export default Page
Remix の特徴 ② File system routing と Nested Routing (Layout)
レイアウトルート / 共通処理
ディレクトリ構成やファイル名がそのままURLになるという点 は、Next.jsのpagesとよく似ている app/ ├── routes/ │ ├── blog/ │ │
├── $postId.tsx │ │ ├── categories.tsx │ │ ├── index.tsx │ └── about.tsx │ └── blog.tsx │ └── index.tsx └── root.tsx
URL Matched Route / app/routes/index.tsx /about app/routes/about.tsx │ └── about.tsx
│ └── index.tsx app/ ├── routes/ │ ├── blog/ │ │ ├── $postId.tsx │ │ ├── categories.tsx │ │ ├── index.tsx │ └── blog.tsx └── root.tsx
ディレクトリの入れ子はそのままURLに変換される $(ドルマーク)をつけると、 パラメータとしてloader/actionで扱える URL Matched Route /blog app/routes/blog/index.tsx /blog/categories app/routes/blog/categories.tsx
/blog/my-post app/routes/blog/$postId.tsx │ │ ├── $postId.tsx │ │ ├── categories.tsx │ │ ├── index.tsx app/ ├── routes/ │ ├── blog/ │ └── about.tsx │ └── blog.tsx │ └── index.tsx └── root.tsx
root.tsxがトップレイヤレイアウト ディレクトリと同一名ファイルが子レイアウト URL Matched Route Layout / app/routes/index.tsx app/root.tsx /about
app/routes/about.tsx app/root.tsx /blog app/routes/blog/index.tsx app/routes/blog.tsx /blog/categories app/routes/blog/categories.tsx app/routes/blog.tsx /blog/my-post app/routes/blog/$postId.tsx app/routes/blog.tsx │ ├── blog/ │ └── blog.tsx └── root.tsx app/ ├── routes/ │ │ ├── $postId.tsx │ │ ├── categories.tsx │ │ ├── index.tsx │ └── about.tsx │ └── index.tsx
ダブルアンダースコアで始めると URL化されないレイアウトルートになる (pathless layout routes) ディレクトリ構造の代わりにドットでも表現可能 Catch all route (*)
│ ├── __authed/ │ ├── __authed.tsx app/ ├── routes/ │ │ ├── dashboard.tsx │ │ └── $userId/ │ │ │ └── profile.tsx └── root.tsx │ ├── blog.$slug.tsx app/ ├── routes/ │ ├── blog.tsx └── root.tsx │ └── $.tsx app/ ├── routes/ │ ├── blog/ │ │ ├── $postId.tsx │ │ ├── categories.tsx │ │ ├── index.tsx └── root.tsx
ドキュメントで紹介されている例 https://example.com/sales/invices/102000 こんな感じのダッシュボード app/ ├── routes/ │ ├── sales/ │
│ ├── invoices/ │ │ │ └── $id.tsx │ │ ├── invoices.tsx │ └── sales.tsx └── root.tsx
root.tsxがトップレイヤレイアウト Outletコンポネント部分がレンダリング時に 子レイアウト・子ページになる └── root.tsx app/ ├── routes/ │ ├──
sales/ │ │ ├── invoices/ │ │ │ └── $id.tsx │ │ ├── invoices.tsx │ └── sales.tsx export default function Root() { return ( <Sidebar> <Outlet /> </Sidebar> ) }
ディレクトリと同一名ファイルで子レイアウトを定義 │ ├── sales/ │ └── sales.tsx app/ ├── routes/
│ │ ├── invoices/ │ │ │ └── $id.tsx │ │ ├── invoices.tsx └── root.tsx export default function Sales() { return ( <> <h1>Sles</h1> <Tabs /> <Outlet /> </> ) }
layoutにもloaderを設置可能 │ │ ├── invoices/ │ │ ├── invoices.tsx app/
├── routes/ │ ├── sales/ │ │ │ └── $id.tsx │ └── sales.tsx └── root.tsx export const loader = async () => { const overview = await fetch(...).then((res) => res.json()) // ... return { overviewData, inviceListData } } export default function InvoiceList() { const { overviewData, inviceListData } = useLoaderData() return ( <> <Overview data={overviewData}> <InvoiceList items={inviceListData} > <Outlet /> </InvoiceList> </> ) }
各ページ・レイアウトにごとに ErrorBoundaryを定義可能 │ │ │ └── $id.tsx app/ ├── routes/
│ ├── sales/ │ │ ├── invoices/ │ │ ├── invoices.tsx │ └── sales.tsx └── root.tsx export const loader = async ({ params }) => { const data = await db.invoice.findOne({ where: { id: params.id } }) return { data } } export default function Invoice() { const { data } = useLoaderData() return ( <InvoiceItem data={data} /> ) } export function ErrorBoundary({ error }) { return ( <ErrorMessage>{error.message}</ErrorMessage> ) }
エラーの伝搬を留めることができる フォールバックが最小限になる │ │ │ └── $id.tsx app/ ├── routes/
│ ├── sales/ │ │ ├── invoices/ │ │ ├── invoices.tsx │ └── sales.tsx └── root.tsx export const loader = async ({ params }) => { const data = await db.invoice.findOne({ where: { id: params.id } }) return { data } } export default function Invoice() { const { data } = useLoaderData() return ( <InvoiceItem data={data} /> ) } export function ErrorBoundary({ error }) { return ( <ErrorMessage>{error.message}</ErrorMessage> ) }
Nested Routes があると何が嬉しいか レイアウトのグルーピングと階層的な適応 並列データフェッチ 各loaderは並列に処理されるため、高速化につながる
ロジックの共通化 特定ルート配下はログイン必須にするなどの、共通処理を階層的にもたせられる pathless routesと組み合わせて特定のディレクトリ下は暗黙的に認証必須にするなど 差分ロード・再フェッチ ナビゲーション時にフルページロードではなく、必要なレイアウトルート分のロードが行われる 任意にページ内を更新する再フェッチ処理も実装しやすい
ちょうど先日Next.js にも同等な機能のRFC が公開された https://nextjs.org/blog/layouts-rfc 現プロポーザルではおおよそRemixと同等の機能をカバーする予定 pathlessやErrorBoundaryに関しても、ドキュメントにはないが「パート2で言及する」とのこと かなりRemixのノウハウが意思決定に影響を与えている印象 デフォルトでServer Componentになる (Remixでも同様に議論されており近い将来デフォルトになるはず)
Remix の特徴 ③ マルチランタイム Node / web worker / Deno
Vercel / Netlify / Cloudflare Workers・Pages, etc もちろんセルフホスト可能
Remix の一番の強みは Cloudflare Workers 上で動くという点 だと個人的には思う。 エッジロケーションでレンダリングできるというのは今後のReact界隈において重要な意味をもつ
React が向かう先 - Server component / Streaming render コンポネントのレンダリングをServerサイドで行うようになる 従来のSSRとはことなり、コンポネントの粒度で解決し、さらにストリームで返却する
src: https://mxstbr.com/thoughts/streaming-ssr/ 各コンポネントでデータフェッチの処理を持ち、非同期的・自律的に解決する 同時接続数は爆発的に増加し、そしてラウンドトリップによるレイテンシが無視できなくなることが予想できる
そんな未来を見据えると だからCloudflare Workers 上で動くというのは大きな意味を持つ Next.js も昨年のエッジファンクション(middleware) の発表を皮切りに、エッジレンダリングを模索している エッジファンクション(ロケーション)がオリジンとして機能する スケールあまり意識しなくて良い 1リクエストあたりのコストが安価
という点は大きなアドバンテージになる RFC: Switchable Next.js Runtime #34179
Remix の特徴 ④ Form とヘルパー 前述のactionと通信を行うための、Formコンポネントや多数のヘ ルパーを備えている 特に useTransition はフォームのsubmitの状態
(idle / submitting / loading)を管理したり submit中のデータを取り扱うことが可能なので、楽観的UIの実装 も容易 0:00
remix-validated-form https://www.remix-validated-form.io/ remix-validated-formとzodを使用するとactionとコン ポネントを一体化できる クライアントとサーバとでバリデーションを共通化でき るだけでなく エラーメッセージの返却・レンダリング、例外処理の実 装から開放される 別のデータソースと通信して別途バリデーションするな ど、サーバサイドオンリーなバリデーションもかんたん
に追加可能 import { ValidatedForm } from "remix-validated-form"; import { withZod } from "@remix-validated-form/with-zod"; export const validator = withZod( // your zod role ); export const action = async ({ request }) => { const result = await validator.validate(await request.formData()); if (result.error) return validationError(result.error); const { firstName, lastName, email } = result.data; // Do something with the data }; export default function MyPage() { return ( <ValidatedForm validator={validator} method="post"> <FormInput name="firstName" label="First Name" /> <FormInput name="lastName" label="Last Name" /> <FormInput name="email" label="Email" /> <SubmitButton /> </ValidatedForm> ); }
Remix の特徴 ⑤ Cookie ヘルパー シリアライズ&検証の機能もデフォルトで実装されている loader/actionと組み合わせることで、 これまでフロントに実装していたステート管理や認証などをサーバサイドへ移譲できる ロジックがフロントに露出しないため、 秘匿性の高い情報の漏洩防止や、バンドルサイズの軽減につながる
CookieやSessionを取り扱うためのヘルパーが標準装備
remix-auth https://github.com/sergiodxa/remix-auth (サンプルコードはremix-auth-supabase) 認証方法・認可ルール・フォールバックルールなどを簡単に設 定・制御できる クライアント側には一切ロジックが露出しない export const loader =
async ({ request }) => supabaseStrategy.checkSession(request, { successRedirect: '/private' }); export const action = async ({ request }) => authenticator.authenticate('sb', request, { successRedirect: '/private', failureRedirect: '/login' }); export default function LoginPage() { return ( <Form method="post"> <input type="email" name="email" /> <input type="password" name="password" /> <button>Sign In</button> </Form> ); }
実用に耐えられるの? 🤔
他に個人開発サービスの運用実績、社内での実サービス開発への導入実績も Aiji Uejima @aiji42_dev 先日社内のエンジニア・デザイナ(総勢 80人強)でフロントエンド版Isuconを開 催しました。 運営である自分はRemix、Supabase、 CloudflareWorkers でリーダーボードを
作成したのですが、トラブルなくすん なり同時接続を捌いたのを見て、上記 構成のポテンシャルを肌で感じまし た。
実際に得られた恩恵 ステート管理ライブラリが不要 前述の通り 認証ロジック・データフェッチロジックすべてがサーバサイド完結 クライアントの実装はデータの描画のみに集中できる 情報更新をきめ細かくリアルタイムに、かつ高速に 前述の例ではSupabaseのsubscribeと組み合わせて、DBに変更が加わったらスタッツを再フェチする ネストされた部分的なレイアウトのみ再フェッチ(フルページロードしない) 実際のデータフェッチはloader側で行うので、ロジックは一切露出しない
エッジレンダリング(Cloudflare Workers)による恩恵 ゼロコールドスタート KV使わなくても、200-300msで応答できる(TTFB) 同一構成の Next.js on Vercel のSSRで300-500ms KV使えばSSRで60-80ms
もちろんデータソースに引っ張られるが スケールを気にしなくて良い
苦しみ Nested Routeは想像以上に難易度が高い URL設計とディレクトリ設計をセットで行わなければならない 良くも悪くもロジックが分散し、脳内メモリを圧迫する 実際ネストは2階層くらいにとどめておくのがよい 最初のサンプルに上げたような構成は正直無理
Workersに限った話になるが。。。 UIライブラリ入れると1MBにバンドルサイズを抑えるのは結構きつい SSRなので全てバンドルしないといけない(チャンクもできない) Service Bindingsを駆使して回避した まだまだWorker非対応なライブラリが多い esbuildでpolyfillしたり、injectしたりなど職人芸が求められる しかし、そもそもRemixのコンパイラ(esbuild)の設定の拡張が不可能 next.config.jsからwebpackの設定をいじるみたいな感じのことはできない 拡張自体がコミュニティのポリシー的にNG
(マネジメントコストとリスクの問題) 何度もDiscussionやPRは起票されているがことごとくリジェクト 最終的に自分でRemixのesbuild を拡張可能にするプラグインを書いた https://github.com/aiji42/remix-esbuild-override
相性の良いサービスやサイト 次のようなケースならNext.jsで実装するよりもRemixで実装したほうが開発コストは小さくなる(と個人的には思う)
React Router で構築されたSPAサイトをSSRに移行したい、SEO対策したい React Routeの思想をベースに構築されているため、大きく構造を変えずに移行できる 複数ページに渡るエントリーフォームを簡単に実装したい 前述の通り、remix-validated-formとzodで簡単に作れる ステートライブラリも不要 MVCなWebフレームワーク(Rails)使ってた人は比較的とっつきやすい(と個人的には思う) 管理画面やダッシュボードをフルスクラッチしたい
React Adminの導入を試みたが、データスキーム・ビジネスロジックに適したアダプターがなかったなど Nested Routes と remix-validated-form, remix-auth を駆使する loader/actionを各フォームやデータフィードと1対1で配置し、UIとデータロジックをそれぞれで凝縮 テスタビリティの向上にもつながる
まとめ なんと言っても Cloudflare Workerで動く Nested routesの先駆け レイアウトとデータフェッチロジックの分散管理 Next.jsに影響を及ぼす程の先見性 この2つを備えていて、ここまで完成度の高いフレームワークは他にはありません。 メインで使うフレームワークとまはいかなくても、一度試す価値はあると思います。
Next.jsの新しいLayout戦略がGAされるまでの素振りとしても、良いサンドボックスになると思います。
One more thing Next.js にRemix のエッセンスを取り入れる
next-runtime https://next-runtime.meijer.ws/getting-started/1- introduction getServerSidePropsを拡張し、リクエストメソッドごとに 実装を書き分けることができる フォームのアクションをapi routesにせず、自パスに向けれ ば、擬似的なloader/actionになる 楽観的UIのためのヘルパーやCookieを取り扱うヘルパーな どが用意されており、かなりRemixに似ている
というか、Remixをインスパイアされて実装したと作者がドキュメントで 明言している import { handle, json, Form, useFormSubmit } from 'next-runtime'; export const getServerSideProps = handle({ async get() { return json({ name: 'smeijer' }); }, async post({ req: { body } }) { await db.comments.insert(body); return json({ message: 'thanks for your comment!' }); }, }); export default function MyPage({ name, message }) { const { isSubmitting } = useFormSubmit(); if (message) return <p>{message}</p>; return ( <Form method="post"> <input name="name" defaultValue={name} /> <input name="message" /> <button type="submit" disabled={pending}> {isSubmitting ? 'submitting' : 'submit'} </button> </Form> ); }
こちらの記事でも紹介しています https://zenn.dev/aiji42/articles/23a88a7b111694