ANGULARJS + REQUIREJS

в 12:06, , рубрики: amd, AngularJS, javascript, requirejs

ANGULARJS + REQUIREJS
Во время разработки проектов мы полюбили AngularJs. Но также мы встретили некоторые трудности в борьбе за чистоту модульности, с которой AngularJs справляется хорошо, но все же порой ему чего-то не хватает. RequireJs оказывается полезным там, где AngularJs оставляет желать лучшего, но использование их вместе — не совсем тривиальная задача.

Итак, опишем наш взгляд на решение проблемы.

Для чего?

Работая с AngularJs вы обязательно задумаетесь о правильной организации кода. Конечно уже существуют отличные примеры решения проблемы. Например можно изучить теоретический пост Брайана Форда или практическое руководство Клиффа Мейерса. Я же поделюсь способом организации кода в приложениях AngularJs с использованием RequireJs.

Данный подход будет полезен, если вы хотите:

  • перестать беспокоиться о подключении скриптов в правильном порядке;
  • загружать javascript код асинхронно;
  • иметь возможность скомпилировать код в один минифицированный JS-файл;

Для кого?

Предполагается, что вы уже знаете основы AngularJs, а так же по крайней мере знакомы с подходом AMD и библиотекой RequireJs. Чтобы проиллюстрировать подход, я сначала подключу RequireJs для Angular Seed и опишу вносимые изменения. Angular Seed структурирует код, разделяя файлы по назначению. Таким же образом поступлю и я.

Как?

Angular Seed Project

Давайте познакомимся со структурой кода в Angular Seed. Взгляните на код примера на github:

  • app.js файл используется для инициализации загрузки и конфигурирования приложения.
  • сами файлы приложения — контроллеры (controllers), директивы (directives), фильтры (filters), сервисы (services).
  • index.html с подключенными JS-файлами в нужном порядке.
  • или index-async.html, который использует angular-loader.js или сторонние загрузчики, для загрузки зависимостей асинхронно.

Что ж, начнем.

Добавляем RequireJs

Взгляните на пример в браузере или на github.

Установка зависимостей

Для этого я использовал bower. Код bower.json:

 {
    "name": "AngularJS + RequireJS Example",
    "version": "0.1",
    "main": "index.html",
    "ignore": [
      "**/.*",
      "libs"
    ],
    "dependencies": {
     "angular": "latest",
     "requirejs": "latest",
     "requirejs-domready": "latest"
   }
 }

Положите файл .bowerrc рядом с bower.json и запустите bower install. Теперь все необходимые зависимости находятся в директории libs.

index.html

Разрушение будет хорошим началом! Откройте index.html и удалите все теги <script>. Выглядит чище, не так ли? Теперь подключите один скрипт перед закрывающим тегом </body>, который будет загружать библиотеку RequireJs, и поручит ей искать конфигурацию в файле js/main.js, указанном в атрибуте data-main тега <script>:

<!doctype html>
 <html lang="en">
 <head>
   <meta charset="utf-8">
   <title>My AngularJS AngularJS + RequireJS App</title>
   <link rel="stylesheet" href="css/app.css">
 </head>
 <body>
   <ul class="menu">
     <li><a href="#/view1">view1</a></li>
     <li><a href="#/view2">view2</a></li>
   </ul>
 
   <div data-ng-view></div>
 
   <div>Angular Require seed app: v<span app-version></span></div>

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

Это все что нам необходимо. Закройте файл index.html, поскольку он нам больше не потребуется.

main.js

Приступим к конфигуации RequireJS.

require.config({
 
     //  псевдонимы и пути используемых библиотек и плагинов
     paths: {
         'domReady': '../lib/requirejs-domready/domReady',
         'angular': '../lib/angular/angular'
     },
 
     // angular не поддерживает AMD из коробки, поэтому экспортируем перменную angular в глобальную область
     shim: {
         'angular': {
             exports: 'angular'
         }
     },
 
     // запустить приложение
     deps: ['./bootstrap']
});

Что только что произошло?

