source

필요한 경우에만 모듈을 동적으로 주입합니다.

itover 2023. 3. 8. 21:06
반응형

필요한 경우에만 모듈을 동적으로 주입합니다.

Require.js와 Angular.js를 조합하여 사용하고 있습니다.

에 따라서는 큰 하지 않은 외부 의존관계가 합니다.FirstController에는 Angular UI Codemirror가 필요합니다.적어도 135kb가 추가됩니다.

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.codemirror모듈(또는 다른 모듈)을 사용할 수 있습니까?
외부 종속성의 코드를 수정하는 것이 아니라면, 이것이 해킹적인 방법인지는 상관없습니다.

도움이 되는 경우:Angular 1.2.0을 실행하고 있습니다.

저는 얼마 전부터 requiresj+Angular를 믹스하려고 하고 있습니다.인라인 코드나 핀들에 비해 스코프가 너무 커서 지금까지의 노력으로 Github(Angular-require-lazy)에서 작은 프로젝트를 발표했습니다.이 프로젝트에서는 다음 사항을 시연합니다.

  • AngularJS 모듈이 느리게 로드됩니다.
  • 디렉티브도 로딩이 느릴 수 있습니다.
  • "모듈" 검출과 메타데이터 메커니즘이 있습니다(다른 애완견 프로젝트: require-lazy 참조).
  • 애플리케이션이 번들로 자동으로 분할됩니다(즉, r.js를 사용한 빌드).

어떻게 하면 좋을까요?

  • 「」:$controllerProvider,$compileProvider합니다.config기능(agularjs-requirejs-lazy-controller에서 처음 접한 기술).
  • 후 " " "angular로딩이 느린 모듈을 처리할 수 있는 자체 래퍼로 대체되었습니다.
  • 인젝터가 캡처되어 약속으로 제공됩니다.
  • AMD 모듈은 Angular 모듈로 변환할 수 있습니다.

이 실장에서는 Angular 모듈(적어도 사용하고 있는ng-grid :)을 느리게 로드할 수 있으며 외부 라이브러리를 변경하지 않습니다.

코멘트/의견은 대환영입니다.


(이 점은 동적(EDIT)을 하지 않는다는 require()따라서 r.discl(및 내 요구조건 프로젝트)을 사용하여 구축할 수 있습니다.그 외에는 다양한 솔루션에서 아이디어가 다소 수렴되어 있습니다.

모두 행운을 빌어요!

주의: Nikos Paraskevopoulos의 솔루션을 사용합니다.신뢰성이 높고(사용하고 있습니다), 예도 많이 있습니다.


네, 이 답변에 대한 간단한 도움을 받아 드디어 이 문제를 해결하는 방법을 알아냈습니다.

내가 질문에서 말했듯이, 이것은 매우 진부한 방법이 되었다. 각각의 할 수 있습니다._invokeQueue앱 모듈의 컨텍스트에서 종속 모듈의 배열입니다.

이와 같습니다(모듈에서 더 주의하세요).익스텐더 기능을 사용하세요).

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() { });

