Next.jsのSWCコンパイラでPolyfillの自動挿入はできるのか
Next.jsのSWCコンパイラでPolyfillの自動挿入はできるのか
2024/05/18

この記事はNext.js@14.2での調査結果になります。

Next.jsでPolyfillを自動挿入できるか

結論から言うと、SWCを使用している場合はPolyfillを自動挿入する設定はありませんでした。

Babelを使用している場合は、設定次第でPolyfillを自動挿入することが可能です。
https://babeljs.io/docs/babel-preset-env#usebuiltins

そもそも、SWCでPolyfillの自動挿入はできる?

純正のSWCでもBabel同様の機能を提供しています。

.swcrcにtargetとmodeを指定すると、トランスパイル結果にPolyfillが挿入されます。

{
    "env": {
        "targets": "Chrome >= 48, Safari > 9",
        "mode": "usage"
    }
}

以下のような、新しめのメソッドを使ったコードで試してみます。

const hoge = "hoge"

console.log(hoge.replaceAll("1", "2"))

const arr = [1, 4, 3, 2].toSorted()

トランスパイル後のコードは次のようになります。

npx swc ./index.js の出力結果:

import "core-js/modules/es.string.replace.js";
import "core-js/modules/es.regexp.exec.js";
import "core-js/modules/es.array.sort.js";

var hoge = "hoge";
console.log(hoge.replaceAll("1", "2"));
var arr = [1, 4, 3, 2].toSorted();

文頭にcore-jsのPolyfillコードが注入されました。

Next.jsでenvの設定ができないのか

Webpackの設定からSWCのオプションであるenvを指定できれば、Polyfillの自動挿入が可能と考えました。

Next.jsのドキュメントにはSWCローダーに関する記載がなかったため、実装の方を調査しました。

next.config.jsの出力結果から探る

next.config.jsからWebpackをカスタマイズできるので、ログを仕込んで確認します。

webpack: (config, options) => {
    if (options.isServer) {
        return config;
    }

    console.dir(config.module.rules, { depth: 5 });
    
    return config;
}

出力された結果から、それらしきものを発見しました。

{
    test: { or: [/\.(tsx|ts|js|cjs|mjs|jsx)$/, /__barrel_optimize__/] },
    include: [
        '/myproject/path',
        /next[\\/]dist[\\/](esm[\\/])?shared[\\/]lib/,
        /next[\\/]dist[\\/](esm[\\/])?client/,
        /next[\\/]dist[\\/](esm[\\/])?pages/,
        /[\\/](strip-ansi|ansi-regex|styled-jsx)[\\/]/
    ],
    exclude: [Function: exclude],
    use: [
        {
            loader: 'next-swc-loader',
            options: {
                isServer: false,
                rootDir: '/myproject/path',
                pagesDir: '/myproject/path/src/pages',
                appDir: undefined,
                hasReactRefresh: false,
                nextConfig: [Object],
                jsConfig: [Object],
                transpilePackages: [Array],
                supportedBrowsers: [Array],
                swcCacheDir: '/myproject/path/.next/cache/swc',
                serverComponents: true,
                esm: false
            }
        }
    ]
}

next-swc-loaderがSWCでコードをトランスパイルしてると予想できます。

next-swc-loaderの実装を探す

GitHubからコードを探します。

Webpackのオプションを生成している箇所:
https://github.com/vercel/next.js/blob/v14.2.3/packages/next/src/build/webpack-config.ts#L426

next-swc-loader:
https://github.com/vercel/next.js/blob/v14.2.3/packages/next/src/build/webpack/loaders/next-swc-loader.ts

SWCオプションに変換している箇所:
https://github.com/vercel/next.js/blob/v14.2.3/packages/next/src/build/webpack/loaders/next-swc-loader.ts#L115

getLoaderSWCOptions:
https://github.com/vercel/next.js/blob/v14.2.3/packages/next/src/build/swc/options.ts#L324

next.config.jsから設定できるオプションをSWCオプションに置換している箇所まで辿り着きました。
https://github.com/vercel/next.js/blob/v14.2.3/packages/next/src/build/swc/options.ts#L454-L474

そして一番重要なenvの部分が以下のように記述されていました。

...(supportedBrowsers && supportedBrowsers.length > 0
    ? {
        env: {
            targets: supportedBrowsers
        }
    }
    : {}),

Polyfillを挿入するにはenv.modeを設定する必要がありますが、追加する余地がありませんでした。

結論

残念ながら、Next.jsのSWCコンパイラではPolyfillの自動挿入を設定することができませんでした。

SWCのオプションを設定したい要望はいくつか上がってるので、いつかできるようになると良いですね。

https://github.com/vercel/next.js/discussions/46979
https://github.com/vercel/next.js/discussions/30413
https://github.com/vercel/next.js/discussions/30940