Skip to content

Multiple hooks execute browser-only code at module import time, crashing Next.js SSR across all pages #3

Description

@benfoster-dev

In hooks/useAccount.ts around line 6, an async IIFE runs at module import time:

let addressLookup = (async () => {
  if (await isConnected()) return getUserInfo()
})();

isConnected() from @stellar/freighter-api accesses window and document which don't exist during Node.js SSR. This throws a ReferenceError and crashes the server render.

But this is part of a broader SSR incompatibility across the hooks layer:

  1. useAccount.ts runs browser code at import time (not inside useEffect). Any page importing useAccount crashes during SSR. The barrel export at hooks/index.ts means importing any hook from the index also triggers this.

  2. The addressLookup promise is module-scoped. It executes once when the module is first imported and the result is shared across all component instances. If the user connects a wallet after initial page load, addressLookup already resolved to undefined and is never re-executed.

  3. The WalletData and EscrowPanel components import useAccount directly. These are used on multiple pages. Every page that renders these components fails SSR.

  4. There is no dynamic import or next/dynamic wrapper for wallet-dependent components. The entire component tree that touches Freighter must be client-only, but nothing enforces this.

  5. The useAccount hook does not handle the case where Freighter is not installed. isConnected() may throw or return false, but getUserInfo() is called without checking the return value of isConnected() in the promise chain.

This is high severity. The fix requires: moving all browser API calls inside useEffect, adding typeof window !== 'undefined' guards, converting the module-level promise to a proper React state lifecycle, wrapping wallet-dependent components with next/dynamic({ ssr: false }), and handling the Freighter-not-installed case gracefully.

This touches hooks/useAccount.ts, hooks/index.ts, and every component that imports useAccount (WalletData, EscrowPanel, Pledge).

Before submitting your PR, make sure all checks pass locally and the build succeeds. Each issue will be thoroughly reviewed and only merged if it fully meets the requirements. In your PR, specify the issue number and title. You can optionally provide a screenshot showing the fix working. On the issue, comment tagging the author to let them know you're working on it. On the PR, tag the maintainer to notify that review is ready.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdifficulty:hardHard difficultyhelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions