非同期JavaScript:API通信とモジュール
ファイルを分けるという考えかた
このレッスンで分かること
exportで外に出すものを選び、importで名前を指定して受け取りますtype="module"を付けると、読み込み順を人間が管理しなくてよくなります
1 枚の app.js で名前を取り合う
いまの app.js には、作品データの加工、カードを組み立てる関数、エラー表示、fetch、フォームの検証が同居しています。動いてはいますが、困りごとが 3 つ出ています。
1 つめは名前の取り合いです。update という名前を作品一覧でもフォームでも使いたくなったとき、ファイルが 1 枚なら片方を改名して逃げるしかありません。2 つめは、読む範囲が絞れないことです。並び替えの不具合を直したいだけなのに、上から下まで目で追う羽目になります。
3 つめは読み込み順です。<script> を 2 枚に分けて逃げようとすると、今度は先に読んだほうにある関数しか呼べないという別の縛りが生まれます。しかも片方が読めていなくてもエラーにならず、undefined として静かに壊れます。
ファイルを分ける目的は、行数を減らすことではありません。どこを読めば分かるかを、名前ではなくファイルの境界で示すことです。300 行のうち関係するのが 40 行だと分かっているなら、その 40 行を別のファイルに出す価値があります。
外に出すものだけを選ぶ
分けた側のファイルでは、外から使ってよいものにだけ export を付けます。
JavaScript
// works.js
export function publishedWorks(works) {
return works.filter((work) => work.published);
}
// export していないので、このファイルの外からは名前すら見えない
function debugLabel(work) {
return work.category ?? "その他";
}使う側は import で受け取ります。from に書くのは道順で、同じフォルダなら ./works.js、1 つ上なら ../works.js です。
JavaScript
// app.js
import { publishedWorks } from "./works.js";拡張子の .js は省略できません。Node.js のクセに慣れている人ほど、ここで詰まります。また import は関数の中には書けません。どのファイルを読むかはコードが動く前に決まる約束なので、ファイルのいちばん上に置きます。
type="module" を付けると何が変わるか
import を含むファイルは、属性を 1 つ足して読み込みます。
HTML
<script type="module" src="app.js"></script>たったこれだけですが、変わることは 4 つあります。
| 普通の script | type="module" | |
|---|---|---|
| import と export | 構文エラーになる | 書ける |
トップレベルの const | window に共有される | そのファイルの中だけ |
| 実行のタイミング | 読んだ場所ですぐ | HTML を読み終えてから |
| strict mode | 自分で書けば有効 | 常に有効 |
3 番目のおかげで、<head> に書いても querySelector が null を返しません。読み込み順の心配も消えます。app.js が works.js を必要としていると import の行に書いてあるので、ブラウザが先に works.js を読みます。
ただし、このコースの実行環境では import と export を動かせません。採点もプレビューも、書いたコードを普通の script として扱う作りだからです。手を動かすのは自分のパソコンでどうぞ。加工の関数を works.js に移して export を付け、app.js の先頭で import し、script に type="module" を足したら、そのフォルダで python3 -m http.server 8000 を実行して http://localhost:8000 を開きます。
index.html をダブルクリックして file:/// で開くと、モジュールの読み込みは CORS のエラーで止まります。普通の script なら開けるので、昨日まで開けたのに真っ白になった、という形で出ます。
よくある間違い
- 拡張子を省く —
import { publishedWorks } from "./works";と書いてもブラウザは探しに行きません。./works.jsと書きます type="module"を付け忘れる —Cannot use import statement outside a moduleと出ます。原因は JavaScript ではなく HTML 側にありますexportしていないものをimportする — 読み込み前に照合されるので、呼び出す行まで進む前にページごと止まります。静かにundefinedになる普通の script より、むしろ親切な壊れかたです