2015-11-03 87 views
10

我似乎碰壁了,我无法打破。我正在使用angular + typescript,并希望使它与requirejs一起工作。定义了多个角度应用程序,这些应用程序根据正文中的data-app-name属性加载。Requirejs +(多)角+打字稿

文件夹结构(简化):

|- 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]); 
     }); 
    }); 
}); 

Main.ts在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) 
     ; 
}); 

然而,这似乎打破,用好旧的错误:未捕获 错误:[$注射器:NOMOD]模块 'MyApp的' 不可!您拼错了模块名称或忘记加载模块名称。

问题1

我在做什么错在这里?如何确保angular.module()调用在我启动我的应用程序之前完成?

这是console.logs,在那里你可以看到角的输出尚未定义的模块angular.module(“MyApp的”),所以这样做是为了后期明显: Console log

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

UPDATE2 如果我使用需要,而不是在App.ts定义的,它实例化角模块,但仍试图引导之后。

问题2

是否有任何的方式来传递下来的自定义配置,例如其中的lib目录名?我想这似乎没有工作如下(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中做一个嵌套定义?我应该如何配置?

+0

我有怀疑,require.config的'多层()'调用将正常工作。 (Side-question:是吗?)但是由于'data-directory' /'data-app-name'是在服务器端生成的,我建议你也动态生成'require.config()'调用。您甚至可能希望动态地将服务器端的适当片段直接包含到Index.html中。从那里,你需要调整AMD模块中的路径。还有一个旁注:为什么不使用Typescript对AMD的原生支持,即'import Foo = require('Foo')'语法? –

+0

我在angular-app层面上执行'import'东西(在App.ts和所有其他角度组件中)。如果我使用的是打字稿,那么在各处使用导入语法会更好吗?我认为它不适用于非AMD第三方库? – devqon

+0

是的,'require.config()'的多个层似乎工作:) – devqon

回答

-1

对问题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) 
     ; 
}); 
+0

我并不真的需要这个模块本身,我只需要确定它是实例化的,这样我就可以引导我的应用程序,它只能通过名称完成:'angular.bootstrap($ app,[“MyApp”])' – devqon

+0

我也试过:) – devqon

+0

这取决于正文的执行,而不是返回内容的值。 – EricG

0

问题1

亚历山大Beletsky写了great article约搭售requireJS和角度在一起(和为什么它是值得的)。其中,我认为他有第一个问题的答案:从另一个模块加载角度,然后进行引导调用。 这个强制要求JS在执行任何代码之前加载这些模块的依赖关系。

假设这是您的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" 
     } 
    } 
}); 

添加在T1的主,你使实际应用中非常结束通话到下一个模块

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

这里,并把它加载了一次全部。

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"]); 
    } 

}