ランダムなチャンクから本当のコードへ:SentryでNext.jsのソースマップをつなぐ

Article by: Sergiy DybskiyAnton Bjorkman

 
 

Next.js アプリをリリースするとき、あなたが書いた React や TypeScript は、ユーザーが実際にダウンロードするものではありません。Next.js はパフォーマンスには優れている一方でデバッグには最悪な形で、コードをコンパイルし、ミニファイし、分割し、チャンクへとシャッフルします。

この記事では、そのパイプラインがどのように動くのか、ソースマップDebug ID がそれらをどのように元のコードへ結び付けるのか、そして Sentry が読みにくいスタックトレースではなく、実際のファイル名と行番号を表示するように設定する方法を解説します。

 

 

コードに実際に何が起きるのか

一般的な Next.js アプリでは、React+TypeScript のソースはビルドパイプラインを通り、JavaScript、HTML、CSS へコンパイルされます。その出力はミニファイされ、ユーザーが必要なものだけをダウンロードできるようにチャンクへ分割されます。

これらはページの読み込みには良いことです。しかしエラーが起きたとき、スタックトレースが app/page.tsx ではなく static/chunks/12345-something.js を指すようになると、あなたにとってはあまり良いことではありません。

あなたのコードは見覚えのあるものから、まったく見覚えのないものへと変わります。そこで登場するのがソースマップです。コンパイルされた各バンドルチャンクには、2つの重要なメタデータがあります。Debug ID と対応するソースマップを指す sourceMappingURL です。

Sentry はアップロードされたミニファイ済みファイル上の Debug ID を使って、アップロードされたソースマップ上の一致する Debug ID を見つけます。このペアがそろうと、Sentry はスタックトレースをデミニファイし、元のファイル、行、列へマッピングし直して、バンドラーが生成したコードではなく、あなたが実際に書いたコードを表示できます。

 

 

開発ツールではきれいなスタックトレースが出るのにSentry ではチャンクになる理由

開発時はブラウザ上では問題なく見えます。dev でアプリを動かし、サンプルのエラーを投げると、ブラウザの開発者ツールは実際のファイル名とソースを含む、読みやすいスタックトレースを表示します。

これは next dev を実行しているとき、ブラウザがローカルのソースマップと元のソースファイルに直接アクセスできるためです。Sentry なしでも、ブラウザだけで解決できます。

その同じ dev ビルドをSentry に向けると、Sentry が見えるのは送られてきたものだけです。ソースマップがアップロードされていなければ、Sentry が見るのは dev ビルドが生成したバンドルやチャンクファイルだけになります。結果として、ブラウザには人間が読めるスタックトレースがあるのに、Sentry にはランダムな名前のチャンクだらけのスタックトレースが並ぶことになります。

これらのチャンク名はビルドごとに変わります。つまり、同じ内容のエラーであっても、Sentry 上では別の Issue として複数回出てきてしまうことが簡単に起こります。

 

 

本番は Sentry、ローカルデバッグは Spotlight

機能開発中で、リロードのたびにエラーを投げているような状況だと、新しいチャンクが次々に生成され、ほぼ重複のエラーが大量に送信されます。その結果、自分しか見ていない問題で Sentry のクォータを消費してしまいます。

そのローカルの開発ループには、Spotlight のようなツールを使いましょう。Spotlight はローカル開発向けに作られており、Sentry と同様の使い勝手で、デバッグ由来のノイズを Sentry の組織から切り離せます。これにより、Sentry は実ユーザー由来の本番課題のために温存できます。

 

 

本番ビルドをローカルで再現して Sentry にソースマップを渡す

Sentry が重視するのは本番の成果物です。つまり、実ユーザーが踏む最適化済みバンドルと、それに対応するソースマップです。ローカルで本番環境を再現し、Sentry が必要なものを確実に見られるようにするために、アプリをビルドして起動します。

npm run build は、Sentry が組み込まれる最適化済みの本番ビルドを作成し、npm run start は、そのビルドを本番環境で動いているかのように配信します。

この実行はデプロイされたアプリと同じパイプラインを通ります。そしてこの過程で、Sentry が介入してバンドルとソースマップをアップロードします。

 

ビルドステップ中に Sentry が行うこと

本番ビルド(npm run build を実行したとき)では、Sentry は「after production compile」のステップにフックします。このフェーズで、Sentry は生成されたチャンクを収集し、それらのソースマップを見つけ、両方を Sentry にアップロードします。

アップロード後、Sentry はソースマップをビルド出力から削除し、ブラウザに配信されないようにします。これにより、devtools を開いたすべてのユーザーに元のソースコードを渡すことなく、Sentry 側では読みやすいスタックトレースを得られます。

Next.js 以外も含めた、より一般的な方法でソースマップをアップロードする方法を知りたい場合は、uploading source maps のドキュメントを参照してください。

 

ソースマップが正しく紐づいているかを確認する

npm run build と npm run start を実行したら、同じサンプルエラーをもう一度発生させて比較します。ブラウザのコンソールでは、長いミニファイ済みのスタックトレースが表示されるはずです。

これは想定どおりです。この本番相当のセットアップでは、ブラウザはもはやソースマップにアクセスできません。

