JavaScript
応用
JavaScript
ES Modules
import
JavaScriptのコードをモジュールに分割しよう
更新日:2026-08-02
処理が増えたら、データ取得、DOM生成、画面制御などの役割ごとにファイルを分けます。
前回まで一つのscript.jsに書いていた記事取得機能を、API通信、DOM生成、全体制御の三つへ分割します。分割後も動作が変わらないことが今回の目標です。
今回使用するファイル構成
javascript-practice/
├── index.html
└── js/
├── api.js
├── render.js
└── script.js
モジュールを作成して読み込む
関数をexportする
api.jsから関数を公開します。
export async function fetchArticles() {
const response = await fetch('/api/articles');
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
}
importして利用する
script.jsで読み込みます。
import { fetchArticles } from './api.js';
const articles = await fetchArticles();
console.log(articles);
相対パスには拡張子まで記述します。
HTMLからmoduleとして読み込む
<script type="module" src="js/script.js"></script>
モジュールは自動的に遅延実行され、変数はファイル外のグローバル領域へ直接追加されません。ローカルファイルを直接開くと読み込み制限が起きる場合があるため、Live ServerなどのHTTPサーバーで確認します。
モジュール分割の考え方
分割しすぎない
一度しか使わない数行の処理まで分けると、読むファイルが増えます。「何を担当するファイルか」を説明できる単位で分割します。
記事一覧を三つの役割へ分ける
api.jsで通信だけを担当する
export async function fetchArticles() {
const response = await fetch('data/articles.json');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const articles = await response.json();
if (!Array.isArray(articles)) {
throw new TypeError('記事データが配列ではありません');
}
return articles;
}
このファイルはHTML要素を知りません。データ取得に成功すれば配列を返し、失敗すれば例外を投げます。
render.jsでDOM生成を担当する
export function renderArticles(container, articles) {
container.replaceChildren();
articles.forEach((article) => {
const item = document.createElement('li');
item.textContent = article.title;
container.append(item);
});
}
export function showStatus(element, message) {
element.textContent = message;
}
操作対象を引数で受け取るため、特定のidへ強く依存しません。
script.jsで処理を組み合わせる
import { fetchArticles } from './api.js';
import { renderArticles, showStatus } from './render.js';
const loadButton = document.querySelector('#load-button');
const status = document.querySelector('#status');
const articleList = document.querySelector('#article-list');
async function loadArticles() {
loadButton.disabled = true;
showStatus(status, '読み込み中です。');
try {
const articles = await fetchArticles();
renderArticles(articleList, articles);
showStatus(status, `${articles.length}件を読み込みました。`);
} catch (error) {
console.error(error);
showStatus(status, '記事を取得できませんでした。');
} finally {
loadButton.disabled = false;
}
}
loadButton.addEventListener('click', loadArticles);
script.jsは、どの要素とどの機能を接続するかを担当します。それぞれのファイルの役割を一文で説明できれば、分割の意図が伝わりやすくなります。
exportとimportの種類を理解する
今回使ったのは名前付きexportです。一つのファイルから複数の値を公開でき、import側では同じ名前を波括弧で指定します。
export function firstFunction() {}
export function secondFunction() {}
import { firstFunction, secondFunction } from './functions.js';
一つだけを代表として公開するdefault exportもありますが、名前を自由に変えられるため、初めは対応関係が明確な名前付きexportを基本にすると読みやすくなります。
よくあるエラー
Cannot use import statement outside a module:type="module"を確認するFailed to resolve module specifier:./と拡張子.jsを確認する- CORS関連のエラー:ファイルを直接開かずHTTPサーバーを使う
- exportが見つからない:export側とimport側の名前・大文字小文字を確認する
まとめ
exportで公開し、importで利用します。次の記事では日付と時刻を扱います。