web-dev-qa-db-ja.com

exports / module.exportsの用途は何ですか?

今日、私はAngularJSプロジェクトにBrowserifyを採用していますが、非常に不明確なことがあります。すべての例とブログ投稿で、次のようなものを見ました。

/app.js:

require('./messages');
angular.module('sling', ['sling.messages']);

/messages/index.js:

exports = angular.module('sling.messages', [])
    .controller('MessagesListCtrl', require('./MessagesListCtrl'));

/messages/MessagesListCtrl.js:

module.exports = function() {
    // ...
});

確かに、これは動作しますが、なぜこれを行うのですか?私はこれをこのように実装しましたが、それは絶対にうまく機能し、AngularJSプロジェクトではより普通に感じます:

/app.js:

require('./messages');
angular.module('sling', ['sling.messages']);

/messages/index.js:

angular.module('sling.messages', []);
require('./MessagesListCtrl');

/messages/MessagesListCtrl.js:

angular.module('sling.messages').controller('MessagesListCtrl', function() {
    // ...
});

つまり、exports/module.exportsを完全にスキップし、requireを使用して基本的にコントローラー、サービス、フィルターなどのファイルを含めるだけです。

これは正しいことですか?私はそれがすべてうまくいくことを意味しますが、私は後でトラブルになりそうですか?

14
Kevin Renskers

Browserifyを使用する主な(そして正直な唯一の)理由は、ブラウザにCommonJSモジュール(つまりNodeJSモジュール)を含める場合です。 CommonJSモジュールは、暗黙的な「モジュール」スコープを持つことにより、グローバルスコープの外に留まります。すべてのモジュールが持っている「エクスポート」オブジェクトを拡張することにより、モジュールスコープ(通常はモジュールのエントリポイントまたは主要機能)から何を公開するかを選択します。

したがって、「実際の」CommonJSモジュールは次のようになります。

ファイルA:

// a.js

function doSomething() {
  console.log("I am doing something");
}

module.exports = doSomething

ファイルB:

// b.js

doSomething();
// Exception - attempt to call a non-existent function

ファイルC:

// c.js
var doSomething = require('a');
doSomething();
// logs "I am doing something"

モジュールスコープのないブラウザでは、a.jsがdoSomething関数でグローバルスコープを拡張します。これは、グローバルとして宣言されているためです。 Browserifyは、バンドルされた各モジュールを関数ラッパーにラップし、このラッパーへの引数として含まれるモジュールに「エクスポート」オブジェクトを提供することにより、これを回避します。

AngularJSを入力します。ここで使用できるアプローチは2つありますが、require( 'angular')を使用していないことが最初であるという事実から推測します。

  1. Index.htmlで利用可能なハードコーディングされたスクリプトとしてAngularJSを含めますbefore Browserify-transpiled bundle script。
  2. AngularJSをShimし、ウィンドウではなくexportsオブジェクトにアタッチし( browserify-shim などを使用)、他のモジュールと同様にrequireを使用してインポートします。

Browserifyを使用してモジュールスコープを提供し、プロジェクトの主要な依存関係をウィンドウグローバルにするのは奇妙なため、2番目のアプローチを好む傾向があります。

ただし、AngularJSには独自の依存関係注入駆動型モジュールシステムが既にあります。 angularJSコンポーネントを宣言するとき、それらはangularオブジェクトにアタッチされているモジュールオブジェクトにアタッチしています。これは、Angularの場合、angularJSモジュールファイルのexportsオブジェクトが本質的に冗長であることを意味します。ファイルが実行される限り、angularオブジェクトはモジュールとコンポーネントで拡張されるためです。

そうしないと、Browserifyはファイルをバンドルせず、実行されず、モジュールでangularオブジェクトを拡張することもないため、ファイルを「必要」にする必要があります。ただし、angularオブジェクトがエクスポートであるため、Angularのエクスポートに何かを追加するのにneedを使用しないでください。

それでは、なぜCommonJSモジュールとエクスポートがどのように機能するかを説明するのにこの時間を費やしたのでしょうか?なぜなら、Browserifyを使用するother理由は、ブラウザアプリケーションでNPMでホストされているモジュールを使用できるようにするためです。これらのモジュールのほとんどは非角形のcommonJSモジュールです。つまり、それらの機能はエクスポートによって公開されます。この場合、上記のc.jsで行っているように、必要なときにそれらのエクスポートを変数にキャプチャすることが重要です。同様に、いくつかのモジュールを作成してNPMにリリースすると、ユーザーはモジュールのエントリポイントをpackage.jsonでmainとして宣言されたファイルのexportsオブジェクトに追加することを期待します。

32
HowlingEverett