【发布时间】:2016-02-03 15:40:56
【问题描述】:
我似乎碰到了一堵我无法打破的墙。我正在使用 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
内容:
索引.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)
;
});
然而,这似乎打破了旧的错误: 未捕获的错误:[$injector:nomod] 模块“MyApp”不可用!您要么拼错了模块名称,要么忘记加载它。
问题 1:
我在这里做错了什么?在引导我的应用之前,如何确保 angular.module() 调用已完成?
这是console.logs的输出,在这里你可以看到angular还没有定义模块angular.module("MyApp"),所以很明显这是很晚才完成的:
更新 我可以在 App.ts 中解开角度调用,所以它不需要任何东西(除了顶部的导入)。然后,如果我将 App 添加到 App1/Main.ts 中的 shim,并在那里放置依赖项,它似乎可以工作。这是解决这个问题的好方法吗?
更新2 如果我在 App.ts 中使用 require 而不是定义,它会实例化 angular 模块,但仍然在尝试引导它之后。
问题 2:
有没有办法传递自定义配置,例如 Libs 所在的目录名称?我尝试了以下似乎不起作用的方法(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 被加载。因此,角度模块尚未定义,并且无法引导。似乎您不能像在 App1/Main.ts 中那样进行嵌套定义?我应该如何配置?
【问题讨论】:
-
我怀疑
require.config()的多层调用能否按预期工作。 (附带问题:是吗?)但是由于data-directory/data-app-name是在服务器端生成的,我建议您也动态生成require.config()调用。您甚至可能希望在服务器端将适当的片段直接动态地包含到 Index.html 中。从那里,您将需要调整 AMD 模块中的路径。还有一个旁注:你为什么不使用 Typescript 对 AMD 的原生支持,即import Foo = require('Foo')语法? -
我在 angular-app 级别(在 App.ts 和所有其他 angular 组件中)做
import的东西。如果我使用打字稿,在任何地方都使用导入语法会更好吗?我认为它不适用于非 AMD 第三方库? -
是的,
require.config()的多层似乎工作:) -
您能否将 cmets 添加到已解决的依赖项中(这样我们就不必回读配置),绘制包含预期/需要/期望状态的依赖关系图或通过电子邮件将项目发送给我(A)xD
-
我开始觉得导入可能会被阻塞,我没有遇到需要控制器的问题(也跳过了插件)。
标签: angular typescript requirejs amd