Marginalia

webpack と ES Module Import Assertions についての調査

ES Moduleの Import Assertions が各環境で使えるようになるのも遠くない。

しかし現実のユースケースではまだまだモジュールバンドラーを使ってデプロイ前にモジュール解決を済ませることが多いだろうから、Import Assertionsを直接ブラウザ上で使用することは少ないだろう。

というわけでソースコードで Import Assertionsを使ったときに、webpack によるモジュール解決がどのように振る舞うかを調べてみた。なぜ調べる必要があったかというと、ドキュメンテーションが(そこそこ探した限りでは)見つからず、ブログなどのアンオフィシャルなものすら見当たらなかったからだ。だが、GitHubの履歴を見ると間違いなくImport Assertionsに対応する実装は加えられていたので、実態がどうなっているかは実際に動かして試すこととなった。

アサーションなし(ファイル拡張子による判別)

data.json ファイルを拡張子付きのパスでインポートする。webpackはJSONのインポートをビルトインでサポートしており、これはそのまま自動的にJSONとしてパースされる。

data.jsonのインポート(アサーションなし)
data.jsonのインポート(アサーションなし)

インポートのパスで拡張子を省略していても、デフォルトのwebpack設定が .json の省略を許可しているので自動的に探索され、ファイルの拡張子からJSONであることを判別する。

data.jsonのインポート(アサーションなし、拡張子省略)
data.jsonのインポート(アサーションなし、拡張子省略)

つまり、ファイルの拡張子を削除するとwebpackはそのファイルがJSONであることがわからなくなり、モジュールのパースに失敗する。次の例では ./data ファイルをインポートしようとしてパースできずにエラーになっている。

dataのインポート(アサーションなし、拡張子なし)は失敗する
dataのインポート(アサーションなし、拡張子なし)は失敗する

アサーションあり ( JSON )

ここからは Import Assertions によるファイル形式のアサーションを試みる。 assert { type: 'json' } を付与し、先ほどの拡張子がないJSONファイルのインポートをすると、JSONであることを判別し、問題なくパースできていた。(エディタ上の赤線は無視してほしい)

dataのインポート(JSONアサーションあり)は成功する
dataのインポート(JSONアサーションあり)は成功する

その他のファイル形式のアサーション

webpackといえば Loader によってさまざまな形式のファイルをモジュール解決できるのが魅力だ。webpackの Import Assertions はJSON以外にも対応しているのか一応試してみた。

JSONの拡張であるJSON5のファイル data.json5 をパースできるか試してみた。事前に json5-loader をインストールした上で、特にwebpack設定には手を入れずに type: 'json5' を指定してみたが、これではモジュール解決できなかった。エラーを見るに、JSONとしてパースしようとして失敗したようだ。なぜJSONだと解釈したのだろうか?

data.json5のパース(アサーションあり)は失敗
data.json5のパース(アサーションあり)は失敗

次に、 styles.postcss というファイルを用意し、さらにwebpack設定に .css ファイルについてのルールを追加した(一般的な style-loadercss-loader を通すもの)。そのうえで、 styles.postcss ファイルを type: 'css' だとアサーションしてインポートするとどうなるかを試してみた。

結果は以下のように、 .postcss ファイルに対応する Loader がないためにパースできずエラーとなった。アサーションによって Loader を切り替えるようなことは(少なくとも今は)できないようだ。

cssであることをアサーションで教えることはできなかった
cssであることをアサーションで教えることはできなかった

現状の結論

webpackのImport Assertions対応は、現状では JSON 形式のアサーションだけが可能なようだ。そもそも拡張子さえあればもともとJSONのインポートはビルトインサポートされていることから、この対応で何か新しい機能が増えているわけではない。

開発者はこれまでどおりアサーションなしにインポートしてもよいが、それはwebpackが気を利かせてくれているだけだ。そしてwebpack以外でもJSONを読み込める標準化された記法に切り替えるという選択肢も用意されている、ということだろう。

今回の調査は Stackblitz上の Node.js 環境で行った。再現したい場合はこちらを参照されたし。