Node.js Express + Typescript へ ES Module を導入しようとした所、動かすのに随分手こずりました。正確にはある程度動かすのは簡単だったのですが型補完等を考慮すると推奨の方法だと warning は出るわでこだわった結果時間がかかりました(言い訳
Express + Typescript + ES Module で最終的に組んだ例を掲載します。
環境
- package.json の type に module は指定しない
- Express
- Typescript
- ES Module (今回は使おうとしていた symbol-sdk@3 を利用)
package.json ですが、 type: "module" を指定するのが正攻法だと思いますが、既存のプロジェクトへの組み込みを想定してここでは指定せずの例で記載しています。
準備
npm init -y
npm install express typescript symbol-sdk@3 @types/express
npx tsc --init
コード
tsconfig.json
module
は NodeNext
でお願いします
{
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"strict": true,
}
}
esmodule.ts
少し工夫しています。 import("module-name") 形式で読み込む必要があるのですが、利用する度に毎回読み込むのは非現実的なので、読み込み用の関数をここでは定義しました。
// @ts-ignore
let symbolSdk: typeof import("symbol-sdk").default;
export const loadSdk = async () => {
if (!symbolSdk) {
symbolSdk = (await import("symbol-sdk")).default;
}
return symbolSdk;
};
警告
typeof import
に ts-ignore をつけていますが、これをつけないと何故かエラーになります... await import("symbol-sdk")
の方はエラーにならないのに typeof だと出るのは何故に...?
index.ts
esmodule.ts を利用する側の express の記述です。 ES Module は直接 import せずに先程定義しました loadSdk 関数側を読み込んでいます。
import { loadSdk } from "./esmodule";
import express from "express";
const app = express();
const port = 3000;
app.get("/", async (_, res) => {
const sdk = await loadSdk();
res.send(new sdk.facade.SymbolFacade("mainnet").network.name);
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
これで準備が出来ました。ここで少し悩んだ部分があります。 ts-node で実行したいなと考えており、公式の手順だと次が推奨されています。
npx ts-node-esm ./src/index.ts
まず、これは動きませんでした。
もう1パターンがこれ。これは動きました。
node --loader ts-node/esm ./src/index.ts
しかし、このパターンは動くものの、 node.js 側でこの方法は非推奨であるとずっとログが出てしまうんですね。
ということで最終的に ts-node は諦め、オーソドックスな以下にしました。
npx tsc
node ./src/index.js
もし ts-node を利用しても問題ない方法をご存知の方がおりましたら是非コメント等で教えて欲しいのですが、取り急ぎこれで開発はしようと思うので、一旦まとめになりました。
まとめ
ということで、上記で Express + Typescript + ES Module を実行させる方法になりました。 ライブラリが ES Module にしか対応していないケースはまだまだ稀ではありますが、同じように困った方がいれば是非参考になれば幸いです。