web-dev-qa-db-ja.com

RequireJSで遅延読み込みを実現する方法は?

Backbone、RequireJS、Handlebarsを使用して、重要でないWebアプリケーションを構築していますが、好奇心m盛です。現時点では、各モデルは次のようになっています。

_define(['Backbone', 'js/thing/a', 'js/thing/b', 'js/lib/bob'], function(a, b, bob) {
  return Backbone.Router.extend({
    // stuff here
  });
});
_

ここで、thing/a、thing/bの両方に、たとえばHandlebarsテンプレートなどの独自の依存関係があります。今起こっているのは、main.jsで、すべての「トップレベル」ルーターがロードされ、初期化されることです。各最上位ルーターには、それぞれ独自の依存関係(テンプレート、ヘルパー、utilsなど)を持つ依存関係(モデル、ビューなど)のセットがあります。基本的に、大きなツリー構造。

この場合の問題は、このツリー全体が解決され、ページのロード時にロードされることです。最終的にオプティマイザーを実行し、最終的に1つの大きな単一ファイル(RequireJSを基本的にモジュール化フレームワークに縮小する)になるので、私はそれを気にしません。ただし、ビューやテンプレートなどを「オンデマンド」でロードできるかどうかは興味があります。

「簡略化されたCommonJSラッピング」が説明されています こちら なので、私はそれを試しました:

_define(function(require) {
  Backbone = require('Backbone');
  return Backbone.Router.extend({
    doStuff: function() {
      var MyView = require('js/myView');
      new MyView().render();
    }
  });
});
_

ただし、Chromeのネットワークインスペクターを見ると、RequireJSは、何らかの形で、doStuffハンドラーをトリガーするルートをトリガーしなくても、myView依存関係をロードしているようです。質問:

  • これは実際に可能ですか? RequireJSに、実際にdoStuffルートをトリガーせずにrequire()の呼び出しを探すブラックマジックがありますか?
  • これは、RequireJSモジュールとリソースの「オンデマンド」で遅延読み込みを行う理論的に正しい方法ですか?
  • この表記を使用した場合、r.jsオプティマイザーは引き続き宣伝どおりに機能しますか?
60
fwielstra

これは実際に可能ですか? RequireJSに、doStuffルートを実際にトリガーせずにrequire()の呼び出しを探すブラックマジックがありますか?

「sugar」構文を使用する場合 Function.prototype.toStringおよび正規表現 は、requireへの参照を抽出し、関数を実行する前に依存関係としてリストします。基本的に、最初の引数としてdepsの配列を持つ通常のスタイルのdefineになります。

このため、require呼び出しがどこにあるかは気にしません。そのため、条件ステートメントが無視されます(これらのrequire呼び出しが変数ではなく文字列リテラルを使用する必要がある理由も説明します)。

これは 'オンデマンド'、RequireJSモジュールとリソースの遅延ロードを行う理論的に正しい方法ですか?

シュガーシンタックスを使用すると、これまで見てきたように条件付きロードが許可されません。私が頭の外から考えることができる唯一の方法は、require呼び出しをdepsの配列とコールバックとともに使用することです:

define(function(require) {
    var module1 = require('module1');

    // This will only load if the condition is true
    if (true) {
        require(['module2'], function(module2) {

        });
    }

    return {};
});

欠点は、別のネストされた関数だけですが、パフォーマンスが必要な場合、これは有効なルートです。

この表記を使用すると、r.jsオプティマイザーは広告どおりに機能しますか?

「シュガー」構文を使用している場合、はい、オプティマイザーは正常に機能します。例:

modules/test.js

define(function(require) {
    var $ = require('jquery');
    var _ = require('underscore');

    return {
        bla: true
    }
});

R.jsでコンパイルすると、次のようになります。

define('modules/test', ['require', 'jquery', 'underscore'], function(require) {
    var $ = require('jquery');
    var _ = require('underscore');

    return {
        bla: true
    }
});

結論として、条件付きでロードできますが、前述のように、r.jsを使用してプロジェクトを最適化する場合は、砂糖の構文を使用するだけで大​​きなオーバーヘッドは発生しません。

50
Simon Smith

require-lazy をチェックアウトすることもできます。

ランタイムコンポーネントとビルド時コンポーネントがあります。ランタイムコンポーネントを使用すると、次のようにモジュールを遅延的に要求できます(_lazy!_プラグインに注意してください)。

_define(["lazy!mymodule"], function(mymodule) {
    ...
});
_

前のコンテキストでは、mymodulepromise で、実際のモジュールはget()でロードされ、then()で利用可能になります折り返し電話:

_mymodule.get().then(function(m) {
    // here m is the real mymodule
});
_

Require-lazyはr.jsと統合して、Javascriptファイルの「バンドル」を自動的に作成します。また、バンドルのキャッシュバスティングを自動的に処理します。アイデアを得るためのいくつかの例があります。 Grunt および Bower 統合もあります。