45

Require.js を Angular.js と組み合わせて使用​​しています。

一部のコントローラーは、他のコントローラーが必要としない巨大な外部依存関係を必要とします。たとえば、Angular UI CodemirrorFirstControllerが必要です。これは、少なくとも 135 kb 余分です。

require([
  "angular",
  "angular.ui.codemirror" // requires codemirror itself
], function(angular) {
  angular.module("app", [ ..., "ui.codemirror" ]).controller("FirstController", [ ... ]);
});

Angular を満足させるためだけに、ページが読み込まれるたびにディレクティブと Codemirror lib を含める必要はありません。そのため、ここで行われたことのよう
に、ルートがヒットした場合にのみコントローラーをロードしています。

ただし、次のようなものが必要な場合

define([
  "app",
  "angular.ui.codemirror"
], function(app) {
  // ui-codemirror directive MUST be available to the view of this controller as of now
  app.lazy.controller("FirstController", [
    "$scope",
    function($scope) {
      // ...
    }
  ]);
});

ui.codemirrorapp モジュールにもモジュール (または他のモジュール)を挿入するように Angular に指示するにはどうすればよいですか?
外部依存関係のコードを変更する必要がない限り、これがハックな方法であるかどうかは気にしません。

役に立つ場合: Angular 1.2.0 を実行しています。

4

6 に答える 6

33

しばらくの間、requirejs + Angular を混在させようとしています。スコープがインライン コードやフィドルには大きすぎるため、これまでの努力で Github ( angular-require-lazy ) で小さなプロジェクトを公開しました。このプロジェクトは、次の点を示しています。

  • AngularJS モジュールは遅延ロードされます。
  • ディレクティブも遅延ロードできます。
  • 「モジュール」の発見とメタデータのメカニズムがあります (私の他のペット プロジェクトを参照してください: require-lazy )
  • アプリケーションは自動的にバンドルに分割されます (つまり、r.js でのビルドは機能します)。

それはどのように行われますか:

  • プロバイダー (例: $controllerProvider$compileProvider) は関数から取得されます ( angularjs-requirejs-lazy-controllersconfigで最初に見た手法)。
  • ブートストラップの後、angular遅延ロードされたモジュールを処理できる独自のラッパーに置き換えられます。
  • インジェクターは、Promise としてキャプチャされ、提供されます。
  • AMD モジュールは Angular モジュールに変換できます。

この実装はあなたのニーズを満たします: Angular モジュール (少なくとも私が使用している ng-grid) を遅延ロードでき、間違いなくハックです:)、外部ライブラリを変更しません。

コメント/意見は大歓迎です。


(編集)このソリューションと他のソリューションの違いは、動的呼び出しを行わないためrequire()、r.js(および私のrequire-lazyプロジェクト)で構築できることです。それ以外は、アイデアはさまざまなソリューション間で多かれ少なかれ収束しています。

皆さんお元気で!

于 2013-09-11T22:25:13.840 に答える
7

注意: Nikos Paraskevopoulos によるソリューションを使用すると、より信頼性が高く (私はそれを使用しています)、より多くの例があります。


さて、私は最終的に、この答えの簡単な助けを借りてこれを達成する方法を見つけました.

質問で述べたように、これは非常にハックな方法になりました。_invokeQueueアプリモジュールのコンテキストで、依存モジュールの配列内の各関数を適用することを含みます。

これは次のようなものです (moduleExtender 関数に注意してください):

define([ "angular" ], function( angular ) {
    // Returns a angular module, searching for its name, if it's a string
    function get( name ) {
        if ( typeof name === "string" ) {
            return angular.module( name );
        }

        return name;
    };

    var moduleExtender = function( sourceModule ) {
        var modules = Array.prototype.slice.call( arguments );

        // Take sourceModule out of the array
        modules.shift();

        // Parse the source module
        sourceModule = get( sourceModule );
        if ( !sourceModule._amdDecorated ) {
            throw new Error( "Can't extend a module which hasn't been decorated." );
        }

        // Merge all modules into the source module
        modules.forEach(function( module ) {
            module = get( module );
            module._invokeQueue.reverse().forEach(function( call ) {
                // call is in format [ provider, function, args ]
                var provider = sourceModule._lazyProviders[ call[ 0 ] ];

                // Same as for example $controllerProvider.register("Ctrl", function() { ... })
                provider && provider[ call[ 1 ] ].apply( provider, call[ 2 ] );
            });
        });
    };

    var moduleDecorator = function( module ) {
        module = get( module );
        module.extend = moduleExtender.bind( null, module );

        // Add config to decorate with lazy providers
        module.config([
            "$compileProvider",
            "$controllerProvider",
            "$filterProvider",
            "$provide",
            function( $compileProvider, $controllerProvider, $filterProvider, $provide ) {
                module._lazyProviders = {
                    $compileProvider: $compileProvider,
                    $controllerProvider: $controllerProvider,
                    $filterProvider: $filterProvider,
                    $provide: $provide
                };

                module.lazy = {
                    // ...controller, directive, etc, all functions to define something in angular are here, just like the project mentioned in the question
                };
                module._amdDecorated = true;
            }
        ]);
    };

    // Tadaaa, all done!
    return {
        decorate: moduleDecorator
    };
});

これが完了したら、たとえば次のようにする必要があります。

app.extend( "ui.codemirror" ); // ui.codemirror module will now be available in my application
app.controller( "FirstController", [ ..., function() { });
于 2013-09-11T17:24:58.833 に答える