3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js+Turbopack構成でsymbol-sdk v3を使えるようにする

Posted at

環境

> node -v    
v24.13.0

>npm -v
11.6.2

Next.js アプリ作成

最新のcreate-next-appからウィザード形式で作成します

mkdir your-next-proj
cd your-next-proj
npx create-next-app@latest .

オプション設定

# (任意)もしこれがでたら'y'→Enter
Need to install the following packages:
create-next-app@16.1.6
Ok to proceed? (y) y

# recommendのままEnter
? Would you like to use the recommended Next.js defaults? › - Use arrow-keys. Return to submit.
❯   Yes, use recommended defaults - TypeScript, ESLint, Tailwind CSS, App Router
    No, reuse previous settings
    No, customize settings

必要なパッケージのインストール

symbol-sdk v3とsymbol-crypto-wasm-webをインストールします

npm i symbol-sdk@^3 symbol-crypto-wasm-web

ここまでの各パッケージのバージョンの確認

  "dependencies": {
    "next": "16.1.5",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "symbol-crypto-wasm-web": "^0.1.1",
    "symbol-sdk": "^3.3.0"
  }

サンプルページ

ページに適当にsdkを呼ぶ処理を記述します。
今回はSSR,CSR双方で動くことを確認したいので以下の3つを作ります。

  • app/page.tsx:ルート(リンクのみ)
  • app/ssr/page.tsx:SSR用の検証ページ
  • app/csr/page.tsx:CSR用の検証ページ

app/page.tsx

export default function Home() {
  return (
    <main className="min-h-screen p-8">
      <h1 className="text-2xl font-semibold">Repro Index</h1>
      <p className="mt-2 text-sm text-zinc-600">
        Choose SSR or CSR pages to reproduce the Symbol SDK v3 behavior.
      </p>
      <ul className="mt-6 list-disc pl-6">
        <li>
          <a className="text-blue-600 underline" href="/ssr">
            SSR page
          </a>
        </li>
        <li>
          <a className="text-blue-600 underline" href="/csr">
            CSR page
          </a>
        </li>
      </ul>
    </main>
  );
}

app/ssr/page.tsx

import { PrivateKey } from "symbol-sdk";
import { KeyPair, SymbolFacade } from "symbol-sdk/symbol";

export default function SsrPage() {
  const facade = new SymbolFacade("testnet");

  const privateKey = PrivateKey.random();
  const account = facade.createAccount(privateKey);
  const addressRaw = account.address.toString();
  const keyPair = new KeyPair(privateKey);
  const publicKeyHex = keyPair.publicKey.toString();

  return (
    <main className="min-h-screen p-8">
      <h1 className="text-2xl font-semibold">SSR</h1>
      <ul className="mt-6 list-disc pl-6">
        <li>Address: {addressRaw}</li>
        <li>Public Key: {publicKeyHex}</li>
      </ul>
    </main>
  );
}

app/csr/page.tsx

"use client";

import { PrivateKey } from "symbol-sdk";
import { KeyPair, SymbolFacade } from "symbol-sdk/symbol";

export default function SsrPage() {
  const facade = new SymbolFacade("testnet");

  const privateKey = PrivateKey.random();
  const account = facade.createAccount(privateKey);
  const addressRaw = account.address.toString();
  const keyPair = new KeyPair(privateKey);
  const publicKeyHex = keyPair.publicKey.toString();

  return (
    <main className="min-h-screen p-8">
      <h1 className="text-2xl font-semibold">SSR</h1>
      <ul className="mt-6 list-disc pl-6">
        <li>Address: {addressRaw}</li>
        <li>Public Key: {publicKeyHex}</li>
      </ul>
    </main>
  );
}

動作確認(コケます)

  1. 開発サーバ起動
npm run dev
  1. http://localhost:3000/ にアクセス
  2. CSRまたはSSRのリンククリック

これだけだとそれぞれのページでただしくSDKを呼べずに以下のようになると思います。

image.png

エラーログ(テキスト)
Module not found: Can't resolve 'fs'
./node_modules/symbol-crypto-wasm-node/symbol_crypto_wasm.js (250:15)

Module not found: Can't resolve 'fs'
  248 |
  249 | const path = require('path').join(__dirname, 'symbol_crypto_wasm_bg.wasm');
