他の方が作ってくれたテンプレートをそのまま使いまわしているため、このexportとimportの意味をわからず使用していました。
ちょうど、別の講座を受けたときに、そんな意味があったんだ!と細かい違いを知ったので、まとめておきたいと思います。
そもそもESModuleとは?
ES modulesは、ES2015仕様において策定された、JavaScriptファイルから別のJavaScriptファイルを読み込む仕組みです。
これだけ聞いてもよくわかりません。。。
それでは、このESModule以前はどのような読み込み方をしていたのかというと、下記のように複数のjsファイルを読み込むのが一般的だったようです。うちの社内でも、けっこうこんな感じで読み込んでいます。
※こんなaccordionだけで単体で書くことはないと思いますが、後で説明しやすいようにそうしています。
<script src=”js/vender/jquery.min.js”></script>
<script src=”js/accordion.js”></script>
<script src=”js/slider.js”></script>
<script src=”js/main.js”></script>
上記をESModuleを導入すると、どうなるかというと、読み込むscriptが一つでよくなります。
<script src=”js/main.js”></script>
どうして、main.jsだけでよくなるのか?main.jsの中を見てみましょう。
import jquery from "./vender/jquery.min.js";
import accordion from "./accordion.js";
import slider from "./slider.js";
jquery();
accordion();
slider();
importという記述がありますね。これがEsmoduleのimportになります。そして、exportは、importさせるために必要な記述になるのですが、importさせるjsファイル側に記述します。次で説明していきたいと思います。
と、その前に、こんなこと思った人いませんか?
accordionやsliderなどは、main.jsで一つのファイルに記述してもいいのではないか?
そうですよね!わたしも思いました!
これ、記述がそこまで長くないならそれでもいい気がするのですが、一つのファイルにずらーと記述すると、どこになんの記述を書いてあるのか探すのが大変です。
実際、わたしも自分で書いていて、この記述はどこにあるんだ!と探し回ったことがあります。
そしてチームで開発するとなったら、一つのファイルで管理すると、もっと大変。
ですので、モジュールで管理をすると、どこに何を記述しているのか、探しやすいのかなと思います!
他にも利点はあるようですが、あまりよくわかりませんでした。。下記サイトを参考ください!
バンドラーを使用せずにES Modulesを使う
わたしは、webpackを使用してバンドルしているので、知らなかったのですが、バンドラーなしでこのEsmoduleを使用したい場合、type=”module”と記述する必要があります。
<script type="module" src="main.js"></script>
なんとなくふんわりで認識していたのですが、バンドラーは、現行ブラウザでもモジュールの仕組みを利用できるように、JSを変換してくれてたようです。
ですので、このtype=”module”をつけなくても読み込めていたんですね。
こういう細かいところの理解ができていなかったので、いい勉強になりました。
また、現在のブラウザではだいたい使用できそうです。バージョンによっては対応していないブラウザもありますが、2017-2018年以前のバージョンなので、使用してもいいように思います。
ImportとExportについて
前提として、ディレクトリ構成を下記の通りとします。
├──index.html
├── js/
├──main.js
├──module.js
上記の構成でいくと、index.htmlの記述は下記です。
完成ソース
全体のソースは下記です。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>テスト</title>
<script type="module" src="main.js"></script>
</head>
<body>
<h1>テスト</h1>
</body>
</html>
main.jsを読み込むときは、type=”module”を追記すること
module.js
//①exportできるよう定義した関数
export const hello = () => {
console.log("hello!");
};
//②クラスをexportとして定義
class User {
constructor(name) {
this.name = name;
}
hello() {
console.log(this.name);
}
}
export { User }
//③export defaultと定義した関数
const funcB = () => {
console.log("デフォルトだよ");
};
export default funcB;
main.js
import {hello} from "./module.js";
import {User} from "./module.js";
import functionB from "./module.js";
//①exportできるよう定義した関数を呼び出す
hello();
//②クラスをexportとして呼び出しをする
const user = new User('名前です');
user.hello();
//③export defaultと定義した関数を呼び出す
functionB();
今回、呼び出し方として3パターンあります。
①exportできるよう定義した関数を呼び出す
下記の関数を、exportと記述することで、外部のjsファイルでも呼び出せるように宣言しています。
module.jsの記述はこちら↓
export const hello = () => {
console.log("hello!");
}
これをmain.jsで呼び出したいときは、こちら↓
import {hello} from "./module.js";
hello();
②クラスをexportとして呼び出す
クラスを呼び出したいときの、module.jsは下記
class User {
constructor(name) {
this.name = name;
}
hello() {
console.log(this.name);
}
}
export { User }
main.jsでは、下記を記述して、呼び出します。
import {User} from "./module.js";
const user = new User('名前です');
user.hello();
③export defaultと定義した関数を呼び出す
こちらは少し特殊で、一つのファイルに一つだけexport defaultとして定義ができます。
module.jsの記述はこちら↓
const funcB = () => {
console.log("デフォルトだよ");
};
export default funcB;
また呼び出し方も他の2つと違い、関数名が同じでなくても読み込めます。
main.jsの記述はこちら↓
import functionB from "./module.js";
functionB();
関数名は、funcBだが、importする際は、functionBと名前が違いますが、読み込みができます。
ただ、名前が違うと保守性がよくないと思うので、基本的には同じ名前のほうがいいと思います。
importの記述を省略できます
今回、同じファイル名からの呼び出しなので、importの記述を省略もできます。
下記のように、カンマで区切って呼び出させることが可能です。
import {hello, User} from "./module.js";
import functionB from "./module.js";
さらに、こちらを一つにまとめることもできます。
import functionB, {hello, User} from "./module.js";
通常、一ファイルについて、一関数(export default)での運用が多いのかなと思うので、あまり使用する箇所はないかもしれませんが、このように記述することもできます。
そして、もう一点、バンドラーを使用すると、.jsを記述しなくても、補完をしてくれるようです。
ですので、webpackなどを使用して構築する際は、.jsを記述しなくてもよくなるので、下記のようになります。
import functionB, {hello, User} from "./module";
わたしが使用しているテンプレートは、他の方が実装しているものを使いまわしていたため、.jsの記述ないなと思いつつも、なぜなのか特に気にしたことがありませんでした。
ですので、今回webpackが補完してくれているんだと知れたので、よかったです。
まとめ
こういう細かい違いなど意識せずにバンドラーツールなどを使用していたので、概念を理解できてよかったです。
最近は、いろんなビルドツールが増えてきており、追いつくのが大変です。。
ただ、モダンなフロントエンドの開発スタイルだと思うので、基礎をしっかり押さえていきたいです。