JavaScript における import/export/exports の違い、および ES Modules の簡単な歴史
JSで外部モジュールを import・export する場合、 import
/export
/require
/exports
など色々な書き方があり、どの場合にどれが使われるのか自分の理解が浅いと感じたので、勉強しなおした。
本記事は備忘としてまとめたもの。後半は ES Modules の話に脱線している。
ES Modules か CommonJS か
大前提として、モジュールのインポート・エクスポートの書き方は ES Modules
と CommonJS
、プロジェクトがどちらの方式を採用しているかによって異なる。
- ES Modules の場合は
import
/export
- CommonJS の場合は
require
/exports
/module.exports
ES Modules
ECMA Script Modules
の略。
クライアントサイドJS、つまり一般的なWebブラウザがサポートしているのはこちらである。
しかし 最近は サーバーサイドJS である Node.js も ES Modules に対応してきており、私個人の体感としても サーバーサイドでも ES Modules を採用することが一般的になっているように思う。
CommonJS
サーバーサイドJS、つまり Node.js が元々サポートしているのはこちらである。
Webブラウザ環境 以外(主にはサーバーサイド)におけるJavaScriptの各種仕様を定めることを目標としたプロジェクト。
(自分用の属人的な)結論
携わるプロダクトの ほぼ全てが(たまたま)ES Modules である自分用の結論としては
import
とexport
を基本的に使用するexports
は便利なのだが これは CommonJS のものなので使用不可
export の宣言方法 および import による受取方法
default export
- 1つのモジュール内に1回だけ使える
- CommonJS の
module.exports
に相当するものだが、module.exports
のように複数のモジュールを一気に出力はできない
// deafult export in /Functions/Common.ts
// deafult は 1モジュール内に1回しか宣言できないが、後述の 名前つきexport は default とは別に何個も宣言可能
// 以下のどの書き方でもいい
export default () => {}
export default function () {}
export default function getParam () {}
export default "1"
// 上記の default export で定義したものは、以下で受け取る test の部分は何でもいい
// getParam で宣言していても、好きな名前で受け取ることができる(test の部分は getParm でなくても何でもいいということ)
import test from '/@Functions/Common'
named export (名前つきexport)
- 1つのモジュール内で何回でも使える
- default export を定義していても、named export を(0以上の任意の数)定義することが可能
// 名前つきexport in /Functions/CommonNamed.ts
export const getParam = () => {}
export function setParam () {}
export const param = "2"
// 上記の 名前つきexport で定義したものは、以下で受け取る
// 宣言した変数名で受け取らないといけない
import { getParam } from '@/Functions/Common';
import { setParam, param } from '@/Functions/Common';
// default export と 名前つきexport 両方を受け取る場合の書き方
import test, { getParam, setParam, param } from '@/Functions/Common';
// 以下のように分けても可
import test from '@/Functions/Common';
import { getParam, setParam, param } from '@/Functions/Common';
ES Modules の歴史と仕様(バージョン)
ES Modules 自体の理解も浅かったので、この機会に(軽くだが)勉強した。
歴史は Wikipedia に概略がまとめられている。
ES Modules では、バージョンごとに利用可能な関数や書き方が異なり、新しいバージョンほど より便利な関数や書き方が利用できるようになっている。
ES5以前
- ES1〜ES3 は 1997年〜1999年の間、毎年バージョンが1上がっていた
- ES4は公開されることはなかった
- ES5 は 2009年に登場した
ES6以降
ES6以降は、仕様名に発行年が付与されることになり、これ以降は毎年新しいバージョンが登場している。 ES6 = ES2015 であり、現在は ES2023 までが登場している。
個人的なバージョンごとの見どころをまとめると
- ES2015: ES6と同義
- ES2017: 今では当たり前の
async
/await
は(ECMAScriptでは)ここが初出 - ES2020: null合体演算子、オプショナルチェーンなどが使えるようになり null との付き合い方に柔軟性が追加された
- ES2021: 何かと便利な
replaceAll
は(ECMAScriptでは)ここが初出 - ES2022: Top Level await、 private method, variable, static variable などが利用可能に
- ES2023: 現在の最新だが 正直そんなに目ぼしい機能は・・・という感じ
各ESバージョンの変更点・新機能などを見ていて思ったのは
- 開発効率を下げないために必要な最低ラインは ES2020, ES2021(ないと実装がごちゃつく)
- より便利に開発するためには ES2022(あるとより安全に書ける)
ということで、 自分でバージョンを自由に選べるならば ES2021 が最低ラインかな、と。
どの ESバージョンを採用すべきか
前提として、Node.js のバージョンによって 利用可能な ES Modules バージョンが異なる。
具体的な対応状況は https://node.green を見ることで、知ることが可能。
個人的には ES2021 までは 開発効率維持のために採用したいため、逆算すると Node.js は(上記の https://node.green にて ES2021 の機能が全て green である) 16.10.0
以降 の採用が必要となる。