...

четверг, 20 марта 2014 г.

[Из песочницы] 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 для сборки, но в нем нету ничего не обычного.


Ссылки:


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


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий