Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

なぜrequire('lodash/zipWith')で関数ひとつだけ読み込めるのか

lodashというユーティリティライブラリがあります。lodashは便利な関数をたくさん提供しています。たとえば配列をシャッフルするshuffle()や、配列の差をとるdifference()などが挙げられます。

lodashは300個以上の関数を提供しています。しかし、実際に使うのはそのうちせいぜい10個です。コードサイズが大きくなってしまうのはJavaScript的に大罪です。そこで、必要な関数だけピックアップする方法が提供されています。それがタイトルにもあるrequire('lodash/zipWith')といった書き方です。

今回はどうしてそれで300を超える関数が読み込めるようになっているのか解説します。

lodashモジュールの様々な読み込み方

lodashは以下のように複数の読み出し方に対応しています。

const {zipWith} = require('lodash'); // lodashのすべてが読み込まれてしまっている
const {zipWith} = require('lodash/array'); // lodashのうち配列操作系だけ読み込む
const zipWith = require('lodash/zipWith'); // 関数をピンポイントで読み込む

ES Modulesを使う書き方もできます(node_modules/配下を参照するので、Node.jsでのみ動作します)。

import * as _ from 'lodash';
import * as lodashArray from 'lodash/array';
import zipWith from 'lodash/zipWith';

では、どうしてこのような読み込み方ができるのでしょうか?実際にインストールしたパッケージを見てみます。

f:id:panda_noir:20190419212255p:plain

なんと631個もJavaScriptファイルが置かれています!そして、それぞれ関数に対応したファイル、arrayに対応したファイルがあります。

つまり、require('lodash/array')ではlodashパッケージ内にあるarray.jsが読み込まれます。同様にrequire('lodash/zipWith')ではzipWith.jsが読み込まれます。

仕様ではどうなっているのか?

Node.jsのドキュメントのModulesページを見てみます。

どうやら、require('example-module/path/to/file')./node_moduels/example-module/path/to/fileと同様のようです(現在のディレクトリのnode_modulesになければ見つかるまで親ディレクトリを辿っていくようです)。

つまり、上のrequire('lodash/array')はドキュメントで保証されている動作らしいです。

これって名前空間なのでは?

このrequire('lodash/array')という書き方、lodashという名前空間のarrayを読み込むと見えませんか?実際の動作も名前空間にみえます。非常に面白いですね。

ただ、実際にコレをやっているパッケージをあまり見ない気がします。そもそもやる必要があるパッケージが少ないというのがありますが。