トラブルシュート

type="module"のJSが読み込めない・CORSで止まるときの対処

通常のscriptでは動いたのに、type=moduleにした途端にJSが読み込めず、ConsoleにCORS関連のエラーが出る。ESモジュールは通常のスクリプトより読み込みのルールが厳しく、配信環境の条件を満たさないと止まります。この記事では原因と確認手順をまとめます。

ESモジュールは通常のscriptと読み込みルールが違う

type=moduleを付けたスクリプトはESモジュールとして扱われ、importでファイルを参照したり、自動で遅延実行になったりと、通常のスクリプトと挙動が変わります。読み込みの厳しさも増し、配信元やMIMEタイプの条件を満たさないと実行されません。

特につまずきやすいのが、ローカルでファイルを直接開いた場合です。file:// で開くとモジュールの取得がブロックされ、HTTP(S)で配信しないと動かないことが多いです。まずはサーバー経由で開いているかを確認するのが出発点です。

なぜCORSが関係するのか

CORS(クロスオリジン制約)は、あるサイトから別のオリジンのリソースを読み込むときの安全ルールです。ESモジュールのimportはこの制約の対象になり、別オリジンのモジュールを読むには、配信側が適切な許可ヘッダを返している必要があります。

同じサイト内(同一オリジン)の相対パスなら基本的にCORSは問題になりません。エラーが出るときは、別ドメインのモジュールを直接importしていないか、あるいはfile://で開いてオリジンが特殊扱いになっていないかを疑います。

通常のscriptは画面表示の都合上ゆるく読み込めますが、モジュールは設計上CORSを必須とするため、同じファイルでも読み込み方が変わると挙動が分かれます。

症状別チェック表

type="module"のJSが読み込めない・CORSで止まるは、症状を分けずに直そうとすると原因探しが長引きます。まず「自分だけで起きるのか」「全員で起きるのか」「特定ブラウザだけか」「差し替え後だけか」を切り分けます。

確認順序を固定すると、相対パス、ファイル名、キャッシュ、認証、外部読み込みのどこで止まっているかが見えます。修正後はローカル確認だけで終わらせず、実際の共有URLで再表示して、相手と同じ条件で直ったことを確認します。

  • 自分だけ表示されない: キャッシュ、ログイン状態、ブラウザ拡張、端末幅を確認する
  • 全員で表示されない: ファイル構成、相対パス、大文字小文字、アップロード漏れを見る
  • 一部だけ崩れる: CSS/画像/JSごとに読み込みエラーを分ける
  • 差し替え後だけ古い: URL、キャッシュ、更新対象ファイルの取り違えを確認する

止まる原因を切り分ける手順

CORSと一口に言っても、実際にはパス・MIMEタイプ・オリジンのどれかでつまずいていることがほとんどです。次の順で確認します。

  1. F12のConsoleでエラー文を読み、CORSなのかMIMEタイプなのか取得失敗なのかを見分ける
  2. Networkタブで該当JSのステータスが200か、Content-Typeがjavascript系かを確認する
  3. importやsrcのパスが同一オリジンの相対パスになっているか確かめる
  4. 別ドメインを直接importしている場合は、同梱して相対パスに変えられないか検討する
  5. ローカル確認はfile://をやめ、HTTP(S)配信で開き直す

MIMEタイプの不一致に注意

ESモジュールは、サーバーが返すContent-Typeがtext/plainやoctet-streamなど不適切だと、JavaScriptとして実行されずに止まります。Networkタブで該当ファイルのContent-Typeを確認し、javascript系で返っているかを見ると、MIMEタイプ起因かどうかが分かります。

拡張子は.jsでも、配信側の設定によっては正しいMIMEで返らないことがあります。配信環境がモジュール向けのMIMEタイプを適切に付けてくれるかどうかは、type=moduleを使ううえで地味に重要なポイントです。

適切に配信される環境で確認する

ESモジュールはHTTP(S)配信と正しいMIMEタイプが前提なので、ローカルで直接開くだけでは本来の挙動を確認できません。本番に近い配信環境で開いて確かめるのが確実です。

ギガサイト便はCSSやJSを含むZIPをドロップすると 〇〇.giga-site.com でHTTPS配信され、同一オリジンの相対パスでモジュールを読み込めます。file://起因のブロックを避けて、Console・Networkでステータスやmime-typeを確認しながら切り分けられます。同じURLのまま差し替えられるので、import先を直しては再検証する反復もスムーズです。

よくある質問

通常のscriptでは動くのにtype=moduleだと止まるのはなぜですか

モジュールはCORSや配信元、MIMEタイプの条件が通常のスクリプトより厳しいためです。特にfile://で直接開くとブロックされやすく、HTTP(S)配信が前提になります。

同じサイト内の相対パスでもCORSエラーになりますか

同一オリジンの相対パスなら通常CORSは問題になりません。エラーが出るなら、別ドメインを直接importしていないか、file://で開いてオリジンが特殊扱いになっていないかを確認してください。

MIMEタイプが原因かどうかはどう確認しますか

Networkタブで該当JSのContent-Typeを見ます。javascript系でなくtext/plainなどになっていると、JavaScriptとして実行されず止まります。配信側のMIME設定を確認してください。

別ドメインのモジュールをimportしたいときはどうすればよいですか

参照先が適切な許可ヘッダを返している必要があります。難しい場合は、そのファイルを自分側に取り込んでZIPに同梱し、同一オリジンの相対パスでimportする方法が確実です。

原因が分からないときはどこから確認すべきですか?

まず自分だけの問題か全員の問題かを分けます。次にシークレットウィンドウ、別ブラウザ、スマホで確認し、ファイル構成・相対パス・キャッシュ・認証設定を順に見ます。

関連記事

トラブルシュート

CORSエラーで外部データが読めないときの対処

外部APIをfetchしたらCORSでブロックされた――誰が許可を出す必要があり、フロント側でできること・できないことの境界線はどこかを理解することで、対処方針を正しく判断できる記事です。

6分で読める
トラブルシュート

scriptのdefer/asyncで読み込み順が崩れて動かないときの対処

ライブラリより先に自分のコードが走ってエラーになり、deferとasyncのどちらを付けるべきか迷っている方向け。それぞれの実行タイミングの違いを図解で整理し、依存関係を壊さないスクリプトの並べ方を判断できるようになる記事です。

5分で読める
トラブルシュート

外部JSONの読み込みでパースエラーになるときの確認点

fetchはリクエスト成功なのにJSON.parseで落ちる、という謎のエラーに当たった方向け。Content-Typeの不一致・BOMの混入・HTMLが返ってくる状況など、パースが失敗しやすい原因をパターン別に挙げて確認手順を示します。

5分で読める
トラブルシュート

公開後にJavaScriptが動かないときの原因と直し方

ローカルでは動いていたボタンやアニメーションが公開後に反応しなくなった方向け。JavaScriptが止まる主な原因をファイルパスや読み込み順の観点で切り分け、自分で直せるかどうかを判断できます。

5分で読める
トラブルシュート

公開後に動画が再生されないときの対処

デモページや資料に埋め込んだ動画が公開後に再生されなくなった方向け。動画ファイルの添付漏れ・パスのズレ・ブラウザの自動再生制限を症状ごとに切り分け、自分でできる確認と対処を把握できます。

4分で読める
「トラブルシュート」の記事をもっと見る →