Sentry では、Issues ページを更新して新しいエラーを開きます。スタックトレースは、あなたが実際に書いたコードとともに、実際の Next.js ファイルを指すはずです。Sentry のスタックトレースが読みやすく、ソースと一致しているなら、ソースマップは正しく紐づいています。

Sentry ではソースマップはプロジェクト設定にあります。Issues に移動し、プロジェクトセレクターで Next.js プロジェクトを選択して、Project Settings をクリックし、サイドバーから Source Maps ページを開きます。

そのプロジェクトにアップロードされたソースマップがすべて表示されます。Next.js アプリの場合、クライアントバンドル、サーバーバンドル、エッジバンドルが表示されることがあります。同じリリースに対して複数のエントリがあるのは通常です。Next.js はランタイムごとに別々のバンドルをビルドするだけです。

ソースマップの挙動が想定どおりでない場合(たとえば、Sentry が依然としてチャンク化された/ミニファイされたフレームを表示している場合)は、プロジェクトの Source Maps ページに移動し、既存のソースマップを削除してから、npm run build で本番ビルドをやり直し、npm run start でもう一度起動してエラーを発生させてください。

これによりクリーンなアップロードが行われ、古いファイルや不一致のファイルが原因の問題が解消されることがよくあります。

 

Next.js と Sentry の設定を再確認する

アプリをビルドしているのに Sentry にソースマップが表示されない場合、原因はたいてい設定です。

Next.js+Sentry のセットアップでは、Sentry の組織が正しく設定されているか、Sentry プロジェクトが想定しているものになっているか、有効な認証トークン(auth token)を渡しているかを確認してください。

認証トークンは Sentry 関連の設定に直接書くか、ビルドを実行している環境(ローカル、CI、Vercelなど)で SENTRY_AUTH_TOKEN 環境変数として設定できます。

環境変数が設定されていれば、設定ファイルにハードコードする必要はありません。

 

 

それでも詰まったときの参照先

本番モードでアプリをビルドし直し、ソースマップを整理して再アップロードし、Sentry の設定と環境変数も再確認したのにスタックトレースがまだおかしい場合は、Next.js のソースマップに関するドキュメントと、そのページ内のトラブルシューティングのセクションを確認してください。

そこでは、よくある設定ミス、動作が確認できている例、そして自分のセットアップと照らし合わせるためのチェックリストが紹介されています。

それでも疑問が残る場合は、ぜひ連絡してください。ランダムなチャンク名から、あなたが実際に書いたコードへ戻せるようお手伝いしますので、Discordで声をかけてください。Sentry が初めの場合は、インタラクティブな Sentry sandbox を試すか、無料でサインアップすることもできます。

 

 

Next.js ソースマップ FAQ


 
■ Sentry で実際のファイル名ではなくチャンクファイルが表示されるのはなぜですか?

npm run build を実行すると、Next.js はコードを static/chunks/12345-something.js のような名前の最適化済みチャンクにコンパイルします。ソースマップがない場合、Sentry が見えるのはこれらのチャンクファイルだけです。解決するには、npm run build と npm run start で本番ビルドを実行してください。これにより Sentry のアップロード処理が走り、スタックトレースに実際のファイル名が表示されるようになります。

 

■ Turbopack ではソースマップのアップロードは自動で動きますか?

はい。Sentry の設定と auth token をセットアップしていれば、Turbopack を使う Next.js プロジェクトでは、本番ビルド中にソースマップが自動的にアップロードされます。追加の設定は必要ありません。

 

Turbopack ではなく Webpack を使っている場合はどうなりますか?

Next.js の Webpack でも、ソースマップのアップロードは自動で動作するはずです。ミニファイされたスタックトレースが表示される場合は、auth token が設定されていることを確認し、npm run build で本番モードで実行していることを確認し、ビルドが実際にソースマップを生成しているかを確認してください。問題が続く場合は、プロジェクト設定で既存のソースマップを削除してから再ビルドしてください。

 

■ ローカル開発中に Sentry を使うべきですか?

リロードのたびに発生する新しいエラーをデバッグする目的では使わないでください。代わりに Spotlight を使ってください。Spotlight はローカル開発向けに作られており、デバッグ由来のノイズを Sentry の組織から切り離せるため、Sentry を実ユーザーの本番課題のために温存できます。

 

■ 同じエラーが Sentry で別の Issue として複数表示されるのはなぜですか?

チャンク名はビルドごとに変わります。dev ビルドのエラーを Sentry に送っていると、同じ内容のエラーでも、基になるチャンクファイル名が異なるため、別の Issue として複数回表示されることがあります。意味のある安定したスタックトレースを得るために、本番ビルドを実行してください。

 

ソースマップがまだ動きません。何を確認すべきですか?

まず、プロジェクト設定の Source Maps ページから既存のソースマップを削除してください。次に npm run build と npm run start を実行して、クリーンなアップロードをトリガーします。Sentry の組織、プロジェクト、auth token が正しく設定されていることを確認してください。ビルドが実際にソースマップを出力していることも確認してください。それでも解決しない場合は、Next.js のソースマップドキュメントとトラブルシューティングのセクションを確認してください。

 

 

Original Page: From random chunks to real code — wiring up Next.js source maps in Sentry

 

 




IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談は「お問い合わせ」からお気軽にお問い合わせください。

 

シェアする

Recent Posts