at backyard

Color my life with the chaos of trouble.

ts-loader(webpack)を用いてのTypeScript開発の際、Node.js実行のためのshebangでTypeScriptのコンパイルエラーが起きたときの対応メモ

なんだかタイトルが長ったらしくなってしまった。

Node.js製のCLIツールを作っていた。 npmにてリリースして、globalインストールして使う予定だ。

そちらのツールに関する内容は本題ではないので、一旦そちらは脇にどけておく。
(たぶん、またどこかでそれについても書くと思う。ってか、このあと、話題に関係する形でコミット内容をしれっと貼らせていただきます。だけども、まだ開発段階です。)

そのようなツールを作る場合、Node.jsではファイルの先頭に shebang を記述して、実行環境のnodeを参照するようにする必要がある。

#! /usr/bin/env node

今回このような形式のNode.jsのCLIツールをTypeScriptで書いていた。 ビルド環境はwebpack。ts-loader を用いてビルドしている。 ところがこの shebang を書いた状態でビルドすると、下記のようなエラーになってしまった。

Module parse failed: Unexpected character '#' (1:0)

shebang が認識されていないようだ。

下記のStack overflowの回答を元に対応した。

stackoverflow.com

stackoverflow.com

解決方法

shebang-loader をインストールする。

npm install --save shebang-loader

webpack側に設定する。 なお shebang-loader 自体はコンパイル時に shebang を消しているだけで、コンパイル後のソースに持っていってくれたりはしない。

shebang-loader/index.js at master · JavascriptIsMagic/shebang-loader · GitHub

そのためwebpack側で直接 shebangコンパイル後のソースにも追加するという、割と泥臭い対応を行う必要がある。
( shebang-loader 側では仕組み的にそこまで行うことは出来なそう?)

実際に書き換えたDiffが下記となる。

iff --git a/webpack.config.js b/webpack.config.js
index 3cbcad0..7978c19 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,3 +1,4 @@
+const webpack = require('webpack');
 const isProduction = process.env.NODE_ENV === "production";

 module.exports = {
@@ -8,7 +9,7 @@ module.exports = {
     rules: [
       {
         test: /\.ts$/,
-        use: ["ts-loader"],
+        use: ["ts-loader", "shebang-loader"],
         exclude: /node_modules/
       }
     ]
@@ -18,5 +19,8 @@ module.exports = {
   },
   output: {
     filename: "index.js"
-  }
+  },
+  plugins: [
+    new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true }),
+]
 };

これでビルドエラーがなくなり、コンパイル後のソースにも shebang が追加されたため、実行も問題なくできるようになった。

実際に対応した際のコミットはこちらになる。
(以前もこちらのブログに書いたかもしれないが、JUGEM XMLMarkdownに変換するためのツールとなります。)

github.com