タイトル: script要素
SEOタイトル: HTML script要素 完全ガイド(src / type / async / defer / module / 読み込みタイミング / セキュリティ)
| この記事の要点 |
|
script 要素とは
は HTML にJavaScript を埋め込むための要素です。外部の JS ファイルを読み込むこともできれば、要素内に直接コードを書くこともできます。type 属性を module にすると ES Modules として動作します。
基本構文
外部ファイル読み込み
インラインスクリプト
主要な属性
| 属性 | 役割 |
|---|---|
src | 外部 JS ファイルの URL |
type | スクリプトの種類。省略 = JS、module = ES Modules、application/json = JSON データブロック |
async | ダウンロードは並行、実行は完了次第すぐ。順序は保証なし |
defer | ダウンロードは並行、実行はHTML パース完了後、複数あれば記述順に実行 |
integrity | SRI(Subresource Integrity)。ファイルの SHA ハッシュ。改ざん検知に使う |
crossorigin | CORS 設定。CDN からの SRI 付き読み込みで必須 |
nonce | CSP インラインスクリプト許可用のワンタイムトークン |
referrerpolicy | Referer 送信ポリシー |
読み込みタイミングの違い
| 属性 | HTML パース | DL タイミング | 実行タイミング | 順序 |
|---|---|---|---|---|
| 属性なし | 止まる | 到達時に同期 DL | DL 完了直後に即実行 | 記述順 |
| async | 続行 | 並行 DL | DL 完了次第すぐ実行(パース中断) | 不定 |
| defer | 続行 | 並行 DL | HTML パース完了後 | 記述順 |
| type="module" | 続行 | 並行 DL | defer 相当 | 記述順 |
具体例
type="module"(ES Modules)
type="module" を指定すると ES Modules として読み込まれます。以下の特徴があります。
import/export構文が使える- 自動で strict mode
- 自動で defer 相当のタイミング
- スクリプトのスコープがモジュールスコープ(グローバルを汚さない)
- 同じ URL の重複読み込みはキャッシュされる
type="application/json"(データブロック)
実行されないデータ用のスクリプトブロックです。JSON-LD(構造化データ)や、JS から後で読み出すためのデータ埋め込みに使います。
SRI(Subresource Integrity)
CDN から JS を読むとき、ファイル改ざんを検知するためにハッシュを integrity 属性で検証できます。
CSP との関係
Content Security Policy(CSP)で script-src が制限されていると、外部 URL やインラインスクリプトはブロックされます。インラインを許可するには nonce または hash を使います。
Content-Security-Policy: script-src 'self' 'nonce-aBcD1234';
script の置き場所
- 内 + defer — 現在の推奨パターン
- 直前 — 古い対処法。defer が使える今はあまり使わない
- 内で属性なし — レンダリングをブロックするので非推奨
セキュリティ上の注意
- untrusted な文字列を innerHTML / document.write しない — XSS
- ユーザー入力を JS リテラルに直挿入しない
- 外部 CDN は SRI + CSP でガード
- 分析タグなど一括埋め込み系はタグマネージャ経由で管理
script の挿入順序とパフォーマンス
ページの表示速度はJavaScript の読み込み戦略で大きく変わります。同期スクリプトは HTML パースを止めてしまうため、First Contentful Paint(FCP)に直撃します。
- クリティカルでない JS は defer — メイン UI の操作を担う JS のデフォルト
- 独立した広告 / 分析タグは async — 失敗してもページに影響しない
- ファーストビューを描画するための最小スクリプトのみインラインで上部に置く
- 大型ライブラリは動的 import() で必要時のみ読み込み(コード分割)
動的に script を追加する
JS から後付けで を挿入することもできます。サードパーティライブラリの遅延読み込みなどで使います。
function loadScript(src) {
return new Promise((resolve, reject) => {
const s = document.createElement("script");
s.src = src;
s.async = true;
s.onload = () => resolve(s);
s.onerror = () => reject(new Error("load failed: " + src));
document.head.appendChild(s);
});
}
// 必要になったタイミングでロード
button.addEventListener("click", async () => {
await loadScript("/js/chart.min.js");
drawChart();
});
よくあるトラブル
| 症状 | 原因と対処 |
|---|---|
| document.querySelector が null を返す | HTML パース前に実行されている。defer を付けるか DOMContentLoaded を待つ |
| import が SyntaxError | type="module" を付けていない |
| CORS error: NetworkError when attempting to fetch resource | module スクリプトは同一オリジン or CORS 許可サーバが必要 |
| Refused to execute inline script (CSP) | CSP の script-src でインラインがブロックされている。nonce / hash を使う |
関連
- JavaScript — ブラウザ用スクリプト言語
- ES Modules — モダンな JS モジュール仕様
- defer / async — 非同期読み込み属性
- SRI / CSP — スクリプトのセキュリティ
- document.write — レガシーな書き出し API(非推奨)