[Monorepo] NodeJSのモジュールの読み込み

2024-01-23 hit count image

JavaScriptで開発するプロジェクトでモノレポ(Monorepo)を使用するための知識として、NodeJSがモジュールを読み込む方法について説明します。

概要

今回のブログポストではモノレポを理解するための基本知識として、NodeJSがモジュールを読み込む方法について説明します。

ブログシリーズ

このブログはシリーズで制作されています。次のリンクを通じて他のブログポストも確認してください。

モジュール

JavaScript でモジュールはコードを構成し、再利用可能な単位に分離するために使用される機能です。モジュールを使用するとコードをより簡単にメンテナンスすることができるし、拡張することができます。ECMAScript 2015(ES6)から JavaScript に元々なかったモジュールシステムが導入されました。

モジュールはファイルレベルでコードをカプセル化し、必要な機能を他のファイルから取り込んで使用することができます。モジュールを使用するとグローバルスコープのコンフリクトを防ぐことができ、コードの依存関係を明確に管理することができます。

JavaScript でモジュールを使用するためには、次のキーワードを使用します。

  • import: 他のモジュールからエクスポートされた機能を現在のモジュールに取り込みます。
  • export: 現在のモジュールから外部にエクスポートする関数、変数、クラスなどを指定します。

JavaScript で次のようにモジュールを作成することができます。

// math.js
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

このように作成したモジュールは次のように使用することができます。

// main.js
import { add, subtract } from './math';

console.log(add(5, 3)); // 8
console.log(subtract(7, 2)); // 5

モジュールの読み込み

JavaScript でモジュールを読み込む方法は大きく分けて次の 2 つがあります。

  • File pathを使用する方法
  • Package nameを使用する方法

File path

File pathを使用してモジュールを読み込む場合、相対パス(Relative path)と絶対パス(Absolute path)の両方を使用することができます。

// Relative path
import { add, subtract } from '../some/file/path/math';

// Absolute path
import { add, subtract } from '/src/math';

Package name

node_modulesフォルダーにあるモジュールはPackage nameを使用して読み込むことができます。

// react module exists in node_modules
import React from 'react';

モジュールの読み込み優先順位

NodeJSはモジュールを読み込む際に、まずは同じフォルダーにモジュールが存在するか、同じフォルダーのnode_modulesにモジュールが存在するかを確認します。もし同じフォルダーにモジュールが存在しない場合、親フォルダーのnode_modulesフォルダーを確認し、親フォルダーのnode_modulesにも存在しない場合、親フォルダーの親フォルダーのnode_modulesからモジュールを探します。

例題

NodeJSがモジュールを読み込む方法を確認するために、次のようなフォルダー構造を作成してみます。

.
└── src/
    ├── module-a/
    │   ├── index.js
    │   └── package.json
    └── module-b/
        ├── index.js
        └── package.json

module-apackage.jsonは次のようです。

// src/module-a/package.json
{
  "name": "module-a",
  "version": "1.0.0",
  "main": "index.js"
}

module-bpackage.jsonは次のようです。

// src/module-b/package.json
{
  "name": "module-b",
  "version": "1.0.0",
  "main": "index.js"
}

そしてmodule-bindex.jsは次のようです。

// src/module-b/index.js
console.log('module-b');

最後にmodule-aindex.jsは次のようです。

// src/module-a/index.js
console.log('module-a');

require('module-b');

このようにファイルを構成した後、次のコマンドを実行してモジュールを読み込むことができるか確認します。

node src/module-a/index.js

そしたら次のようなエラーが発生することが確認できます。

module-a
node:internal/modules/cjs/loader:1073
  throw err;
  ^

Error: Cannot find module 'module-b'
Require stack:
- /Users/deku/temp/temp/src/module-a/index.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1070:15)
    at Module._load (node:internal/modules/cjs/loader:923:27)
    at Module.require (node:internal/modules/cjs/loader:1137:19)
    at require (node:internal/modules/helpers:121:18)
    at Object.<anonymous> (/Users/deku/temp/temp/src/module-a/index.js:3:1)
    at Module._compile (node:internal/modules/cjs/loader:1255:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1309:10)
    at Module.load (node:internal/modules/cjs/loader:1113:32)
    at Module._load (node:internal/modules/cjs/loader:960:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/Users/deku/temp/temp/src/module-a/index.js' ]
}

次はsrcフォルダ名をnode_modulesで変更して次のコマンドを実行してみます。

node node_modules/module-a/index.js

そしたら次のように問題なく実行されることが確認できます。

module-a
module-b

フォルダー名がsrcの場合、module-aからrequire('module-b');を通じてmodule-bを読み込むと、ファイルパスではないため、同じフォルダーのnode_modulesからmodule-bを探すことになります。node_modulesが現在のフォルダーに存在しないため、親フォルダーのnode_modulesを確認します。親フォルダーにもnode_modulesが存在しないため、MODULE_NOT_FOUNDエラーが発生することが確認できます。

フォルダー名をnode_modulesに変更した後、同じコードを実行すると、module-aフォルダーにnode_modulesが存在しないため、親フォルダーからnode_modulesを探すことになります。親フォルダーにはフォルダー名を変更したnode_modulesが存在し、そのフォルダーにmodule-bが存在するため、問題なく実行されることが確認できます。

完了

これでNodeJSがモジュールを読み込む方法について説明しました。NodeJSがモジュールを読み込む方法はモノレポでプロジェクトを構成するのに役立つ知識なので、今回のブログポストで紹介しました。皆さんもこの機会にNodeJSがモジュールを読み込む方法についてもう一度理解してみてください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts