かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Rollup require がバンドルされないにハマる

Rollup を使って JS をビルドしていたのですが CommonJS 形式の require が解決されずそのまま出力されてしまう問題にハマったのでメモ

環境

  • rollup v2.77.2
  • @rollup/plugin-node-resolve v13.3.0
  • @rollup/plugin-commonjs v22.0.1

rollup.config.js

import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

const config = {
  input: './src/main.js',
  output: {
    file: './build/bundle.js',
    format: 'esm'
  },
  plugins: [nodeResolve(), commonjs(),]
};

export default config;

🙆 CommonJS (require) のみの場合は OK

sub.cjs.js

exports.sub = (x, y) => {
  return x - y;
};

main.js

const { sub } = require('./sub.cjs');

const x = sub(10, 5);
console.log(x);

👇 ビルド npx rollup -c

/build/bundle.js

var main = {};
var sub_cjs = {};
const sub$1 = (x, y) => {
  return x - y;
};
sub_cjs.sub = sub$1;

const { sub } = sub_cjs;
const x = sub(10, 5);
console.log(x);

export { main as default };

🙅 ESM (import) と CommonJS (require) が混在すると NG

sum.js

export const sum = (x, y) => {
  return x + y;
};

main.js

import { sum } from './sum';
const { sub } = require('./sub.cjs.js');

const a = sum(1, 2);
console.log(a);

const b = sub(10, 5);
console.log(b);

👇 ビルド npx rollup -c

/build/bundle.js

const sum = (x, y) => {
  return x + y;
};
const { sub } = require('./sub.cjs.js');

const a = sum(1, 2);
console.log(a);

const b = sub(10, 5);
console.log(b);

require 文がそのまま残ってしまう
main.js で import より先に const { sub } = require('./sub.cjs.js'); を書いても同様

importrequire が混在する場合は transformMixedEsModules オプションを true にする必要がある

transformMixedEsModules
Type: boolean
Default: false

Instructs the plugin whether to enable mixed module transformations. This is useful in scenarios with modules that contain a mix of ES import statements and CommonJS require expressions. Set to true if require calls should be transformed to imports in mixed modules, or false if the require expressions should survive the transformation. The latter can be important if the code contains environment detection, or you are coding for an environment with special treatment for require calls such as ElectronJS. See also the "ignore" option.
cf. https://github.com/rollup/plugins/tree/master/packages/commonjs#transformmixedesmodules

rollup.config.js を修正する

import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

const config = {
  input: './src/index.js',
  output: {
    file: './build/dist.js',
    format: 'iife',
  },
-  plugin: [commonjs(), nodeResolve()],
+  plugins: [
+    nodeResolve(),
+    commonjs({
+      transformMixedEsModules: true,
+    }),
+  ],
};

main.js

import { sum } from './sum';
const { sub } = require('./sub.cjs.js');

const a = sum(1, 2);
console.log(a);

const b = sub(10, 5);
console.log(b);

👇 ビルド npx rollup -c

/build/bundle.js

var sub_cjs = {};
const sub$1 = (x, y) => {
  return x - y;
};
sub_cjs.sub = sub$1;
const sum = (x, y) => {
  return x + y;
};
const { sub } = sub_cjs;

const a = sum(1, 2);
console.log(a);

const b = sub(10, 5);
console.log(b);

npm パッケージを require で読み込んでも大丈夫っぽい

懐かしの jQuery を npm でインストールしたものを使ってみる
cf. jquery - npm

& npm i jquery

パッケージの中を見てみると export とかがされている訳ではなく return jQuery の様になっていた import $ from "jquery"; も使えるようだけど敢えて const $ = require( "jquery" ); で読み込ませる

main.js

const $ = require('jquery');
import { sum } from './sum';
const { sub } = require('./sub.cjs.js');

const a = sum(1, 2);
console.log(a);

const b = sub(10, 5);
console.log(b);

$(() => {
  const btn = $('.btn');
  btn.on('click', () => {
    console.log('clicked!');
  });
});

👉 ビルド npx rollup -c

ビルドされた JS を簡易な HTML で読み込ませて <button class="btn"> がクリックされた時にコンソールに clicked! が出力されることを確認できれば恐らくOK!

所管

最初 require がバンドルされずにハマっていたのですが明示的にオプションを指定してあげなければならないだけでした。ドキュメント…ちゃんと読もう… (いつものこと)

おわり


[参考]

https://chaika.hatenablog.com/entry/2022/08/08/083000

(神クズ☆アイドル おもしろい)