Requirejs +(多)angular +打字稿

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Requirejs +(多)angular +打字稿相关的知识,希望对你有一定的参考价值。

我好像撞墙了,我无法分解。我正在使用angular + typescript,并希望使用requirejs。定义了多个角度应用程序,这些应用程序依赖于正文上的data-app-name属性进行加载。

文件夹结构(简化):

|- Libs
   |- angular
   |- some-plugin
   |- angular-some-plugin // Exposes an angular.module("ngSomePlugin")
   |- require.js
|- Common
   |- Common.ts // Exposes an angular.module("common")
|- App1
   |- Controllers
      |- SomeController.ts
      |- SomeOtherController.ts
   |- Services
      |- SomeService.ts
   |- Main.ts
   |- App.ts
|- App2
   // same as above
|- AppX
   // same as above
|- Index.html
|- Main.ts

内容:

index.html的:

// All these attributes are set dynamically server-side
<body id="ng-app-wrapper" data-directory="App1" data-app-name="MyApp">
    <script src="Libs/require.js" data-main="Main"></script>
</body>

Main.ts:

console.log("Step 1: Main.js");

requirejs.config({
    paths: {
        "angular": "Libs/angular/angular",
        "common": "Common/common"
    },
    shim: {
        "angular": {
            exports: "angular"
        }
    }
});

require(["angular"], (angular: angular.IAngularStatic) => {
    angular.element(document).ready(function() {

        var $app = angular.element(document.getElementById("ng-app-wrapper"));
        var directory = $app.data("directory");
        var appName = $app.data("app-name");

        requirejs.config({
            paths: {
                "appMain": directory + "/Main"
            }
        });

        require([
            'common',
            'appMain'
        ], function () {
            console.log("Step 5: App1/Main.js loaded");
            console.log("Step 6: Bootstrapping app: " + appName);
            angular.bootstrap($app, [appName]);
        });
    });
});

App1中的主要内容:

console.log("Step 2: App1/Main.js");

requirejs.config({
    paths: {
        "app": "App1/App",
        "somePlugin": "Libs/some-plugin/some-plugin", // This is an AMD module
        "ngSomePlugin": "Libs/angular-some-plugin/angular-some-plugin"
    },
    shim: {
        "ngSomePlugin": {
            exports: "ngSomePlugin",
            deps: ["somePlugin"]
        }
    }
});

define([
    "app"
], () => {
    console.log("Step 4: App.js loaded");
});

应用1 / App.ts:

console.log("Step 3: App.js");

import SomeController = require("App1/Controllers/SomeController");
import SomeOtherController = require("App1/Controllers/SomeOtherController");
import SomeService = require("App1/Services/SomeService");

define([
    "angular",
    "ngSomePlugin"
], (angular: angular.IAngularStatic) => {

    // This isn't called, so obviously executed to late
    console.log("Defining angular module MyApp");

    angular.module("MyApp", ["common", "ngSomePlugin"])
        .controller("someCtrl", SomeController.SomeController)
        .controller("someOtherCtrl", SomeOtherController.SomeOtherController)
        .service("someService", SomeService.SomeService)
        ;
});

然而这似乎打破了,好的错误:未捕获错误:[$ injector:nomod]模块'MyApp'不可用!您要么错误拼写了模块名称,要么忘记加载它。

问题1:

我在这做错了什么?在引导我的应用程序之前,如何确保angular.module()调用已完成?

这是console.logs的输出,你可以在其中看到angular还没有定义模块angular.module(“MyApp”),所以这很明显很晚了:Console log

更新我可以在App.ts中解开角度调用,因此它不需要任何东西(除了顶部的导入)。然后,如果我将App添加到App1 / Main.ts中的垫片,并在那里放置依赖项,它似乎工作。这是解决这个问题的好方法吗?

UPDATE2如果我在App.ts中使用require而不是define,它会实例化角度模块,但仍然在它尝试引导它之后。

问题2:

有没有办法传递自定义配置,例如Libs所在的目录名称?我尝试了以下似乎不起作用的(Main.ts):

requirejs.config({
    paths: {
        "appMain": directory + "/Main"
    },
    config: {
        "appMain": {
            libsPath: "Libs/"
        },
        "app": {
            name: appName
        }
    }
});

应用1 / Main.ts:

define(["module"], (module) => {
    var libsPath = module.config().libsPath;
    requirejs.config({
        paths: {
            "somePlugin": libsPath + "somePlugin/somePlugin"
            // rest of paths
        }
    });

    define([ // or require([])
        "app"
    ], () => {});
});

App.ts:

define([
    "module"
    // others
], (module) => {
    angular.module(module.config().name, []);
});

但是这样,逻辑上,angular.bootstrap()不会等待App.ts加载。因此,角度模块尚未定义,并且无法自举。看来你不能像App1 / Main.ts那样做嵌套定义?我该如何配置?

答案

Question 1

Alexander Beletsky写了一篇关于将requireJS和Angular绑在一起的great article(以及为什么它值得)。在其中,我认为他有第一个问题的答案:从另一个模块加载角度,然后进行自举调用。这迫使requireJS在执行任何代码之前加载这些模块的依赖关系。

假设这是你的main.ts

console.log("Step 1: Main.js");

requirejs.config({
    paths: {
        "angular": "Libs/angular/angular",
        "common": "Common/common".
        "mainT1": "t1/main.js"
    },
    shim: {
        "angular": {
            exports: "angular"
        }
    }
});

在最后添加对下一个模块的调用

requirejs(["app"], function(app) {
    app.init();
});

在t1的主要部分中,您可以创建实际的应用程序并立即加载它们。

t1/main.ts

define("app-name", ['angular'], function(angular){

    var loader = {};

    loader.load = function(){

         var app = angular.module("app-name",[]);

         return app;
         }

 return loader;

}

最后,让我们说一个暂存文件,它带你去叫app.js。在这里,您需要设置排序以获取已完成角度加载顺序的对象。一旦完成,然后在init()函数中调用bootstrapping。

t1/app.js

define("app", function(require){
     var angular = require('angular');
     var appLoader = require('mainT1');

     var app = {}
     app.init = function(){
           var loader = new appLoader();
           loader.load();
           angular.bootstrap(document, ["app-name"]);
     }

}
另一答案

与问题1相关:

在App1 / App.ts中,该函数不应返回角度模块以进行注入。

例如。

define([
    "angular",
    "ngSomePlugin"
], (angular: angular.IAngularStatic) => {
    return angular.module("MyApp", ["common", "ngSomePlugin"])
        .controller("someCtrl", SomeController.SomeController)
        .controller("someOtherCtrl", SomeOtherController.SomeOtherController)
        .service("someService", SomeService.SomeService)
        ;
});

以上是关于Requirejs +(多)angular +打字稿的主要内容,如果未能解决你的问题,请参考以下文章

带有打字稿的 Angular 5 websocket 示例

Angular 2问题:打字:找不到命令

Angular - 打字稿变量范围

Angular 1.5 $onInit 未触发 - 打字稿

从数组打字稿中删除对象(Angular 2)

Angular 打字稿异步 HTTPClient 调用