🌵

【Next.js】みんな next.confing.js にどんなプラグイン入れてる?

2021/07/17に公開

https://twitter.com/aiji42_dev/status/1415711986608795648?s=20



Why Next.js

私は、業務でもプライベートでも Next.js を使っています。
Next.js は "Zero Config" をうたっているわけですが、実際業務で使うとなると、なかなか Zero とはいきません。IE11用にトランスパイルが必要になったり、ソースマップのアップロードのために webpack の拡張が必要なるケースにおいては、next.config.js のカスタマイズが必要になります。

そういったカスタマイズをサポートし、設定のストレスから我々エンジニアを開放してくれるパッケージが世の中にはたくさんあります。ということで、自分以外の方々が next.config.js にどのようなプラグインを入れているか気になりました。

まずは、自分がどのようなプラグインを入れているかシェアしたいと思います。
「自分はこんなプラグイン入れていて便利ですよ」みたいなシェアを、Twitter や Zenn のコメントでお待ちしております。

1. @next/bundle-analyzer (バンドルアナライザ)

https://github.com/vercel/next.js/tree/canary/packages/next-bundle-analyzer

Next.js が公式に提供しているバンドルアナライザです。
Next.js を利用しているエンジニアの方々は昨今のパフォーマンス事情に対しての関心が高いと思いますので、分析に活用しているという人は多いと思います。

こんな感じで設定をします。

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({
  // next.jsの設定
})
ANALYZE=true yarn build 

と実行してあげることで、サーバサイドとクライアントサイドのバンドルマップを作成すると同時に、自動的にブラウザを立ち上げてくれます。

サーバーサイド クライアントサイド

不要なモジュールがバンドルされていないか、あるいは一部ページでしか使われていないモジュールが共通部分にバンドルされていないかなどを確認して、パフォーマンス改善に役立てましょう。

あるコンポネントを Dynamic Import で退避したにも関わらず、関連ソースのインポートを普通の import で書いてしまっており、実は共通スクリプトにバンドルされてしまっていた…というあるあるミスも、対象のモジュールがチャンクに分割さているか確認することで防げます。

2. next-transpile-modules (モジュールトランスパイル)

https://github.com/martpie/next-transpile-modules#readme

node_modules 内の指定パッケージを、ビルド時にトランスパイルするためのプラグインです。
IE11のサポートが来年2022年の6月で終了しますが、サービスの特性上IEでの動作を考慮し続けなければいけないという状況もあると思います。
モジュールによってはトランスパイルしないとIEで動かないものもありますので、そうったものを対象に指定して使用します。

const withTM = require('next-transpile-modules')([
  'somemodule',
  'and-another'
])

module.exports = withTM({
  // next.jsの設定
})

私のプロジェクトでは、@react-google-maps/api 内で使用されている、@googlemaps/js-api-loader や、fill-range 内の to-regex-range などがトランスパイルが必要であるため、これらを対象にしてしています。

const withTM = require('next-transpile-modules')([
  '@googlemaps/js-api-loader',
  'to-regex-range'
])

https://github.com/martpie/next-transpile-modules#compatibility-table

3. next-with-split (A/Bテスト自動化)

https://github.com/aiji42/next-with-split#ab-next-with-split

ブランチベース・CDNベースでA/Bテストを行うためのプラグインです。
何を隠そう、この記事を書いている私自身がオーナーのプラグインです。

以前、こちらの記事で紹介をさせていただいているのですが、
https://zenn.dev/aiji42/articles/d635ce025efdd2
この記事時点から2度メジャーアップデートを重ねており、導入ステップがスムーズになっただけでなく、Vercel意外のプロバイダーにも対応していたりと、さまざまな問題が解消されています。(上の記事の情報は古く、設定方法が異なるためご注意ください。参考情報として貼っておきます。)

ブランチベースのA/Bテストであるため、チャレンジャーのコードとオリジナルのコードは、Gitのブランチ上で完全に切り分けて管理することが可能です。そのため、バンドルサイズの増加を防げますし、何より管理が楽なので開発体験がよくなります。

設定方法はこんな感じです。

const withSplit = require('next-with-split')({
  splits: {
    example1: {
      path: '/foo/bar/:path*',
      hosts: {
        original: 'example.com',
        challenger: 'challenger-for-example1.vercel.app',
      }
    }
  }
})

module.exports = withSplit({
  // next.jsの設定
})

