🕌

ArNextの紹介: Arweave&Vercelへ同時にデプロイできるNext.jsフレームワーク

に公開

原文: ArNext

ArNextは、同じコードベースをVercelArweaveの両方にデプロイできるNextJSベースのフレームワークです。

これにより、これまで不可能だったクラウドを活用したあらゆる種類のパフォーマンス最適化をpermaappに適用することが可能になります。

PermaAppsの制限

Permaappsは、Arweave上にデプロイされたSPA(シングルページアプリケーション)であり、デプロイ前にアプリをビルドするために完全なSSG(静的サイト生成)が必要です。Permaappsは伝統的に、サーバーサイドルーティングがないため、SPA内でのクライアントサイドのハッシュルーティングのみを許可しています。

permaappの例:

permaappsには多くの制限があります。

  • SSR(サーバーサイドレンダリング)がないため、動的コンテンツの読み込みが非常に遅い。
  • クライアントサイドのハッシュルーティングでは、ルートURLのみがアクセス可能。ハッシュなしの通常のブラウザルーティングでは、リロード時にアクセスできないページに移動してしまう。
  • 動的に生成されたページではソーシャルメディアカードが機能しない。Javascriptで動的に生成されたメタタグはX(旧Twitter)などのソーシャルアプリで読み込まれないため、ルートページ用の1つのカードしか持てない。
  • SSR、ISR、エッジCDNなどのサーバーサイドの最適化が不可能。

これらの制限により、permaappsは実用的に数百万人のユーザーをオンボーディングすることができません。

ArNextの機能

ArNextアプリは基本的にNextJSアプリですが、一連のハックを通じて同じコードベースから同一のpermaappをビルドすることもできます。これは、VercelではSSR、Arweaveではクライアントサイドルーティングを備えたマルチページSPA(!?)です。

  • 同一のアプリをVercelとArweaveの両方にデプロイできます。
  • Arweaveにデプロイされたpermaappsは検閲耐性のある永続的なバックアップとして機能します。
  • Vercelにデプロイされたアプリには、あらゆる種類のクラウドを活用した最適化を適用できます。
  • アプリは静的に生成されたマルチページサイトとして機能しますが、ページが読み込まれると、クライアントサイドルーティングを備えたSPAとして機能します。

サーバーサイドのパフォーマンス強化

以下のVercelにデプロイされたpermaappのパフォーマンスと、上記のArweaveにデプロイされたものを比較してみてください。

Vercel上のものはISR(インクリメンタル静的再生成)により非常に高速です。

動的ページ用のOpenGraphタグ

また、動的に生成されたページのオープングラフメタタグはSSRで有効化されています。

ハッシュルーティングが不要に

Arweaveにデプロイされたpermaappsではハッシュルーティングが不要になりました。

https://uz3hpyxn3pe6nifh3xbarjtntxtwcbgd2k2bgdle5vrhqpw23hua.arweave.net/pnZ34u3byeagp93CCKZtnedhBMPStBMNZO1ieD7a2eg/post/sbVCVIVPwMdeYxXgUqe9-rCgr9-JEInUco7EJ_yJ5tI

これはArweave Manifests v0.2.0fallbackを活用することで可能になりました。

ArNextは、修正版のarkbを使用して、fallback付きの最適化されたマニフェストを生成します。

アセット用の相対パスを動的に生成

NextJSコードベースから静的なpermaappをビルドする最大の課題は、静的ファイルのリンクです。Arweaveゲートウェイはサブディレクトリ型URLでpermaappsをデプロイしますが、そのサブディレクトリ名はビルドされたファイルのハッシュであるため、アプリをビルドする前に知ることができません。NextJSではbasePathを使用してサブディレクトリデプロイ用のアプリをビルドできますが、ビルド前にハッシュを知らなければ使用できません。また、basePathは絶対パスのみを許可します。そのため、これは使用できません。

アセットの相対パスをURLに読み込まれた後に動的に計算して挿入する必要がありますが、NextJSはそのような操作を許可していません。実際、主要なWebフレームワークはそのようなファイルリンクを許可していません。

