jsのimportとrequireの違い

# はじめに
jsで外部ファイルを読み込む際に、
importと書いてある場合とrequireと書いてある場合があります。

この２つの違いがよくわからなかったので確認しました。

# モジュールとは
importとrequireの違いを確認する前に、
前提知識となる「モジュール」について簡単に説明します。

ある程度の規模のjsアプリを作ると、
１つの大きなjsファイルにすべてのコードを書くのではなく
機能ごとにjsファイルを分けて管理したくなります。

そして、その機能ごとに分割したjsファイルを
メインとなるjsファイルで必要に応じて読み込んで利用するイメージです。


この分割した機能ごとのjsファイルを「モジュール」と呼びます。

# モジュールの読み込み方法
モジュールを読み込むための方法、仕様は
何種類かあり、
それぞれ書き方が違い、動く環境も違います。

そのモジュール読み込みの仕様の主要なものとして、
ESM (ECMAScript Modules)と
CJS (CommonJS Modules)があります。
※ほかにもいくつかあるが、主要なのはこの２つ


今回のテーマである`import`を使うのがESM方式で、
`require`を使うのがCJS方式となります。


それでは、
具体的にそれぞれの書き方の違いや動く環境の違いを説明していきます。

# importとrequireの違い
## import（ESM）
### 概要
import（ESM）は、
ES6で決められたモジュール読み込みの仕様です。

ES6の仕様ですので、
import文は
ChromeやFirefoxなどのブラウザでそのまま動かすことができますが、
IEでは動きません。

ESのバージョンとかブラウザによって動いたり動かなかったりという話が分からない場合は
こちらの記事でご確認ください。
[ES（ECMAScript）とは？jsがブラウザによって動いたり動かなかったりするのはなぜ？](https://qiita.com/minato-naka/items/73b9d531c871d98a3f22)

### 書き方
import文の書き方です。
モジュール側と読み込み側それぞれ書き方があります。

#### モジュール側
モジュール側では、いつものように関数やクラスを定義して、
その頭に`export`を付けることで
import可能なモジュールとして定義できます。

```module.js
export const helloWorld = function() {
    console.log('Hello World!!');
}
```

#### 読み込み側
読み込み側では、
import文を使って先ほどのモジュールを読み込みます。

```main.js
import { helloWorld } from './module'

helloWorld();
// 出力：Hello World!!
```

## require（CJS）
### 概要
require文は、CommonJSの仕様で、
Nodejsの環境で動作してくれる書き方です。

Nodejs環境ということはつまり、サーバサイドでの実行ということになります。

多くの場合はブラウザ側でのjs実行になると思いますが、
ブラウザ側ではrequire文は動作しません。

### 書き方
require文のモジュール側、読み込み側それぞれの書き方です。

#### モジュール側
モジュール側では
`module.exports` と書いて、関数やクラスなどを定義します。

```module.js
module.exports = function() {
    console.log('Hello World!!');
}
```

#### 読み込み側
読み込み側では
require文を使って先ほどのモジュールを読み込みます。

```main.js
const helloWorldModule = require('./module.js');

helloWorldModule();
// 出力：Hello World!!
```

# import、require両方を、どの環境でも動くようにするには？
上記の通り、
import文は
・Chromeなどでは動くがIEなどES6に対応していないブラウザでは動かない
require文は
・Nodejs（サーバサイド）では動くがブラウザ側実行のjsでは動かない
という動作環境の制限があります。

ですが、環境関係なく
import文もrequire文も利用したいということがあると思います。

どの環境でも動作するようにするためには、
webpackなどのモジュールバンドルツールを利用する方法があります。

webpackというツールのイメージとしては、
・上記の書き方の例でいう`main.js`のような「読み込み側」のファイルを変換対象として指定する
・ツールを実行する
・ファイルに書かれている`import`や`require`などの文を解析してくれる
・必要な外部ファイル（モジュール）を取ってきて全部１つのファイルとしてまとめて出力する
ということができるものです。

webpackは、
importやrequireや今回言及していない別のモジュール構文にも対応しており
これらを読み取ってすべてモジュールを１つのファイルとしてまとめてくれます。（「バンドルする」という）

そして、最終的にその１つにまとめられたjsファイルを
htmlで読み込むことで
必要なモジュールの機能がすべて利用できるようになります。

今回webpackの具体的な使い方は説明しませんので
別の記事を参考にしてみてください。
[Webpackってどんなもの？](https://qiita.com/kamykn/items/45fb4690ace32216ca25)

# まとめ
■import
・ES6の仕様
・Chromeなどでは動くがIEなどES6に対応していないブラウザでは動かない
■require
・CommonJSの仕様
・Nodejs（サーバサイド）では動くがブラウザ側実行のjsでは動かない

どの環境でも動作させるためには
webpackなどでモジュールバンドルして１つのファイルにまとめてから利用する。

# 備考
## Laravel Mix
今回モジュールバンドルツールとしてwebpackを例に挙げましたが、
このwebpackのラッパーツール（より便利に進化させたツール）のLaravel Mixをお勧めしたいです。
webpackの設定をシンプルに、簡単に記述できるツールです。
「Laravel」という名前がついていますがLaravelが関係ないフロントエンドのアプリでも利用可能です。
[Laravel Mixとは？webpackをより便利に、簡単に。Laravel以外でも使えるよ。](https://qiita.com/minato-naka/items/bfc3bbd9a388084e6f17)


## babel
import構文をbabelに通すとrequire文に変換されます。

importのままならChromeなどのブラウザでそのまま動いていたのに、
babelを通したらrequire文に変換されてブラウザ側では実行できなってしまう。
ということがないように気を付けましょう。

babelで変換後、webpackに通してモジュールバンドルする必要があります。

babelについてわからない方はこちらを参考に。
[polyfill、babelとは？jsをどのブラウザでも動くようにしてくれる。（IE対応）](https://qiita.com/minato-naka/items/a2645aeb158662a9f0e9)


# 参考
https://www.wakuwakubank.com/posts/466-javascript-module-import-export/
https://matatsuna.hatenablog.com/entry/2017/12/03/150520
https://qiita.com/kamykn/items/45fb4690ace32216ca25