Wonder Code

プログラミングとか、PCについてが多いかな

ECMAScript Module (ESM)がimportしようとしたらハマった

久々にブログ書く

下のようなコードをECMAScript Module(ES Module、ESMともいう)をimportしようとしたらハマってしまったので書いておく。

//hello.mjs
function hello() {
    console.log("Hello");
}

export { hello }
<!DOCTYPE html>

<!-- hello.html -->

<html lang="ja">
    <head>
        <meta charset="utf-8">
        <script type="module">
            import { hello } from './hello.mjs'
        </script>
    </head>
    <body>
    </body>
</html>

TL;DR

うまくインポートできなかった原因

  1. ローカルから(Webサーバなしで)Moduleを読み込もうとしてた
  2. .mjs(Moduleの拡張子)のMedia TypeがPythonのhttp.serverでサポートされてなかった

ハマった

hello.htmlをChromeで開くと

Access to Script at 'file:///C:/Users/username/Programming/jsworks/es_module/hello.mjs' from origin 'null' has been blocked by CORS policy: 
Invalid response. Origin 'null' is therefore not allowed access.

というエラー。 調べてみるとどうもAccess Originがnullになっているために読み込んでいないようでした。  同じオリジンからでないと読み込まないようなので pythonを使ってWebサーバを立ち上げてAccess Originを同じlocalhost:8000にしてもう一度やってみました。

しかし、これが別のエラーの原因になろうとは、まだ知る由もなかった

気を取り直して、Webサーバー起動して、localhost:8000/hello.htmlを開いてみると また別のエラーが出ていました。

Failed to load module script: The server responded with a non-JavaScript MIME type of "application/octet-stream". 
Strict MIME type checking is enforced for module scripts per HTML spec.

これもググってみたら、どうもModuleのMIME Typeにはjavascriptという文字列が含まれていないといけないようなのですが、 Pythonのhttp.serverのMIME typeの一覧には、まだ.mjsがなく、その代わりにapplication/octet-streamを送ってしまうためエラーになるようです。 そこで一時的に.mjsを.jsに変更したらきちんと動きました。

ちなみに、http.serverのmimetypeの対応づけはmimetypesというPythonの標準ライブラリを使っているようで、 その中にまだ.mjsがないために発生するエラーのようです。(Python3.7.0時点) もうすでにpull reqは出ているようなので()3.8では直っていると思われます。

終わりに

こんな感じでハマってしまいましたが、JavaScriptには言語にモジュールの仕組みがなかったので(Node.jsのCJSなどもありますが、あれはNode.jsの仕様なのでカウントしない)もっと流行ってほしいです。