LoginSignup
1
1

More than 1 year has passed since last update.

TypeScriptやJavaScriptに記述したrequireをRollupの出力に含める方法3選

Posted at

きっかけ

TypeScriptやJavaScriptに記述したrequireをRollupでバンドルした時、出力にrequireしているファイルが含まれませんでした。
調査して得られた3通りの解決方法をまとめます。

// 解決したいこと: これがRollupの出力にこのまま出てきてしまった (一つのバンドルファイルにまとめてもらえなかった)
const sample = require("sample.js") 

使用したRollupとRollupプラグイン

いずれも執筆日2022-09-25の最新バージョンです。

サンプルリポジトリ

今回扱う全てのソースコードはGitHubに格納してあります。
動作検証を目的としてメソッド実行やログ出力を含んでいますが、この記事で論点としている処理は同じ記述としてあります。
ljourm/sample-rollup-typescript-require

結論

最初に結論をまとめます。

No. 方法 使用条件 バンドル後のrequire サンプルコード(GitHub)
00 Rollupオプションなし 特になし requireがそのまま出力される(実行するとエラー) 00-first-issue
01 plugin-commonjsextensions: [".js", ".ts"]を指定 tsconfigで"module": "CommonJS"を設定 バンドルされる 01-include-ts-js
02 plugin-commonjstransformMixedEsModules: trueを指定 JavaScriptのみを使用 バンドルされる 02-only-js
03 02の設定 + requireをJavaScriptに記述し、それをTypeScriptからimport JavaScriptとTypeScriptをハイブリッドで使用 バンドルされる 03-use-loader

前提として、そもそもrequireを使うべきではない

可能な場合は require (CommonJSの記法) を廃止し、 import (ES Modulesの記法) の使用に切り替えるべきです。
公式ドキュメント、GitHub Issue、StackOverflowなどを参照していくと、どこもimportの使用に誘導されていました。

それでもrequireしなければならない時がある

ですが、先日私が出会ったケースでは以下のような制約・条件となっていました。

  • CommonJSのライブラリを使用している。
  • そのライブラリはベンダー製で、こちらで変更することができない。
  • JavaScriptでなくTypeScriptから使用したい。

検討した上でrequireの継続使用を決定し、問題解消の調査に進みます。

問題となったソースコード

作成したソースコード

calculator.js
// a + b するだけの簡単なサンプルメソッドをexportしている
module.exports.add = function (a, b) {
  return a + b;
};
index.ts
export const output = () => {
  // requreによってcalculator.jsを読み込む
  const { add } = require("./calculator.js");

  // 以降、addメソッドを使って何かする
};

Rollupの出力結果

index.js
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var output = function () {
    // requreによってcalculator.jsを読み込む
    require("./calculator.js").add; // !!!!ポイント!!!!

  // 以降、addメソッドを使って何かする
};

exports.output = output;

requireがaddメソッドに置き換わることを想定していましたが、そうはなりませんでした。
このコードを実行するとrequire("calculator.js")でファイルを読み込めず、エラーが発生します。

このrequireをaddメソッドに置き換えることが、この記事の目標です。

解決方法

01: plugin-commonjsextensions: [".js", ".ts"]を指定

まずは、今回紹介する中でTypeScriptにrequireを記述できる唯一の方法です。
サンプルコード: 01-include-ts-js

たいていの場合、プラグイン@rollup/plugin-commonjsを使っていると思います。
このプラグインのオプションextensionsを変更する方法がplugin-typescriptのドキュメントで紹介されていました。

公式ドキュメント: @rollup/plugin-typescript #Importing CommonJS

プラグイン 変更するオプション デフォルト値 変更後
@rollup/plugin-commonjs extensions(読み込み対象の拡張子) ['.js'] ['.js', '.ts']

ただし、これを実現するためにはtsconfig.json"module": "CommonJS"と設定することも必須のため、適用できないケースも多いと思います。
ドキュメントにもit is not recommended(=推奨していない)とあり、バンドル時に"module": "esnext"の使用を推奨する警告も表示されました。

02: plugin-commonjstransformMixedEsModules: trueを指定

次はTypeScriptのことを考えず、JavaScriptとしてrequireを使用する方法です。
サンプルコード: 02-only-js

これも先ほどと同じく、プラグイン@rollup/plugin-commonjsのオプションから設定します。

公式ドキュメント: @rollup/plugin-commonjs #transformMixedEsModules
参考記事: かもメモ Rollup require がバンドルされないにハマる

プラグイン 変更するオプション デフォルト値 変更後
@rollup/plugin-commonjs transformMixedEsModules false true

TypeScriptを使用しない場合はこれで全て解決ですが、今回の目標ではTypeScriptの使用を継続したいため、さらに別の方法の模索へと進みます。

03: 02の設定 + requireをJavaScriptに記述し、それをTypeScriptで読み込む

最後に実際に採用した方法です。
これによってTypeScriptとrequireによって参照するCommonJSの共存が実現できました。
サンプルコード: 03-use-loader

この方法ではJavaScriptとTypeScriptのハイブリットによって解決を図ります。
RollupのオプションはNo.2と同じですが、自分にとっては発想の転換が必要だったため、別の方法として記載します。

ソースコード

transformMixedEsModulesが結果的にJavaScriptのみに適用される特性に着目し、requireとexportだけを実現するJavaScriptファイルを新たに作成しました。

calculator-loader.js
// このファイルではrequireした結果をexportするのみとする
export const loadCalculator = () => {
  return require("./calculator.js");
};

そして、作成したJavaScriptをTypeScriptから読み込みます。

index.ts
import { loadCalculator } from "./calculator-loader";

export const output = () => {
  const { add } = loadCalculator();

  const result = add(1, 2);
};

これによってTypeScriptとrequireによって参照するCommonJSの共存が実現できました。
No.1のようなtsconfig.jsonの変更も不要です。

最後に

全部がモダンで綺麗なプロジェクトばかりならよいのですが、そうでないケースもどうしてもあります。
同じようなケースでお役に立てたら幸いです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1