この問題を解決するために、3つのハックが組み合わされています。

  • 相対パスを動的に計算し、HTMLヘッドにタグを挿入する(_document.js
  • アプリコードのビルド後にアセットタグを手動で書き換え、不要なhtmlファイルを削除し、実行時に正しいパスを生成するためにwebpackが生成したjsファイルを修正する(arweave.mjs
  • デプロイ前に修正されたarkbで適切なmanifest.jsonを生成する(deploy.js

ArNextアプリの構築方法

ArNextアプリの作成

npx create-arnext-app myapp
cd myapp && yarn
yarn dev

Vercelにデプロイ

vercel --prod

Arweave向けにビルド

yarn arweave

これで、Arweaveにデプロイするための静的アプリがlocalhost:3000で実行されています。

Arweaveにデプロイ

arkbを使用

yarn deploy -w WALLET_PATH

Turboを使用

Turboを使用したデプロイには、Turbo Creditsで資金提供されたウォレットが必要です。

yarn deploy:turbo -w WALLET_PATH

各ファイルのアップロード情報、生成されたArweaveマニフェスト、マニフェストのアップロードレスポンスを含むJSONオブジェクトがコンソールに表示されます。デプロイのマニフェストIDはmanifestResponse.idで確認できます。

ArNext ユーティリティ

VercelとArweaveの両方で同じように動作させるために、NextJSアプリコードにいくつかの小さな変更を加える必要があります。

現在、ArNextはNextJSのページルーターとArweave用のreact-router-domのみをサポートしています。

LinkuseParamsuseRouterarnextのものに置き換えます。これによりnext/routerreact-router-domが連携します。

import { Link, useParams, useRouter } from "arnext"

export default function Post() {
  const router = useRouter() // router.push(pathname)
  const { id } = useParams()
  ...
  return <Link href={`/post/${id}`}>/post/{id}</Link>
}

getStaticProps / ssr

getStaticPropsssrでラップします。

import { ssr } from "arnext"

export const getStaticProps = ssr(async ({}) => {
  ...
  return { props }
})

移行ガイド

現在、ArNextはsrcディレクトリとJSを使用しないページルーターでのみ動作します。

既存のNextJSアプリがある場合は、以下の手順に従ってください。create-arnext-appを使用してソースコードを手動でコピーする方が手間が少ないかもしれません。

  1. サポートされていない機能を削除する

ArNextは現時点で特定のNextJS機能をサポートしていません。あなたのアプリが以下の機能を使用している場合は、代替の実装方法を見つけてください。

  • Typescript
  • Appルーター
  • srcディレクトリ
  • next/font/local
  • next/image
  • next/routerpushのみサポート

これらは将来のリリースでサポートされる予定です。

  1. 必要な依存関係をインストールする。
yarn add arnext
yarn add arnext-arkb cheerio cross-env starknet @ardrive/turbo-sdk --dev
  1. next.config.mjsで設定をラップする。
/** @type {import('next').NextConfig} */
import arnext from "arnext/config"
const nextConfig = { reactStrictMode: true }
export default arnext(nextConfig)
  1. _document.jsHeadを置き換える。
import { Html, Main, NextScript } from "next/document"
import { Head } from "arnext"

export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}
  1. _app.jsComponentArNextに置き換える。
import { ArNext } from "arnext"
export default function App(props) {
  return <ArNext {...props} />
}
  1. getStaticPropsssrでラップする
import { ssr } from "arnext"

export const getStaticProps = ssr(async ({}) => {
  ...
  return { props }
})
  1. LinkuseParamsuseRouterarnextのものに置き換える。
import { Link, useParams, useRouter } from "arnext"

export default function Post() {
  const router = useRouter() // router.push(pathname)
  const { id } = useParams()
  ...
  return <Link href={`/post/${id}`}>/post/{id}</Link>
}
  1. arweave.mjsファイルをアプリのルートディレクトリにコピーする。

  2. スクリプトコマンドをpackage.jsonに追加する。

{
  ...
  "scripts": {
    "arweave": "npm run build:arweave && npx serve -s out",
    "deploy": "node node_modules/arnext-arkb deploy out",
    "deploy:turbo": "turbo upload-folder --folder-path out",
    "build:arweave": "cross-env NEXT_PUBLIC_DEPLOY_TARGET='arweave' next build && node arweave.mjs",
    ...
  },
  ...
}
  1. Arweave向けにビルドする
yarn arweave

Arweaveにデプロイするための静的版NextJSアプリがlocalhost:3000で実行されているはずです。

  1. Arweaveにデプロイする

すべてが正常に動作していれば、arkbまたはturboを使用してアプリをデプロイできます。

yarn deploy -w KEYFILE
yarn deploy:turbo -w KEYFILE
WeaveDB

Discussion