【Javascript】requireとimportの違いをまとめてみた
はじめに
こんにちは、SHIFT のアジャイルサービス部に所属している Matsuura です。
現在はサービス改革部のテックブースト(以下,TB)プロジェクトに参画し開発の基礎について学んでいます。Node.js を使い始めたばかりの初心者として、モジュールの管理が少し複雑に感じています。そこで、CommonJS と ECMAScript のモジュールシステムの違いや、それぞれの使い方をまとめてみました。
Node.js のモジュールとは
モジュールとは再利用可能なコードの単位であり、特定の機能をカプセル化したものです。モジュールの利用により、コードの可読性や再利用性を高め、メンテナンスを容易にすることができます。
Node.js には主に 3 種類のモジュールがあります。
コアモジュール
Node.js に組み込まれているモジュールで、インストール不要で使用可能です。
例)fs(ファイルシステム操作)、http(HTTP サーバー)、path(ファイルパス操作)
一覧は以下のコマンドから確認できます。
node -e "console.log(module.paths);"
サードパーティモジュール
npm(Node Package Manager)や yarn を使ってインストールする外部のモジュールです。
例)express(Web フレームワーク)、commander(cli ツール作成ライブラリ)、axios(HTTP 通信ライブラリ)
ユーザ定義モジュール
開発者が自分で作成するモジュールです。
このモジュールを管理するための仕組みが「モジュールシステム」です。
Node.jsには、CommonJSモジュールとECMAScriptsという2つのモジュールシステムがあります。
Commonjs とは
CommonJS は、サーバーサイド JavaScript の標準化を目指して 2009 年に始まったプロジェクトです。モジュールシステムの標準を提供することを目的としています。
デフォルトでは以下のファイルを commonjs モジュールとして扱います。
拡張子が.cjs のファイル
拡張子が.js のファイルで、そのファイルが存在するディレクトリから上位のディレクトリに向かって最初に見つかる package.json ファイルの type が commonjs という値で含まれている場合
ECMAScripts とは
ECMAScript(エクマスクリプト)は、Ecma International という団体において標準化された JavaScript の国際規格です。1997 年に誕生し定期的に新しいバージョンがリリースされており、2015 年には第 6 版(ES6 または ECMAScript 2015)が登場しました。ES6 は、JavaScript に多くの新機能と改良をもたらし、特にモジュールシステム、クラス構文、アロー関数、テンプレートリテラル、プロミスなどが追加されました。また以下のような特徴を持ちます。
拡張子が「.js」
package.json の type が module
ES6 は環境によっては実行できないため、Babel や Webpack を使ってトランスパイルする必要がある。
以降は ES6 以降についてみていきます。
Commonjs と ES6 の比較
【Commonjs】export / require の使い方
Commonjs ではモジュールのエクスポート方法が、exports と module.exports の 2 種類あります。ここではそれぞれの特徴と、それぞれの require 文の書き方を見ていきます。
exports / require
exports
exports は module.exports のショートカットです。
初期状態では exports は module.exports を指しています。 主に複数のプロパティや関数をエクスポートする場合はこちらを使用します。
// moduleA.js
const function1 = () => {
console.log("This is function1");
};
const function2 = () => {
console.log("This is function2");
};
exports.function1 = function1;
exports.function2 = function2;
exports.<プロパティ名>と記述し、プロパティを追加する形でエクスポートします。 それは module.exports にも反映されます。
また以下のように関数の定義と同時にプロパティに代入することもできます。
// moduleA.js
exports.function1 = () => {
console.log("This is function1");
};
exports.function2 = () => {
console.log("This is function2");
};
require
// main.js
const { function1 } = require("moduleA");
const { function1, function2 } = require("moduleA");
const { function2: alias } = require("moduleA");
モジュール名を{ }内に記載し、 複数のモジュールをまとめて読み込むこともできます。また、「関数名: エイリアス名」でエイリアスを設定できます。
module.exports / require
module.exports
module.exports はモジュールがエクスポートするオブジェクトそのものです。モジュール全体をエクスポートする場合に使用されます。
主に 1 つのオブジェクトや関数、クラスをエクスポートする場合はこちらを使うことが一般的です。
// moduleB.js
const function3 = () => {
console.log("This is function3");
};
module.exports = function3;
プロパティ名を設定せずmodule.exports に関数を直接代入しています。
これにより、モジュール全体が関数としてエクスポートされます。
初期状態では exports は module.exports を指していました。しかしこのようにmodule.exports に新しい値を代入すると、exports は module.exports を指さなくなります。
// moduleB.js
module.exports.function3 = () => {
console.log("This is function3");
};
module.exports オブジェクトに プロパティを追加し、そのプロパティに値や関数を割り当てることもできます。
ただし module.exports が初期状態で空のオブジェクトである必要があります。
require
// main.js
const function3 = require("./moduleB");
exportsとは異なり{ }は記載しません。
【ES6】 export / import の使い方
名前付きの export / import
export
Commonjs での module.exports に対応します。モジュールごとに複数のエクスポートを持つことができます。
// moduleC.js
const myNamedFunction1 = () => {
console.log("This is myNamedFunction1");
};
const myNamedFunction2 = () => {
console.log("This is myNamedFunction2");
};
export { myNamedFunction1, myNamedFunction2 };
以下のように書くこともできます。
// moduleC.js
export const myNamedFunction1 = () => {
console.log("This is myNamedFunction1");
};
export const myNamedFunction2 = () => {
console.log("This is myNamedFunction2");
};
import
モジュールが複数のエクスポートを持っている場合、その中から必要なものを指定してインポートします。
// main.js
import { myNamedFunction } from "moduleC";
import { myNamedFunction1, myNamedFunction2 } from "moduleC";
import { myNamedFunction2 as alias } from "moduleC";
モジュール名を{ }内に記載します。
複数のモジュールをまとめてインポートできます。
エクスポート時と同じ変数名や関数名でインポートが必要ですが、as を用いることでエイリアスを設定することができます。
デフォルトの export / import
export default
Commonjs での exports に対応します。 1 つのモジュールにデフォルトエクスポートは 1 つです。 export default は、JavaScript のモジュールシステムである ES6(ECMAScript 2015)で導入された機能の一つです?
// moduleC.js
const myDefaultFunction = () => {
console.log("default function");
};
export default myDefaultFunction;
以下のように書くこともできます。
// moduleC.js
export default myDefaultFunction = () => {
console.log("default function");
};
import
モジュールが 1 つのデフォルトエクスポートを持っている場合に使用されます。デフォルトエクスポートは、モジュールからインポートされる主要なエクスポートです。
// main.js
import defaultFunc from "moduleC";
インポート時に任意の名前を使用できます。
名前空間の import
モジュールのすべてのエクスポートを 1 つのオブジェクトとしてインポートする方法を。ここではモジュール内のすべてのエクスポートに名前空間を通じてアクセスできます。
// main.js
import * moduleName from "moduleC";
// 使用例
console.log(moduleName.defaultExport);
console.log(moduleName.namedExport1);
console.log(moduleName.namedExport2);
おわりに
この記事では commonjs と ECMAScript におけるモジュールの読み込み・エクスポート方法の違いについて紹介しました。 この記事を通じて、私と同じように初心者の方々がモジュールシステムの基本を理解し、スムーズに開発を進める手助けとなれば幸いです。
参考リンク
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/
PHOTO:UnsplashのKatie Harp