Aktuelle Trendstudie Digitale Innovation 2020
KOSTENLOS DOWNLOADEN

Tutorial – AngularJS mit RequireJS

Dieses Tutorial beschäftigt sich ausschließlich mit der Nutzung von AngularJS in Kombination RequireJS. Wer noch keinen Einblick in AngularJS hat, sollte sich daher zuerst unser AngularJS-Einsteiger-Tutorial anschauen.

Was erklärt dieses Tutorial nicht?

Ein weiteres Problem zur Modularisierung von AngularJS Apps ist das Laden der Controllers erst beim Wechseln das Zustandes (States), da diese, z.B. beim $stateProvider schon geladen sein müssen. Dafür gibt bereits verschiedene Lösungsansätze. Ein vielversprechender befasst sich mit Route-Resolvers.

Was ist RequireJS überhaupt?

RequireJS ist ein Datei- bzw. Modullader für Javascript, der dafür die sogenannte “asynchronous module definition” (kurz AMD) aufgreift. Javascript ist bekanntlich eine funktionale Programmiersprache, wodurch Vorteile von objektorientierten Konzepten, beispielsweise Vererbung oder Kapselung, auf der Strecke bleiben. Hier kommen die Ansätze der AMD ins Spiel, die uns diese nützlichen Werkzeuge auch für Javascript zur Verfügung stellen.

Was bringt AngularJS schon mit?

AngularJS versucht selbst schon eine Art Kapselung durch die verschieden Provider vorzugeben. Dadurch lassen sich quasi verschiedene Typen von Javascript-Modulen abgrenzen, jedoch nur im AngularJS-Kontext.

Wozu RequireJS?

RequireJS bietet sich dann an, wenn eine größere App, neben einer sauberen Datei – auch eine aufgeräumte Abhängigkeitsstruktur erhalten soll. Ohne einen Modullader werden alle verwendeten Skripte in der index.html, womöglich noch im Kopfbereich, geladen. Zusätzlich muss dabei noch auf die richtige Reihenfolge geachtet werden, damit der benötigte Service oder Controller wirklich schon geladen ist.

<html>
  <head>
    <script type="text/javascript" src="angular.js"></script>
    ...
    <script type="text/javascript" src="app.js"></script>
    <script type="text/javascript" src="controllers.js"></script>
    ...
  </head>
  <body>
    ...
  </body>
</html>

Das mag für kleinere Apps schnell und einfach sein, wird bei größeren Apps allerdings mühselig zu pflegen. Wieso sollten außerdem alle Skripte und Module direkt beim Aufruf der index.html geladen werden, wenn ich vielleicht nur die Hälfte zu Beginn brauche?

Richtig, sollte man einfach nicht!

Beispiel

  • Da es verschiedenste Ansichten gibt, wie man am besten eine App strukturiert, kann der folgende Aufbau ruhig nach Bedürfnissen abgewandelt werden.

App-Aufbau

Das Projekt besteht aus folgender Verzeichnis/Dateien Struktur:

  • index.html – laden aller nötigen Skripte
  • dem app Verzeichnis – alles für die Funktionalität der App, die app.js beinhaltet die App an sich
  • lib Verzeichnis – alle externen Bibliotheken
  • resource Verzeichnis – alle statischen Dateien
Root
- app
  - controller
    - MeinController.js
    ...
  - service
    - MeinService.js
    ...
  - template
    - TemplateMeinController.html
    ...
  - app.js
- resources
  - img
  - css
  ....
- lib
  - angularjs.min.js 
index.html

RequireJS kann hier über die Projekt-Webseite heruntergeladen werden. Die bereits minifizierte Version reicht im Normalfall vollkommen aus und wird nach erfolgreichem Download in das lib-Verzeichnis kopiert.

Root
- app
- lib
  - angularjs.min.js
  - requirejs.min.js
- resource

Der Einfachheit halber können alle in der index.html eingebundenen Skripte der App entfernt werden.

<html>
  <head>
  </head>
  <body>
    ...
  </body>
</html>

Bevor RequireJS richtig eingebunden werden kann, wird eine Konfigurationsdatei benötigt.
Diese heißt in der Regel main.js und wird jetzt im app Verzeichnis angelegt.

Root
- app
  - controller
  - service
  - app.js
  - main.js
- lib
- resource

Als nächsten folgt der Inhalt der Konfiguration.

require.config({
    baseUrl: 'app',
    paths: {
        'angular': '../lib/angularjs/angular.min',
        ...
    },
    shim: {
        'angular' : { 'exports' : 'angular' },
        ...
    }.
    callback: function () {
        'use strict';
        ...
    }
});

