例えばこのサイトだとIntersectionObserver
を使っていて、これはスマホなどでまだ対応しておらず見れないことが多いので含めています。
なぜ Webpack の entry に含めたいのか
<script>
での読み込みは Lighthouse のスコアを下げる
HTMLで以下の Polyfil を読み込むことで、IntersectionObserver
を対応していないサイトでも使えるようにできます。
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
しかしこれは、Minimize Critical Requests Depthとして引っかかってしまいます。
NextJS の entry ファイルのルートで Polyfil を読み込む
上のnpm版である、intersection-observerを使います。
Polyfil は基本エントリーの最初に読み込むファイルの先頭にimport
を記載すれば使えるので、_app.[jt]sx?
をその形にすれば使えそうです。しかし、この Polyfil は中で window
オブジェクトへアクセスしている部分があり NextJS ではその_app
ファイルも SSR で使われるので、 「window
がundefined
だよ」なエラーが起こってしまうのでこれも駄目です。
// _app.tsx
import 'intersection-observer';
NextJS の Webpack-Config の entry に含める
next.config.js
からwebpack
設定を自身の設定で上書きする方法です。
next.config.js
のデフォルトentry
は() => Promise<{[x: string]: string[]}>
な形をしていて、このオブジェクトを上書きすれば良さそうです。以下は戻り値の例です。
Promise {
{ 'main.js': [],
'static/runtime/main.js':
[ '/Users/nju33/github/blog/node_modules/next/dist/client/next-dev' ],
'static/development/pages/_app.js': [ './pages/_app.tsx' ],
'static/development/pages/_error.js':
[ '/Users/nju33/github/blog/node_modules/next/dist/pages/_error.js' ] } }
このmain.js
へ含めてます。
{
webpack: config => {
const originalEntry = config.entry;
config.entry = () => {
return originalEntry().then(entry => {
entry['main.js'] = 'intersection-observer';
return entry;
}
}
}
}
ただまだこれだと、サーバーサイド用のビルドファイルにもintersection-observer
Polyfil が含まれてしまい、上記と同じエラーが起きてしまうので、含めるのは Client 用のビルドファイルだけにする必要があります。
幸いにも、next.config.js
のwebpack
関数は第二引数にoptions.isServer
というフラグを渡してくれます。これは Client 用のビルド時にはfalse
になってくれるフラグです。
つまり、
options.isServer
がtrue
のときは、デフォルトのままのentry
を返すfalse
のときは、intersection-observer
を含める
とすれば解決できそうです。config.entry
を以下のように改良してみます。
{
webpack: (config, {isServer}) => {
const originalEntry = config.entry;
config.entry = () => {
if (isServer) {
return originalEntry;
}
return originalEntry().then(entry => {
entry['main.js'] = 'intersection-observer';
return entry;
}
}
}
}
上のように変更したところ Lighthouse のスコアがあがり、かつIntersectionObserver
に対応していない端末も対応することができました。