В блоке paths мы устанавливаем псевдонимы используемых библиотек и плагинов. Далее указываем что AngularJs должен быть виден в глобальной области видимости (для этого используется блок shim). Так же указыавем, что для запуска приложения должен быть загружен bootstrap.js.

bootstrap.js

Сейчас нам нужно настроить AngularJs, именно для этого используется файл bootstrap.js (обратите внимание, что вам больше не нужно использовать ng-app в HTML коде приложения). Первым делом нам потребуется routes.js, который содержит конфигурацию маршрутов приложения, поэтому добавим его в список зависимостей.

Заметьте, что в этом модуле мы почти не имеем дело с асинхронной загрузкой, и цепочка подключения скриптов всегда будет
angular->app->routes так как они зависят от друг друга: AngularJs необходим до создания модуля приложения (app) который уже должен существовать при конфигурировании маршрутов (routes).

 /**
  * bootstraps angular onto the window.document node
  */
 define([
     'require',
     'angular',
     'app',
     'routes'
 ], function (require, ng) {
     'use strict';
 
     require(['domReady!'], function (document) {
         ng.bootstrap(document, ['app']);
     });
});

Мы используем модуль domReady, чтобы пред запуском приложения убедиться, что DOM загружен. Также обратите внимание, что для запуска необходимо загрузить зависимость app.js, которая является основой приложения.

app.js

app.js содержит определение модуля верхнего уровня и загружает зависимости его подмодулей.

define([
     'angular',
     './controllers/index',
     './directives/index',
     './filters/index',
     './services/index'
 ], function (ng) {
     'use strict';
 
     return ng.module('app', [
         'app.services',
         'app.controllers',
         'app.filters',
         'app.directives'
     ]);
});

Мы условились использовать четыре основных модуля: контроллеры (controllers), директивы (directives), фильтры (filters), сервисы (services). Указываем, что эти модули должны быть загружены до определения основного модуля.

routes.js

Конфигурация маршрутов (routes) осуществляется в этом файле. Кроме того возможно указывать маршруты для каждого модуля в отдельности (этот случай выходит за рамки данной статьи).

define(['./app'], function (app) {
     'use strict';
     return app.config(['$routeProvider', function ($routeProvider) {
         $routeProvider.when('/view1', {
             templateUrl: 'partials/partial1.html',
             controller: 'MyCtrl1'
         });
 
         $routeProvider.when('/view2', {
             templateUrl: 'partials/partial2.html',
             controller: 'MyCtrl2'
         });
 
         $routeProvider.otherwise({
             redirectTo: '/view1'
         });
     }]);
});

Структура модуля

Модули состоят из трех частей:

  • объявление модуля
  • компонент
  • загрузчик

Давайте рассмотрим модуль app.controllers для примера.

Объявление модуля controllers/module.js

define(['angular'], function (ng) {
    'use strict';
    return ng.module('app.controllers', []);
});

Этот файл будет использоваться компонентами модуля для назначения самих себя (см. следующую часть)

Загрузчик модуля controllers/index.js

Это просто пустой блок define, который включает в себя все компоненты модуля. Здесь не нужно упоминать файл module.js так как он будет запрошен самими компонентами (в данном случае контроллерами). Загрузчик подключается как зависимость верхнего уровня модуля приложения. Благодаря ему RequireJs знает какие файлы загружать.

define([
    './my-ctrl-1',
    './my-ctrl-2'
], function () {});

Компонент модуля controllers/my-ctrl-1.js

В случае с модулем контроллера app.controllers компонентами будут отдельные контроллеры приложения. Пример определения контроллера:

define(['./module'], function (controllers) {
    'use strict';
    controllers.controller('MyCtrl1', [function ($scope) {}]);
});

Обратите внимание, что мы использовали ссылку на ./module.js для того чтобы получить модуль и присоединить компонент к модулю.

Выводы:

Вот и все. Теперь мы имеем рабочее AngularJs приложение основанное на RequireJs. Вы можете наслаждаться разработкой не обращая внимания на порядок подключения ваших скриптов, а также этот подход позволит вам с легкостью минифицировать и объединить все файлы приложения в один.

Автор: oledje

Источник

Поделиться

* - обязательные к заполнению поля