このページ内容は2021年1月21日以降、再調査・再検証してません。実際に扱う際は最新の情報にアクセスしてください。

link
フレームワーク編
link
Remix

RemixはCDNのEdge部分でSSRできるReactの新しいフレームワークですremix。Remixでは以下4つの理念からなる特徴を持っていますremix_philo

    ソースコードとコンテンツ/データの分離を含む、クライアント - サーバーモデルを採用
    ブラウザやHTTP, HTMLなどのWebの基盤を活用する
    JavaScriptでブラウザの動作をエミュレートし、ユーザー体験を向上させる
    基盤となるテクノロジーを過度に抽象化しない

まず1つ目ですが、Remixではクライアント-サーバーモデルを採用しているため、クライアント側で完結するSSGをサポートせず、Edge領域でのSSRを活用します。このことにより、動的コンテンツを提供するアプリでも静的サイト並みの速度を提供できるそうですremix_performance

またRemixではネットワーク送信量を減らす機能が豊富にあります。これはサーバー側は高速化できるが、ユーザーのネットワークは改善しようがないことを認識しているためです。例えば、GitHubのGist APIを単純に使う場合は以下のようになりますが、このように書く場合は不要な情報も含まれるため、送信されるデータ量は多くなりますremix_server_client_model

1
export default function Gists() {
2
const gists = useSomeFetchWrapper("https://api.github.com/gists");
3
// React18を使うなら、Suspenseで置き換えできるため不要
4
if (!gists) return <Skeleton />;
5
6
return (
7
<ul>
8
{gists.map(gist => (
9
<li>
10
<a href={gist.html_url}>
11
{gist.description}, {gist.owner.login}
12
</a>
13
<ul>
14
{Object.keys(gist.files).map(key => (
15
<li>{key}</li>
16
))}
17
</ul>
18
</li>
19
))}
20
</ul>
21
);
22
}

対してRemixを使う場合はユーザーにデータを送信する前に、loader関数でデータをフィルタリングできるため、以下のように書くことができます。このようにフィルタリングすることで送信するデータ量を少なくできます。

1
// サーバー側でのデータのフィルタリング
2
export async function loader() {
3
const res = await fetch("https://api.github.com/gists");
4
const json = await res.json();
5
return json.map(gist => {
6
return { url: gist.html_url, files: Object.keys(gist.files), owner: gist.owner.login };
7
});
8
}
9
10
export default function Gists() {
11
const gists = useLoaderData();
12
return (
13
<ul>
14
{gists.map(gist => (
15
<li>
16
<a href={gist.url}>
17
{gist.description}, {gist.owner}
18
</a>
19
<ul>
20
{gist.files.map(key => (
21
<li>{key}</li>
22
))}
23
</ul>
24
</li>
25
))}
26
</ul>
27
);
28
}

2つ目として、RemixではWebの標準的な機能を活用するために、独自のリクエスト/レスポンス APIなどを作らず、Fetch APIを活用します。例えば、Fetch APIのHeadersインターフェースremix_headersを使うと、HTTPリクエストやレスポンスヘッダーに応じた処理ができますが、RemixでもloaderHeaders関数として利用できます。また、このようなHTTPヘッダーを各ルート (異なるパス) ごとに作成できるのもRemixの特徴ですremix_path_headers

1
export function headers({ loaderHeaders }) {
2
return {
3
"Cache-Control": loaderHeaders.get("Cache-Control")
4
};
5
}

ヘッダーだけでなく、metaタグもパスごとに設定できますremix_meta_tag

1
import type { MetaFunction } from "remix";
2
3
export const meta: MetaFunction = () => {
4
return {
5
title: "Something cool",
6
description:
7
"This becomes the nice preview on search results."
8
};
9
};

3つ目はRemixではユーザー体験を向上させるために、ページ遷移時はレイアウトの変更部分のみデータ取得するように動きます。これはNested Routingという機能が関わってきます。言葉や図で説明するのが難しいので、こちらをみてくださいremix_routing

頑張って文で説明すると、/invoices/12から/invoices/12/editにページ遷移する場合を考えます。(Suspenseを使う場合は少し変わりますが) Next.jsの場合は遷移先のページで必要なJavaScriptやCSSを取得してからページが変わります。しかし、Remixでは変更先で必要な部分のみ取得して更新し、共通部分はそのまま維持され再描画しません。また、必要な部分のみを取得して更新できる特性から、そのページで必要なコンポーネントを並行してダウンロードできます。

ここら辺の技術的な話は理解も説明も難しいため、気になる方はまだ未整理のドキュメントremix_routing2や他の文献を探してみてください。Remixのこの機能はreact-routerのv6で追加された機能と同じなので、こちらのリポジトリも参考になるかもしれませんreact_router

4つ目にRemixのAPIは基本的なHTTPやブラウザ, JavaScriptの機能をラップしてますが、過度に抽象化しないように気をつけて作られているようです。(具体的な例をもって説明はできませんが) 汎用性のある技術を学べる点もRemixの良い点だと感じます。

Remixは他にも以下のような面白い特徴を持っています。

    ページが存在しないときに、404がちゃんと返る
    アプリ作成時にデプロイ先を選ぶ
    Remix用のモニタリングサービスがある

Next.jsだとページが存在しないときに、ステータスコード 404で404ページを返すにはひと手間必要ですnextjs_404。しかし、Remixを使う場合は何も設定しなくても、ページが存在しないときは404のステータスコードと一緒に404ページを返してくれます。

Nuxt3ではビルド時にデプロイ先を決めることができますが、Remixではアプリ作成時にデプロイ先を選びます。候補としてはfly.ioやAWS Lambda, Cloudflare Workersなどがありますremix_deploy。アプリを作り始めたらすぐにデプロイできるようにこのようにしているらしいです。

VercelにもChecksというサービスを統合できるようになりましたが、RemixにもMetronomeというWeb Vitalsやアクセス数、発生したエラーの詳細を確認できるサービスがありますremix_metronome。Rollbarなどをフロントに入れなくても、エラーの詳細が確認できるなら、ありがたいですが、まだ試してないので、詳細は分かりません。

Remixにはいくつかサンプルアプリremix_sampleもあるので、興味のある方はぜひ試してみてください。


remix_metronome: https://metronome.sh/
自己紹介
はじめまして Pilefortです。
東京でエソジニアをしてます。
興味のあるスタックは、JavaScript (React, Vue), TypeScript, Rust, WebAssembly, AWS, Pulumi, Serverless Frameworkです。
このブログでは、普段の業務や趣味で気になったことをまとめたり、フロントやAWS, GitHubやTwitterで見かけた面白い記事やニュースをまとめるためのものです。少しでも何かの役に立てば幸いです。
サイトマップ
Notes
業務や趣味での気づき・メモ
Snippets
記事にするまでもないけど、便利なコマンドや豆知識
Works
同人誌一覧