> 250 | const bytes = require('fs').readFileSync(path);
      |               ^^^^^^^^^^^^^
  251 |
  252 | const wasmModule = new WebAssembly.Module(bytes);
  253 | const wasmInstance = new WebAssembly.Instance(wasmModule, imports);

Import traces:
  Client Component Browser:
    ./node_modules/symbol-crypto-wasm-node/symbol_crypto_wasm.js [Client Component Browser]
    ./node_modules/symbol-sdk/src/impl/ed25519_wasm.js [Client Component Browser]
    ./node_modules/symbol-sdk/src/impl/ed25519.js [Client Component Browser]
    ./node_modules/symbol-sdk/src/symbol/KeyPair.js [Client Component Browser]
    ./node_modules/symbol-sdk/src/symbol/index.js [Client Component Browser]
    ./app/csr/page.tsx [Client Component Browser]
    ./app/csr/page.tsx [Server Component]

  Client Component SSR:
    ./node_modules/symbol-crypto-wasm-node/symbol_crypto_wasm.js [Client Component SSR]
    ./node_modules/symbol-sdk/src/impl/ed25519_wasm.js [Client Component SSR]
    ./node_modules/symbol-sdk/src/impl/ed25519.js [Client Component SSR]
    ./node_modules/symbol-sdk/src/symbol/KeyPair.js [Client Component SSR]
    ./node_modules/symbol-sdk/src/symbol/index.js [Client Component SSR]
    ./app/csr/page.tsx [Client Component SSR]
    ./app/csr/page.tsx [Server Component]

https://nextjs.org/docs/messages/module-not-found

next.config.ts(js)の修正

webpackの場合

以前のwebpackを使ってるNext.jsのバージョンでは以下のやり方で動作するようです。

※一時期devだけturbopack, 本番ビルドはwebpackな時代もあったと思うのですがそれは未検証

Turbopackの場合(今回)

上記と若干書き方が違います。

next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  reactStrictMode: true,

   /**
   * symbol-sdk は Node.js 環境でのみ実行したい処理を含むため、
   * Server Component 側では external として扱う。
   *
   * これを指定しないと Turbopack がクライアント向けに
   * 無理にバンドルしようとしてエラーになることがある。
   */
  serverExternalPackages: ["bitcore-lib", "bitcore-mnemonic", "symbol-sdk"],

  /**
   * Turbopack 用の alias 設定
   *
   * symbol-sdk は内部で `symbol-crypto-wasm-node` を参照するが、
   * ブラウザ環境では `fs` が使えないためビルドエラーになる。
   *
   * ここで WebAssembly(Web) 版の実装に差し替える。
   */
  turbopack: {
    resolveAlias: {
      "symbol-crypto-wasm-node": "symbol-crypto-wasm-web/symbol_crypto_wasm.js",
    },
  },

  /**
   * webpack 設定
   *
   * Turbopack 利用時でも、
   * - 本番ビルド
   * - 一部の依存解決
   * では webpack が使われるケースがあるため、
   * 同じ置き換えを webpack 側にも定義しておく。
   */
  webpack: (config, { webpack }) => {
    /**
     * symbol-crypto-wasm-node を
     * symbol-crypto-wasm-web に強制置換
     */
    config.plugins.push(
      new webpack.NormalModuleReplacementPlugin(
        /symbol-crypto-wasm-node/,
        "symbol-crypto-wasm-web/symbol_crypto_wasm.js",
      ),
    );

    /**
     * WebAssembly を async import / top-level await で
     * 正しく扱うための設定
     */
    config.experiments = {
      ...config.experiments,
      asyncWebAssembly: true,
      topLevelAwait: true,
      layers: true,
    };

    return config;
  },
};

export default nextConfig;

※上記のように修正してもエラーが出る場合は一旦 npm run dev を止めて再実行してください。

本番ビルドでも確認

以下のコマンドで本番ビルド&起動したURLにアクセスしても動作することを確認します。

npm run build
npm run start

まとめ

  • symbol-sdk v3 は Node 用 wasm 実装が優先される
  • Turbopack では alias 設定が必須
  • SSR / CSR 両方で動かす場合でも対応可能
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?