commonjs で esnext なパッケージを一緒に使う

対象

cjs で書かれている。つまり以下のように書かれてるもの。例えば、sindresorhus/ky

module.exports = /* ... */

esnext なobject-rest-spread-propertiesなどが使われてる。

// 例: ky/index.js
returnValue = {...returnValue, [key]: value};

問題

  • 対象のファイルを Babel で変換しないとエラー
  • 依存のnext-babel-loaderの中でnextが読み込む.babelrcの設定がmodules:falseなので変換できても cjs が解決できない
  • next.config.js上で Babel の設定を上書きできない
  • .babelrcでは処理的に 1 つの設定しか持てない
  • 自分のソースコードは cjs にしたくない
  webpack(config, {isServer}) {
    if (isServer) {
      return config;
    }

    config.module.rules.map(rule => {
      if (
        rule.test.test('.js') &&
        Object.prototype.hasOwnProperty.call(rule, 'exclude') &&
        rule.exclude.test('node_modules')
      ) {
        rule.exclude = /node_modules\/(?!ky)/;
        // Module build failed: Error: Duplicate plugin/preset detected.
        rule.options = {
          presets: ['next/babel', {
            'preset-env': {
              modules: 'commonjs'
            },
          }]
        }
      }
      return rule;
    });

    return config;
  },

解決

やっぱりこれだけにルール追加するぐらいしかなかった。(読み込んでるプラグインなどはデフォルトの設定と同じもの)

  webpack(config, {isServer}) {
    if (isServer) {
      return config;
    }

    config.module.rules.unshift({
      test: /\.jsx?$/,
      include: /node_modules\/ky/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: [
            '@babel/plugin-proposal-class-properties',
            '@babel/plugin-proposal-object-rest-spread',
            '@babel/plugin-transform-runtime',
          ],
        },
      },
    });

    return config;
  },