今回は、JavaScriptのファイル読込指定と、インポート・エクスポート方法についてのメモです。
純粋なJavaScriptだけを考えての内容になっています。
普段からお世話になっているMDNを、今回は特に参考にしています。(いつもありがとうございます)
・MDN 開発者向けのウェブ技術 -> JavaScript -> JavaScript リファレンス -> 文と宣言 ->import
https://developer.mozilla.org/ja/docs/Web/HTML/How_to/Add_JavaScript_to_your_web_page
・MDN 開発者向けのウェブ技術 -> HTML -> リファレンス -> 要素 -> <script>
https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/script
目次
jsファイル 読み込み指定
まず、HTMLで読み込む方法です。scriptタグの表記についてです。
scriptタグは、幾つか属性が存在します。(以下を参照ください)
https://developer.mozilla.org/ja/docs/Web/HTML/Reference/Elements/script
・デフォルト(src属性以外指定なし)
<script src="path/to/my/script.js"></script>
処理の流れイメージ
- HTML解析一時停止して、JavaScriptをダウンロードする
- ダウンロード完了後、即座にスクリプト実行
- スクリプト終了後、HTML解析再開
読み込みパス以外を一切を指定しないパターンです。
意図的に同期が必要な場合、HTMLの描画前にどうしても処理したい場合には、こちらの指定になると思いますが、
特殊なライブラリなどでない限り、あまり行わない指定だと思います。
<script src="a.js"></script>
<script src="b.js"></script> <!-- a.js のダウンロード・実行等が完全に処理されてから実施。 -->
<script src="c.js"></script> <!-- b.js のダウンロード・実行等が完全に処理されてから実施。 -->
jsファイルサイズが小さければそこまで影響出ないかもしれませんが、
それでもパーサーブロッキング(スクリプトの解析を優先して、HTML解析を一時停止)が発生することになりますので、
念の為注意が必要です。
・async
<script async src="path/to/my/script.js"></script>
処理の流れイメージ
- HTML解析を行いながら、非同期でJavaScriptをダウンロードする
- ダウンロード完了後、即座にスクリプト実行(HTML解析一時停止)
- スクリプト実行終了後、HTML解析再開
非同期のためHTML解析を阻害しません。早く読み込み終わったものから実行を行うため、処理順は不確定となります。
そのため、依存関係が存在し、実行順が定められている場合指定できません。
疎結合な処理や機能を読み込む場合に利用します。
個人的にはあまりasyncも利用機会がなく、GoogleAnalyticesなど本当に独立性が高いものに指定しています。
<script src="jquery.js"></script>
<script src="use-jquery-utils.js"></script> <!-- jQuery使用箇所が、jQuery読込前に実行されエラーになる可能性あり。 -->
<script src="use-jquery-app.js"></script> <!-- jQuery使用箇所が、jQuery読込前に実行されエラーになる可能性あり。 -->
・defer
<script defer src="path/to/my/script.js"></script>
処理の流れイメージ
- HTML解析を行いながら、非同期でJavaScriptをダウンロードする
- ダウンロード完了後、即座にスクリプト実行せずHTML解析が完了するまで実行待機
- HTML解析終了後、スクリプト実行
遅延指定です。DOMが完全に解析された後、DOMContentLoadedイベントが発火する直前に実行します。
実行順を保証したい時やDOMの操作を行う処理の場合こちらを指定します。
<script defer src="a.js"></script> <!-- DOMが完全に処理されてから実施。 -->
<script defer src="b.js"></script> <!-- a.js のダウンロード・実行等が完全に処理されてから実施。 -->
<script defer src="c.js"></script> <!-- b.js のダウンロード・実行等が完全に処理されてから実施。 -->
・type
スクリプトタグの内容の種類を指定します。用途に応じてこちら(<script type>)を指定します。
jsonの内容を埋め込みたい場合などにも、以下のような指定をします。
<script type="application/json" id="config">
{
"apiUrl": "/api"
}
</script>
未指定
こちらは、type=”text/javascript”と同義となります。
type=”module”
<script type="module" src="a.js"></script>
個人的には最も利用します。
import/exportが使える(依存関係を自動解決)deferと処理の流れが同じ(HTML解析と並行してJSダウンロードされ、HTML解析終了後に実行される)- モジュールごとにスコープが分離される
こちらを指定してjsを読み込まないと、別のjsに定義されたfunctionの利用などができません。
<html>
<head>
<script type="module" src="js/b1.js"></script>
<!-- 以下のようにtype="module"を付与しないとbi.js内で別jsの処理を利用できない -->
<!-- <script type="module" src="js/b1.js"></script> -->
</head>
</html>
a1.js
function sample1() {
console.log("This is sample1 function");
}
export { sample1 };
b1.js
import a1 from './a1.js'; // Uncaught SyntaxError: Cannot use import statement outside a module (at b1.js:1:1)
a1.sample1();
詳しい背景も以下で解説されています。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Modules
まとめ
- 絶対にHTML描画前に実行したい →
deferもasyncも付けない通常の<script> - 順序不要でとにかく並列実行したい →
async付与 - HTML描画をブロックしたくないが順序保証が欲しい →
defer付与 - HTML描画をブロックしたくないが順序保証が欲しい。jsファイルの依存関係自動解決やスコープ分離したい→
type="module"付与
インポート・エクスポート構文
CommonJS と ES modulesについて
JavaScriptの基礎知識として、JavaScriptの規格であるCommonJSとES modulesについて触れておきます。
過去に、サーバーサイドなどWebブラウザ外の各種仕様としてCommonJS(Node.js製)が作成されました。
その後、Webブラウザも含めたJavaScriptの標準規格として、ES Modulesが作成されましたので、
元々CommonJS基準で実装されていたものもES Modulesに移行しているようです。
以下に、ES modulesについての詳細が記載されています。
インポートとエクスポートについてもこちらの規約より確認することができます。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Modules
エクスポート方法
エクスポートしたい変数やfunctionの前に、export キーワードを付与します。
個々に付与したり、まとめて指定したりできます。
a.js
// 個々にexport指定を行う
export const aaa = "text";
export function bbb(num) {
console.log("This is function bbb in a1.js value=" + num);
};
// まとめてexport指定を行う
const ccc = 99;
function ddd(num) {
console.log("This is function ddd in a1.js value=" + num);
};
export { ccc, ddd }
インポート方法
b.js
// 名前付きimport
import { aaa, bbb } from "./a1.js"
// エイリアス指定しつつインポート
import { ccc as numberConst, ddd as loggerFunction } from "./a1.js"
// 全てのエクスポートを含んだインポート
import * as a_all from "./a1.js"
console.log(aaa);
bbb(5);
console.log(numberConst)
loggerFunction(10);
console.log(a_all.aaa);
a_all.bbb(20);
console.log(a_all.ccc);
a_all.ddd(30);
今回の内容は以上となります。
基本的なjsの読み込み方法とインポート・エクスポート方法にすぎませんが、
複数のプログラミング言語を同時に触っている時に、どの記述方法が最適かなど忘れてしまいます。
