Кажется, я ударился о стену, которую я не могу сломать. Я использую angular + typescript и хочу, чтобы он работал с requirejs. Определено несколько приложений angular, которые загружаются в зависимости от атрибута 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]);
});
});
});
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");
});
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)
;
});
Это, однако, похоже, сломается с хорошей старой ошибкой: Ошибка при вскрытии: [$ инжектор: nomod] Модуль "MyApp" недоступен! Вы либо ошибочно написали имя модуля, либо забыли загрузить его.
Вопрос 1:
Что я здесь делаю неправильно? Как я могу убедиться, что вызов angular.module()
выполняется до того, как я загружу свое приложение?
Это результат работы console.logs, где вы можете видеть, что angular еще не определил модуль angular.module( "MyApp" ), так что это делается до конца, очевидно:
UPDATE Я могу развернуть вызовы angular в App.ts, поэтому он ничего не требует (кроме импорта вверху). Затем, если я добавлю App в прокладку в App1/Main.ts и заложил там зависимости, похоже, он работает. Это хороший способ решить эту проблему?
UPDATE2 Если я использую require вместо define в App.ts, он создает экземпляр модуля 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. Поэтому модуль angular еще не определен, и он не может загрузиться. Кажется, что вы не можете сделать вложенное определение, как в App1/Main.ts? Как мне настроить это?