• react

    server-only パッケージをインポートしたやつをどうにかして動かす

    ReactやNext.jsにおいて、server-only というパッケージをimportすることで、該当のパッケージをインポートした処理はServer側の処理からのみインポート可能になります。つまり use client などをつけたコンポーネントからは利用できません。逆にclient-onlyというのもありますね。詳細はNext.jsの記事などが参照になります。

    例えばなのですが運用で使うスクリプトを実行する時に、server-onlyパッケージをインポートしているライブラリが依存に入ってしまっていると、下記のエラーが発生してしまいます。これをどうにかしようという話です。

    Error: This module cannot be imported from a Client Component module. It should only be used from a Server Component.

    結論からするとnode--conditions=react-serverというオプションを付与して実行することで解決しますnode以外で実行する場合、例えばtsx等の場合はNODE_OPTIONS='--conditions=react-server'などで代替可能です。

    深堀り

    server-onlyの仕組みは下記の記事が詳しいです。

    https://quramy.medium.com/server-component-と-client-component-で依存モジュールを切り替える-7d65c8b2074f

    重要なのはnodeのsubpath importsという機能です。その中でもConditional exportsという機能が重要です。

    server-onlypackage.json を見ると下記のような定義がされています。server-only自体はGitHubで見つからないので、node_modulesの中から引っ張ってきています。

    { // ... "exports": { ".": { "react-server": "./empty.js", "default": "./index.js" } } }

    defaultというのは条件に引っかからなかった時のデフォルトの挙動です。つまりreact-serverという何らかしらの条件に引っかかる場合はempty.jsが、そうではない場合はdefaultが呼ばれます。
    ちなみにempty.jsは文字通り空っぽで、index.jsはエラーを吐くだけのファイルです。

    empty.js
    index.js
    throw new Error( "This module cannot be imported from a Client Component module. " + "It should only be used from a Server Component." );

    上記を見るに、react-serverという条件であれば問題なくインポートできるようです。この条件を指定するのが--conditionsオプションです。node --conditions=react-server のようなコマンドを打つことで、server-onlyの挙動を変更でき、動かすことが可能です。