Ich habe eine Wand getroffen, die ich nicht kaputt machen kann. Ich benutze angular + typescript und möchte es mit requirej arbeiten lassen. Es sind mehrere eckige Apps definiert, die abhängig von einem Attribut "data-app-name" im Body geladen werden.Requirejs + (multi) eckig + maschinenschriftlich
Ordnerstruktur (vereinfacht):
|- 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
Inhalt:
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 in 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)
;
});
Dies scheint jedoch zu brechen, mit dem guten alten Fehler: nicht erfasste Fehler: [$ Injektor: nomod] Module 'MeineAnw' ist nicht verfügbar! Sie haben entweder den Modulnamen falsch geschrieben oder vergessen, ihn zu laden.
Frage 1:
Was mache ich hier falsch? Wie kann ich sicherstellen, dass der Anruf angular.module()
erfolgt, bevor ich meine App bootstrappst?
Dies ist die Ausgabe der console.logs, wo man Winkel sehen kann, hat noch nicht das Modul angular.module („MyApp“) definiert, so dass dies geschieht, um spät offensichtlich:
UPDATE Ich kann die winkelförmigen Aufrufe in App.ts auspacken, so dass es nichts erfordert (außer für die Importe an der Spitze). Wenn ich dann App zum Shim in App1/Main.ts hinzufüge und die Abhängigkeiten dorthin lege, scheint es zu funktionieren. Ist das ein guter Weg, dies zu lösen?
UPDATE2 Wenn ich verlangen stattdessen in App.ts von definieren, hat es die Winkelmodul instanziiert, aber immer noch, nachdem er es zu Bootstrap versucht.
Frage 2:
Gibt es eine Möglichkeit benutzerdefinierte Konfiguration zu überliefern, zum Beispiel, wenn der Name die Libs sind? Ich habe versucht, die folgenden, nicht zu arbeiten schien (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, []);
});
Aber auf diese Weise logischerweise wartet angular.bootstrap() nicht darauf, dass App.ts geladen wird. Daher ist das Winkelmodul noch nicht definiert und kann nicht gestartet werden. Es scheint, dass Sie keine verschachtelte Definition wie in App1/Main.ts tun können? Wie sollte ich das konfigurieren?
ich Zweifel, dass die mehreren Schichten von 'require.config()' Anrufe wie erwartet funktioniert. (Side-question: oder?) Aber da das 'data-directory' /' data-app-name' serverseitig generiert wird, würde ich vorschlagen, dass du den 'require.config()' Aufruf auch dynamisch erzeugst. Möglicherweise möchten Sie sogar das entsprechende Fragment direkt serverseitig direkt in die Index.html einbinden. Von dort aus müssen Sie die Pfade in den AMD-Modulen optimieren. Und eine Randbemerkung: Warum verwenden Sie nicht die native Unterstützung von Typescript für AMD, d. H. Die 'import Foo = require ('Foo')' Syntax? –
Ich mache das 'import' Zeug auf Angular-App-Ebene (in App.ts und allen anderen eckigen Komponenten). Ist es besser, die Importsyntax überall zu verwenden, wenn ich Typoskript verwende? Ich denke nicht, dass es auf Drittanbieter-Bibliotheken von Drittanbietern funktioniert. – devqon
Und ja, die mehreren Ebenen von 'require.config()' scheint zu funktionieren :) – devqon