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-only の package.json を見ると下記のような定義がされています。server-only自体はGitHubで見つからないので、node_modulesの中から引っ張ってきています。
{
// ...
"exports": {
".": {
"react-server": "./empty.js",
"default": "./index.js"
}
}
}
defaultというのは条件に引っかからなかった時のデフォルトの挙動です。つまりreact-serverという何らかしらの条件に引っかかる場合はempty.jsが、そうではない場合はdefaultが呼ばれます。
ちなみに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の挙動を変更でき、動かすことが可能です。