Zur Erklärung:

  • require.config: zwischen ({ und }) steht die Konfiguration
  • baseUrl: Basispfad, von hier aus versucht RequireJS die Skripte zu laden
  • paths: Alias (Schlüssel) – relativer Pfad vom Basispfad zur Datei (Wert) Paar
  • shim (engl. “Klemmstück”): Abhängigkeiten zu anderen Modulen definieren, Exports angegeben

Durch exports können Rückgabewerte angegeben werden. Dies findet vor allem Anwendung, wenn Frameworks, wie JQuery oder AngularJS benutzt werden. Bei JQuery beispielsweise, kann nach dem Einbinden durch $ auf das JQuery-Objekt zugegriffen werden. Durch shim und exports funktioniert dies auch mit RequireJS.

Die BasisURL ist mit Absicht auf das app Verzeichnis gesetzt, damit später das Einbinden von Services in Controllers etc. einfacher geht. Für alle externen Quellen, wie AngularJS, wird ein Alias als Schlüssel und der relative Pfad vom app Verzeichnis aus als Wert gesetzt.

Als nächsten Schritt kann nun RequireJS in die index.html eingebunden werden. Ganz normal wird RequireJS als Skript im Kopfbereich der Seite definiert, braucht jedoch das Attribut data-main, wo der Pfad zur Konfigurationsdatei angegeben werden muss.

<html>
    <head>
        <script src="lib/requirejs/requirejs.min.js" data-main="app/main"></script>
    </head>
    <body>
        ...
    </body>
</html>

Damit sind die Änderungen an der index.html abgeschlossen.

Nun werden die Module der App angepasst. Der Einsatz von RequireJS ermöglicht sogar die Konfiguration der App in mehrere Dateien aufzuteilen. Zu Beginn wird die app.js im app Verzeichnis editiert.

define([
    'angular'
], function (angular) {
    'use strict';

    return angular.module('app', []);
});

Mit define() wird das Modul gekapselt und RequireJS gesagt, dass das Modul selbst auch wieder von einem anderen Modul als Abhängigkeit geladen werden kann. Dagegen gibt es noch require(), womit zwar andere Quellen geladen werden können, das Modul selbst jedoch nicht von anderen geladen werden kann.

Die App Konfiguration und Routings können nun in eine extra Datei ausgelagert werden, z.B. in eine routing,js.

define([
    'app'
    'controller/meinController'
], function (app) {
    'use strict';

    return app.config([
        '$stateProvider',
        '$urlRouterProvider',
        function ($stateProvider, $urlRouterProvider) {

            // url routes/states
        }
    ]);
});

Hier wird das erste Mal wirklich etwas required. Durch die Angabe von app im define, wird die app.js im app Verzeichnis geladen (falls sie nicht vorher schon geladen wurde). Da die app.js unsere App zurück gibt, erhalten wir diese als Instanz als Parameter der darauf folgenden Funktion und können mit dieser ganz normal arbeiten.

Als letztes Beispiel ein kleiner Controller, der einen Service benötigt.

define([
    'app',
    'services/meinService'
], function (app) {
    'use strict';

    app.controller('meinController', [
        '$scope',
        'meinService',
        function ($scope, meinService) {

            $scope.meineFunktion = function () {
                meinService.meineFunktion();
            };  
        }
    ]);
});

Nach dem gleichen Prinzip können Services, Directives usw. eingebunden und selbst nach diesem Schema aufgebaut werden.

Damit die App auch funktioniert, muss diese natürlich noch gestartet werden. Dazu muss noch einmal die main.js ein wenig erweitert werden.

require.config({
    baseUrl: 'app',
    paths: {
        'angular': '../lib/angularjs/angular.min',
        ...
    },
    shim: {
        'angular' : { 'exports' : 'angular' },
        ...
    }.
    callback: function () {
        'use strict';
        require([
            'angular',
            'routing'
        ], function (angular) {
            // init app
            angular.bootstrap(document, ['app']);
        });
    }
});

 

Fazit

Durch RequireJS kann eine AngularJS App sehr strukturiert aufgebaut werden, was vor allem bei der Verwendung von vielen externen Quellen hilfreich sein kann. Abhängigkeiten werden erst dann geladen, wenn sie wirklich auch gebraucht werden.

Gemeinsam etwas starten?
Einfach Kontakt aufnehmen:

FLYACTS Anne

NEUKUNDEN & ANFRAGEN

ANNE SCHULZE

+49 3641 55 987 92
hallo@flyacts.com

FLYACTS Christin

PR & MARKETING

CHRISTIN DOMIN

+49 3641 55 987 93
presse@flyacts.com

Share This