AngularJS — разделение приложения на модули и загрузка компонентов с помощью RequireJS

от автора

Использование AngularJS в паре с RequireJS — достаточно популярный подход к разработке веб приложений в последнее время. И один из основных вопросов — структура приложения. Существует достаточно известный seed для такого приложения tnajdek/angular-requirejs-seed, но мне это не походит, так как при увеличении функционала приложения — данная структура просто будет засоряться кучей файлов, не будет никакого логического разделения скриптов и достаточно сложно будет их менеджить.

Целью было создать приложение с модульной и гибкой архитектурой (ну скорее просто разбиение приложение не логические части), с простым и понятным описанием зависимостей между частями приложения и уменьшить зависимость кода от структуры приложения.

Модуль

В данном случае, это логически отдельная часть приложения, включающая в себя набор компонентов:

  • ngModule;
  • Controller;
  • FIlter;
  • Directive;
  • Service;
  • Template;
  • Configs — содержат config() и run() методы для текущего ngModule.

Проблема

При использовании RequrieJS, файлы приложения чаще всего подключаются как-то так:

require('modules/foo/controller/foo-controller.js'); require('modules/foo/service/foo-service.js'); require('modules/foo/directive/foo-controller.js'); require('text!modules/foo/templates/foo.html'); require('modules/bar/directive/bar-controller.js'); 

Здесь есть явные минусы:

  • Код очень зависит от структуры проекта;
  • Код очень зависит от названий модулей;
  • Достаточно много нужно писать руками.

Решение

Были написаны RequireJS плагины для загрузки компонентов модуля.

К примру есть такая структура приложения (кстати, очень похожая на структуру бандлов в Symfony2):

 app    |-modules    |       |-menu    |       |    |-controller    |       |    |          |-menu-controller.js    |       |    |-menu.js        |       |        |       |-user    |             |-controllers    |             |           |-profile.js    |             |-resources    |             |           |-configs    |             |           |        |-main.js    |             |           |    |             |           |-templates    |             |           |          |-user-profile.html    |             |           |-directives    |             |                      |-user-menu     |             |                                 |-user-menu.js    |             |                                 |-user-menu.html    |             |-src    |             |      |-providers    |             |      |          |-profile-information.js     |             |      |-factory    |             |              |-guest.js    |             |-user.js    |    |-application.js    |-boot.js 

В данном случаем у нас есть 2 модуля: user и menu. Файлы /app/modules/menu/menu.js и /app/modules/user/user.js — скрипты с инициализацией angularJS модулей. Все остальное — думаю понятно.

Теперь нужно задать конфигурацию для подключения всех компонентов. Делается это с помощью requirejs.config:

requirejs.config({   baseUrl: '/application',   paths: {     'text': '../bower_components/requirejs-text/text',      // Structure plugins:        'base': '../bower_components/requirejs-angualr-loader/src/base',     'template': '../bower_components/requirejs-angualr-loader/src/template',     'controller': '../bower_components/requirejs-angualr-loader/src/controller',     'service': '../bower_components/requirejs-angualr-loader/src/service',     'module': '../bower_components/requirejs-angualr-loader/src/module',     'config': '../bower_components/requirejs-angualr-loader/src/config',     'directive': '../bower_components/requirejs-angualr-loader/src/directive',     'filter': '../bower_components/requirejs-angualr-loader/src/filter'   },   structure: {       prefix: 'modules/{module}',        module: {         path: '/{module}'       },             template: {         path: '/resources/views/{template}',       },        controller: {         path: '/controllers/{controller}'       },        service: {         path: '/src/{service}'       },        config: {         path: '/resources/configs/{config}'       },        directive: {         path: '/resources/directives/{directive}/{directive}'       },        filter: {         path: '/resources/filters/{filter}'       }     } }); 

Все пути каждого компонента определены в рамках модуля. Поле structure.prefix — путь к корню модуля, после baseUrl.

Теперь, если мы хотим подключить файл /app/modules/user/user.js из:
1. /app.js:

require('module!user')

2. /app/modules/user/controllers/profile.js:

require('module!@')

В рамках одного модуля — имя модуля можно не писать, достаточно символа ‘@’. Тем самым, если придется переименовать модуль — не нужно будет менять код.

Теперь, если мы хотим подключить файл /app/modules/user/controllers/profile.js из:
1. /app.js:

require('controller!user:profile')

До двоеточия — название модуля, после двоеточия — название контроллера.

2. /app/modules/user/user.js:

require('controller!profile')

В рамках одного модуля — имя модуля можно не писать, достаточно указать только название контроллера. Так же, если контроллер лежит на уровень ниже, то возможно подключать так:

require('controller!additional/path/to/profile')

Точно так же и для всех других компонентов.

Результат

Получилось очень гибкая структура приложения с поддержкой разделения кода на модули и с минимальной зависимостью кода от структуры проекта даже если придется перенести какой либо компонент из одного модуля в другой — то практически ничего менять не придется. И лишнего кода так же стало меньше.

Так же не возникает никаких проблем при сброке проекта. В тестовом приложение есть пример собранного проекта в папке /build и Gruntfile для сборки, но в нем нету ничего не обычного.

Ссылки:

Данный подход используем в большом корпоративном приложении, поддержка и развитие данного подхода будет поддерживаться и развиваться.

ссылка на оригинал статьи http://habrahabr.ru/post/216469/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *