はじめに
この記事では、Web3.0アプリケーション開発現場で採用されやすいNext.jsについて、その人気の理由について考察します。さらに2023年5月にリリースされた新機能(App Router)を使って、Web3.0のアプリを作成するにあたって、App Routerの特徴を紹介しつつ、ウォレットに接続する方法をご紹介します。
Web3.0でNext.jsが人気の理由 4選
1. サーバーサイドレンダリング(SSR)
Next.jsはSSR(サーバーサイドレンダリング)をサポートしており、これにより、初期読み込みの高速化やSEOの向上が可能です。Web3のアプリケーションにおいては特に、ブロックチェーン上のデータを取得して表示する必要がある場合、SSRは非常に有用です。
2. 静的サイト生成(SSG)
Next.jsはSSGもサポートしています。SSGは、事前にページを生成し、静的なファイルとして提供することで、パフォーマンスを向上させます。Web3のアプリケーションでは、ブロックチェーン上のデータが頻繁に変化する場合でも、SSGを使用して静的なコンテンツを提供することができます。
3. ルーティングと状態管理
Next.jsは、ルーティング機能と状態管理を簡単に実装できる機能を提供しています。Web3のアプリケーションでは、複数の画面や状態の管理が必要な場合があります。Next.jsのルーティング機能と状態管理のツールセットは、このような要件に対応するのに役立ちます。
4. モジュールの管理
Next.jsは、npmやyarnを介してモジュールを管理するための便利なツールを提供します。Web3開発では、Web3ライブラリや関連するパッケージが多数準備されています。Next.jsのモジュール管理機能により、依存関係の解決やパッケージのバージョン管理が容易になります。
Next.jsのApp Routerとは?
2023年5月にリリースされたバージョン13.4.0から、Next.jsにおけるルーティングの仕様が大きく変更しました。これまでは、Pages Router という仕組みを使用しておりましたが、ルーティングのベースとなる機能の仕様が変更されたことにより、画面遷移がより高速になる可能性を秘めております。
以下に主な特徴を2点記載します。
1. ファイルパスの使い方を刷新
App Routerではトップレベルのフォルダとして pages/
ではなく app/
を利用します。App Routerという名前は、このフォルダ名に由来しています。
Pages Routerでは、レイアウトと呼ばれる機構を後付けした際にAPIが複雑になってしまいましたが、App Routerではレイアウトを初めから設計に組み込んでいるため、直感的に扱えるようになっています。
2. サーバーをより活用したレンダリング
Pages Routerにも、画面遷移時にサーバー側でデータ取得を行う機能はありました。しかし、レンダリングまでサーバー側で請け負うのは、ページを直接リクエストする初期表示のときのみで、画面遷移後の(複雑な条件分岐や反復処理を含む)レンダリングや、ページ内の個別のコンポーネントによる非同期通信は、ブラウザ側に任されていました。
そのため、複雑なロジックが関係するアプリケーションの場合、ユーザー側の環境だけでは利用体験が制限されるケースが多々発生することになりました。
そのような課題を解決するため、App Routerでは原則として、全てのReactコンポーネントをサーバー側でレンダリングすることにしました。通信も、条件分岐も、反復処理も、全てサーバーで行うことで、ユーザーの環境によってパフォーマンスが落ちる要因を最小限にできます。
※ここでいうレンダリングとは、あるデータに基づいて、条件分岐や反復処理を行い、コンポーネントの構造を決定する処理を指し、必ずしもHTMLの生成は伴いません。
Web3.0アプリの開発ステップ(概要)
1. スマートコントラクトの作成
Web3.0アプリの開発はまずスマートコントラクトの作成から始まります。Solidityなどの言語を用いて開発し、Alchemyなどのプロバイダーにデプロイします。このステップはアプリの基礎となるため、非常に重要です。
2. フロントエンドの開発
次に、フロントエンドの開発に移ります。ここではNext.jsなどを使用して画面を開発し、ライブラリ(例えばThirdweb.js)を使ってウォレットやプロバイダーへの接続を行います。しかし、App Routerでウォレットを接続するコードサンプルはほとんどなく、Thirdweb.jsの公式サイトでさえ、Pages Routerの例しか提供していません。
RainbowKit の導入
この問題を解決するために、RainbowKitの使用を提案します。RainbowKitはWeb3.0アプリ向けのReactライブラリで、ウォレット接続機能を簡単に実装できます。デフォルトのウォレットボタンのカスタマイズやどのウォレットを表示するかの設定も可能です。
RainbowKitの使い方
- 新規Next.jsプロジェクトの場合
$ npm init @rainbow-me/rainbowkit@latest
- 既存プロジェクトへの導入、Next.js以外の場合
$ npm install @rainbow-me/rainbowkit wagmi viem
RainbowKitを使ったプロバイダーとの接続
app/provider.tsx
のコード例を以下に示します。
import * as React from 'react'; import { RainbowKitProvider, getDefaultWallets, connectorsForWallets } from '@rainbow-me/rainbowkit'; import { argentWallet, trustWallet, ledgerWallet } from '@rainbow-me/rainbowkit/wallets'; import { configureChains, createConfig, WagmiConfig } from 'wagmi'; import { mainnet, polygon, optimism, arbitrum, base, zora, goerli } from 'wagmi/chains'; import { publicProvider } from 'wagmi/providers/public'; // チェーンの設定 const { chains, publicClient, webSocketPublicClient } = configureChains( [ mainnet, polygon, optimism, ...(process.env.NEXT_PUBLIC_ENABLE_TESTNETS === 'true' ? [goerli] : []), ], [publicProvider()] ); // プロジェクトID・ウォレットの設定 const projectId = 'YOUR_PROJECT_ID'; const { wallets } = getDefaultWallets({ appName: 'RainbowKit demo', projectId, chains, }); // コネクタの設定 const connectors = connectorsForWallets([ ...wallets, { groupName: 'Other', wallets: [ argentWallet({ projectId, chains }), trustWallet({ projectId, chains }), ledgerWallet({ projectId, chains }), ], }, ]); // wagmi の設定 const wagmiConfig = createConfig({ autoConnect: true, connectors, publicClient, webSocketPublicClient, }); // プロバイダコンポーネントの定義 export function Providers({ children }: { children: React.ReactNode }) { const [mounted, setMounted] = React.useState(false); React.useEffect(() => setMounted(true), []); return ( {mounted && children} ); }
同様に、app/layout.tsx
と app/page.tsx
でのRainbowKitの使用例を示します。
// app/layout.tsx
import '../styles/global.css';
import '@rainbow-me/rainbowkit/styles.css';
import { Providers } from './providers';
function RootLayout({ children }: { children: React.ReactNode })
{
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
export default RootLayout;
// app/page.tsx
import { ConnectButton } from '@rainbow-me/rainbowkit';
function Page() {
return (
<div
style={{
display: 'flex',
justifyContent: 'flex-end',
padding: 12,
}}
>
<ConnectButton />
</div>
);
}
export default Page;
参考記事
- https://nextjs.org/docs/app/building-your-application/routing
- https://zenn.dev/akfm/articles/next-app-router-navigation#app%E3%81%AE%E6%8C%99%E5%8B%95
- https://codezine.jp/article/detail/17925