我似乎遇到了一个无法突破的障碍。我正在使用Angular + TypeScript,并希望将其与RequireJS配合使用。有多个定义的Angular应用程序,这些应用程序根据body上的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
Contents:
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中的Main.ts:
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");
});
App1/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)
;
});
然而,出现了一个老问题:Uncaught Error: [$injector:nomod] 模块'MyApp'不可用!您可能拼写错误或忘记加载它。
问题1:
我做错了什么?如何确保在启动应用程序之前完成angular.module()
调用?下面是控制台日志的输出结果,您可以看到angular尚未定义模块angular.module("MyApp"),所以这显然太晚了:
更新 我可以取消App.ts中的angular调用,因此它不需要任何东西(除了顶部的导入)。然后,如果我将App添加到App1 / Main.ts的shim中,并在那里设置依赖项,似乎可以解决这个问题。这是解决这个问题的好方法吗?
更新2 如果我在App.ts中使用require而不是define,则确实会实例化angular模块,但仍然是在尝试引导它之后。
问题2:
是否有任何方法传递自定义配置,例如库所在的目录名称?我尝试了以下内容,但似乎没有起作用(Main.ts):
requirejs.config({
paths: {
"appMain": directory + "/Main"
},
config: {
"appMain": {
libsPath: "Libs/"
},
"app": {
name: appName
}
}
});
App1/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 加载完成。因此,angular 模块尚未定义,导致引导失败。似乎不能像 App1/Main.ts 中那样进行嵌套定义?我该如何配置?
require.config()
多层调用会按预期工作(附带问题:它们能吗?)但由于data-directory
/data-app-name
是在服务器端生成的,建议您也动态生成require.config()
调用。甚至可以动态地将相应片段直接包含到Index.html中。从那里开始,您需要调整AMD模块中的路径。另外一点:为什么不使用Typescript对AMD的本机支持,即import Foo = require('Foo')
语法? - Nikos Paraskevopoulosrequire.config()
似乎有效 :) - devqon