JavaScript で外部スクリプトを動的に読みこむ

JavaScript で外部スクリプトを動的に読みこむには、script 要素を作成して DOM に追加します。この方法を使うと、ページの読みこみ後に必要なスクリプトだけを遅延ロードできます。

基本的な読みこみ方法

script 要素を作成し、src 属性に URL を指定して、document.head や document.body に追加します。

const script = document.createElement('script');
script.src = 'https://example.com/library.js';
document.head.appendChild(script);

この方法でスクリプトが非同期で読みこまれ、読みこみ完了後に自動的に実行されます。

読みこみ完了を検知する

スクリプトの読みこみが完了したタイミングで処理を実行したい場合は、load イベントを使います。

const script = document.createElement('script');
script.src = 'https://example.com/library.js';

script.addEventListener('load', () => {
  console.log('スクリプトの読みこみが完了しました');
  // ここでライブラリの関数を呼び出せる
});

script.addEventListener('error', () => {
  console.error('スクリプトの読みこみに失敗しました');
});

document.head.appendChild(script);

load イベントはスクリプトの読みこみと実行が完了した時点で発火します。error イベントで読みこみ失敗を検知できます。

async と defer の違い

動的に追加した script 要素はデフォルトで async 属性が true になります。async と defer の挙動は次のとおりです。

async

スクリプトを非同期で読みこみ、読みこみ完了後すぐに実行する。実行順序は保証されない。

defer

スクリプトを非同期で読みこむが、実行は HTML の解析完了まで遅延される。複数のスクリプトは記述順に実行される。

動的に追加したスクリプトで defer を使いたい場合は、明示的に指定します。

const script = document.createElement('script');
script.src = 'https://example.com/library.js';
script.async = false;  // async を無効化
script.defer = true;   // defer を有効化
document.head.appendChild(script);

ただし、動的に追加したスクリプトで defer を指定しても、すでに HTML の解析が完了している場合は効果がありません。

複数のスクリプトを順番に読みこむ

複数のスクリプトを順番に読みこみたい場合は、Promise を使って処理を直列化します。

function loadScript(src) {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = src;
    script.addEventListener('load', () => resolve());
    script.addEventListener('error', () => reject(new Error(`Failed to load ${src}`)));
    document.head.appendChild(script);
  });
}

async function loadScripts() {
  try {
    await loadScript('https://example.com/library1.js');
    await loadScript('https://example.com/library2.js');
    console.log('すべてのスクリプトが読みこまれました');
  } catch (error) {
    console.error(error);
  }
}

loadScripts();

この方法では library1.js の読みこみと実行が完了してから library2.js の読みこみが始まります。

インラインスクリプトを実行する

外部ファイルではなく、文字列として渡されたコードを実行したい場合は、textContent を使います。

const script = document.createElement('script');
script.textContent = 'console.log("Hello from inline script");';
document.head.appendChild(script);

この方法はセキュリティリスクがあるため、信頼できるコードのみを実行してください。外部から取得した文字列をそのまま実行すると XSS 攻撃のリスクがあります。