詳しくは README を参照してみてください。
https://github.com/aiji42/next-with-split#ab-next-with-split

4. @sentry/nextjs (エラー捕捉・分析)

エラーの補足に Sentry を利用している方も多いと思います。
https://sentry.io/welcome/

今年の春まで公式のサポートがなく、Next.js に導入する場合には、サーバーサイドには @sentry/node を、クライアントサイドには @sentry/browser を入れることで対応するのが一般的でした。(webpackの設定でエイリアスを書き換えて2つを出し分けるというウェブパッ筋が必要でした。懐かしいですね。)
しかし、ついに公式のサポートが行われ、webpackの拡張性っていが不要になっただけでなく、ウィザードコマンドによってトークンやDSN値の取得と展開を自動で行ってくれます。(なんと自前でSentryをホストしているケースにも対応しています。)

導入は、yarn(もしくはnpm)で @sentry/nextjs をプロジェクトに追加したあとに、次のコマンドを叩きます。

npx @sentry/wizard -i nextjs # 自動的にブラウザが立ち上がるのでログインする

# 自前で Sentryサーバをホストしている場合はこちら
npx @sentry/wizard -i nextjs --url ${ここに自前のURLを}

そうしますと、 sentry.client.config.js sentry.server.config.js sentry.properties これら3つのファイルが自動生成されます。順番に、サーバサイド用の設定ファイル、クライアントサイド用の設定ファイル、共通の設定値(トークンなど)の設定ファイルです。

そして、 next.config.js に次のような設定を施します。

const { withSentryConfig } = require('@sentry/nextjs')

module.exports = withSentryConfig({
  // next.jsの設定
}, {
  // Sentery の webpack に関する設定
})

こちらは主にソースマップに関しての設定になります。

その他、詳しい設定に関しては公式のドキュメントを参考にしてください。
https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/

補足1

2021/07/17 現在の最新バージョンである、v6.9.0 においては、next config の target値を serverless にしていると、ビルドが失敗してしまいます。
Vercel でデプロイ指定分には問題ないと思いますが、serverless-nextjsなどを利用している場合には注意が必要です。

https://github.com/serverless-nextjs/serverless-next.js/issues/1038

ちなみに、私はプレビュー環境にのみ serverless-nextjs を利用しており、次のような方法で問題を回避しています。
https://twitter.com/aiji42_dev/status/1415702271485124614?s=20

補足2

前述した @next/bundle-analyzer との相性が悪く、同時に稼働させるということができないようです。(併用していても ANALYZE=true で起動しない限りは問題ありません。)

そのため、process.env.ANALYZE === 'true' が正となるケースで、withSentryConfig がダミーモジュールになるようにコントロールしてあげるなどの工夫が必要です。(私はこんな感じで回避しています)

const { withSentryConfig } =
  process.env.ANALYZE !== 'true'
    ? require('@sentry/nextjs')
    : { withSentryConfig: (config) => config }

番外編: next-compose-plugins

https://github.com/cyrilwanner/next-compose-plugins

これまで、4つのプラグインを紹介しましたが、複数のプラグインを同時に使用する場合には、複数のネストが発生してしまい可読性が下がってしまいます。
そういった場合に、この next-compose-plugins を使用すると、プラグインを束ねることが可能です。

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
})
const withTM = require('next-transpile-modules')([
  'somemodule',
  'and-another'
])
const withSplit = require('next-with-split')({
  splits: {
    example1: {
      path: '/foo/bar/:path*',
      hosts: {
        original: 'example.com',
        challenger: 'challenger-for-example1.vercel.app',
      }
    }
  }
})
// withSentryConfig だけ、引数の数が異なるためカスタマイズが必要
const withSentryConfig = (config) => {
  // withBundleAnalyzer とのバッティング回避
  if (process.env.ANALYZE === 'true') return config
  return require('@sentry/nextjs').withSentryConfig(config, {
    // Sentery の webpack に関する設定
  })
}

const withPlugins = require('next-compose-plugins')
// ネストしたい順に配列に渡すだけ
module.exports = withPlugins([
  withSplit,
  withTM,
  withSentryConfig,
  withBundleAnalyzer
], {
  // next.jsの設定
})

最後に

いかがでしたでしょうか?
冒頭にも記載したように、「自分のプロジェクトではこんなプラグインを使っているよ」みたいな紹介等ございましたら、コメントやTwitterで返信ください。

GitHubで編集を提案

Discussion