はじめに
以前、(所属する会社の)ブログで書いた【Node.js】Expressでroutesの一覧を成形してログ出力してみたでやった、Expressに登録済みのルーティング(routes)を一覧でログに出力する機能をライブラリにしてみた。
今回は、そのライブラリ(パッケージ)を開発した際の
- TypeScriptをあきらめてJavaScriptで開発したこと
- ES Moduleで開発をしつつも、CommonJSでもパッケージを公開したこと
などを記事にしたいと思う。
※公開したパッケージは以下。
TypeScriptをあきらめた理由
これは実装を見ていただければわかる通りで、Expressの型定義でany
で定義されているapp._router
の中のプロパティにアクセスして実装する必要があるため。
export interface Application<
LocalsObj extends Record<string, any> = Record<string, any>
> extends EventEmitter, IRouter, Express.Application {
...
/**
* Used to get all registered routes in Express Application
*/
_router: any;
...
}
最初は頑張ってTypeScriptで実装しようと思ったが、型の恩恵のあるコードでもなく開発しているライブラリの関数の型定義自体はすごくシンプルなのでtsc
コマンドで型を作成するまでもないという判断で、JavaScriptで実装した。
ES Moduleで開発をしつつも、CommonJSでもパッケージを公開する
Node.jsでも"type": "module"
でES Moduleを利用して開発ができるようになった今、あえてCommonJSで開発する理由はないと思ったので、今回開発したパッケージもES Moduleで開発は行った。
ただ、とはいえ現時点でES ModuleではなくCommonJSでプロダクトコードを書いている方もいると思うので、パッケージとして公開する際は、CommonJS・ES Moduleの両方に対応したデュアルパッケージとして公開することにした。
方法は昔、Node.jsでES Moduleで開発をする際に行われていたBabelでトランスパイルをするという方法と同じ。つまり、BabelでES ModuleをCommonJSのJavaScriptに変換する方法をとった。具体的には、以下のようなBabelの設定をした上で、以下のようなコマンドでトランスパイルを行う。
module.exports = {
presets: [['@babel/preset-env', { targets: { node: 16 } }]]
};
$ babel index.js --out-dir cjs && echo '{\"type\":\"commonjs\"}' > cjs/package.json
上記のトランスパイルのためのコマンドで、echo '{\"type\":\"commonjs\"}' > cjs/package.json
を実行してpackage.jsonを新しく作成しているが、これはDual package hazardに書かれている方法でES ModuleとCommonJSを共存させるために行っている。
※デュアルパッケージとして公開する場合には、以下のようにpackage.jsonで公開するコードの設定も追加で必要になるので注意。
{
...
"types": "./index.d.ts",
"main": "./cjs/index.js",
"module": "./index.js",
"exports": {
".": {
"types": "./index.d.ts",
"import": "./index.js",
"require": "./cjs/index.js"
}
},
...
}