의 열쇠는 모든 이 '''모듈''이라는 입니다.app모듈도 느린 로딩 모듈이어야 합니다.이는 각도가 $injector 서비스에 사용하는 공급자 및 인스턴스는 비공개이며 초기화가 완료된 후 새 모듈을 등록하는 방법을 노출하지 않기 때문입니다.

이 '을 각각 편집한 후(에 컨트롤러, , 콜을 하여 " " " " " 를 입니다. 'appModules.js' 파일에 있음), 컨트롤러, 디렉티브, 공장 호출을 각각 편집하여 사용하는 것입니다.app.lazy.{same call}★★★★★★ 。

그 후, 앱 루트가 어떻게 로딩되어 있는지 살펴봄으로써 링크된 샘플 프로젝트를 계속 진행할 수 있습니다('appRoutes.js' 파일에는 그 방법이 나와 있습니다).

이게 도움이 될지는 모르겠지만 행운을 빌어요.

이를 위한 지침이 있습니다.

https://github.com/AndyGrom/loadOnDemand

예:

<div load-on-demand="'module_name'"></div>

기존의 게으른 부하 기술의 문제점은 내가 하고 싶은 일을 스스로 해낸다는 것이다.

예를 들어 requirejs를 사용하여 다음 번호로 전화하겠습니다.

require(['tinymce', function() {
   // here I would like to just have tinymce module loaded and working
});

하지만 그런 식으로는 안 되지 왜?내가 알기로는 앵글JS는 모듈을 '미래에 로드될 것'으로 표시하기만 하면 됩니다.예를 들어, 조금 기다리면 동작합니다.사용할 수 있습니다.위의 함수에서는 loadPendingModules()와 같은 함수를 호출하고 싶습니다.

프로젝트에서는 심플한 프로바이더('lazyLoad')를 작성했습니다.이 프로바이더는 이것만 하고 나머지는 아무것도 하지 않습니다.따라서 모듈을 완전히 로드해야 할 경우 다음 작업을 수행할 수 있습니다.

myApp.controller('myController', ['$scope', 'lazyLoad', function($scope, lazyLoad) {

    // ........

    $scope.onMyButtonClicked = function() {

        require(['tinymce', function() {
            lazyLoad.loadModules();

            // and here I can work with the modules as they are completely loaded
        }]);
    };

    // ........

});

다음은 소스 파일(MPL 라이선스) 링크입니다.https://github.com/lessmarkup/less-markup/blob/master/LessMarkup/UserInterface/Scripts/Providers/lazyload.js

샘플 코드를 보내드립니다.저는 잘 되고 있어요.확인 부탁드립니다.

var myapp = angular.module('myapp', ['ngRoute']);

/* Module Creation */
var app = angular.module('app', ['ngRoute']);

app.config(['$routeProvider', '$controllerProvider', function ($routeProvider, $controllerProvider) {

app.register = {
    controller: $controllerProvider.register,
    //directive: $compileProvider.directive,
    //filter: $filterProvider.register,
    //factory: $provide.factory,
    //service: $provide.service
};


//    so I keep a reference from when I ran my module config
function registerController(moduleName, controllerName) {
    // Here I cannot get the controller function directly so I
    // need to loop through the module's _invokeQueue to get it
    var queue = angular.module(moduleName)._invokeQueue;
    for (var i = 0; i < queue.length; i++) {
        var call = queue[i];
        if (call[0] == "$controllerProvider" &&
           call[1] == "register" &&
           call[2][0] == controllerName) {
            app.register.controller(controllerName, call[2][1]);
        }
    }
}


var tt = {
    loadScript:
function (path) {
    var result = $.Deferred(),
    script = document.createElement("script");
    script.async = "async";
    script.type = "text/javascript";
    script.src = path;
    script.onload = script.onreadystatechange = function (_, isAbort) {
        if (!script.readyState || /loaded|complete/.test(script.readyState)) {
            if (isAbort)
                result.reject();
            else {
                result.resolve();
            }
        }
    };
    script.onerror = function () { result.reject(); };
    document.querySelector(".shubham").appendChild(script);
    return result.promise();
}
}

function stripScripts(s) {
    var div = document.querySelector(".shubham");
    div.innerHTML = s;
    var scripts = div.getElementsByTagName('script');
    var i = scripts.length;
    while (i--) {
        scripts[i].parentNode.removeChild(scripts[i]);
    }
    return div.innerHTML;
}


function loader(arrayName) {
    return {
        load: function ($q) {
            stripScripts(''); // This Function Remove javascript from Local
            var deferred = $q.defer(),
            map = arrayName.map(function (obj) {
                return tt.loadScript(obj.path)
                .then(function () {
                    registerController(obj.module, obj.controller);
                })
            });

            $q.all(map).then(function (r) {
                deferred.resolve();
            });
            return deferred.promise;
        }
    };
};



$routeProvider
    .when('/first', {
        templateUrl: '/Views/foo.html',
        resolve: loader([{ controller: 'FirstController', path: '/MyScripts/FirstController.js', module: 'app' },
            { controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' }])
    })

    .when('/second', {
        templateUrl: '/Views/bar.html',
        resolve: loader([{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' },
        { controller: 'A', path: '/MyScripts/anotherModuleController.js', module: 'myapp' }])
    })
    .otherwise({
        redirectTo: document.location.pathname
        });
}])

HTML 페이지:

<body ng-app="app">

<div class="container example">
    <!--ng-controller="testController"-->

    <h3>Hello</h3>

    <table>
        <tr>
            <td><a href="#/first">First Page </a></td>
            <td><a href="#/second">Second Page</a></td>
        </tr>
    </table>




        <div id="ng-view" class="wrapper_inside" ng-view>
        </div>
    <div class="shubham">
    </div>
</div>

언급URL : https://stackoverflow.com/questions/18591966/inject-module-dynamically-only-if-required

반응형