LoginSignup
1
1

More than 5 years have passed since last update.

【Node.js】Module Wrapper に遭遇して exports と module.exports の勘違いに気づいた

Last updated at Posted at 2018-10-09

【Node.js】Module Wrapper に遭遇して exports と module.exports の勘違いに気づいた

Node.js 初心者の自分は、なかなか require (特に module.exports) がイマイチ理解できない感あったので、いろいろ勉強してたら Module Wrapper に遭遇したので書き残しておきます。

参考

そもそも require の実行の仕方が全然違った

他の言語からの勝手な想像で

  • 基本的にはファイルを読み込んで展開してくれるから、普通に宣言したら どこからでも参照できそう
  • むむむ... module.exports しないといけない様子...
  • module.exports = app は動くのに exports = app は動かないぞ!

みたいな状態でした。
その勘違いを脱するヒントが Module Wrapper にありました。

どのように遭遇するか

v10.11.0 で試しています。
app.jsmodule.js を用意して実行してみるとエラーから Wrapper らしきものが見えます。

app.js
const m = require('./module.js');
module.js
err; // わざと ReferenceError を起こす

それを実行すると

$ node app.js
/Users/ight/module.js:1
(function (exports, require, module, __filename, __dirname) { err;
                                                              ^

ReferenceError: err is not defined
    at Object.<anonymous> (/Users/ight/module.js:1:63)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> (/Users/ight/Sandbox/Node/app.js:1:73)
    at Module._compile (internal/modules/cjs/loader.js:689:30)

ここで気になるのが (function (exports, require, module, __filename, __dirname) { の部分です!
これは 即時関数の実行をしている ように見えますし、悩んでいた exportsmodule.exportsヒントもありそう です。

Module Wrapper について

実は Node.js で require すると、function で wrap されて呼び出されます。
このことは Node.js Document にも書かれています。

Before a module's code is executed, Node.js will wrap it with a function wrapper that looks like the following:

(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});

Modules | Node.js v10.11.0 Documentation

exports しないと呼び出せない理由

function で wrap されていることを考えると、 export していない変数が呼び出せないのは当然 で、Node.js は何も特殊なことをしてくれているわけではなさそうなことがわかってきました。

require ももう少し詳しく見ていくと仕組みが理解できそうです。

exports? module.exports?

ここで気になるポイントが 引数に渡されているexportsmodule です。module

module.exports is used for defining what a module exports and makes available through require().

require で利用可能なものを定義するために module.exports を使えばよく、exports

A reference to the module.exports that is shorter to type.

つまり、単に module.exports の参照という話でした。
しかし引数に渡されていることからわかるように、そのまま exports に代入する書き方はできません

module.exports = app; // これは OK
exports = app;        // これは exports の参照を書き換えているだけ

ちなみに

引数に require が渡されているのも気になりましたが、いつか調べようと思います。
module.js 内で require('other_module.js') をすると、引数の require が使われてまた 少し挙動が変わる のかなーとか、ただ 単に渡しているだけ なのかなとか。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1