Using AngularJS paired with RequireJS is a fairly popular approach to developing web applications recently. And one of the main issues is the structure of the application. There is a well-known seed for such an application
tnajdek / angular-requirejs-seed , but this does not
suit me, because as the functionality of the application increases, this structure will simply be clogged with a bunch of files, there will be no logical separation of the scripts and it will be difficult enough to manage them.
The goal was to create an application with a modular and flexible architecture (well, rather, just splitting the application is not logical parts), with a simple and understandable description of the dependencies between parts of the application and reduce the dependence of the code on the structure of the application.
Module
In this case, it is a logically separate part of the application, which includes a set of components:
- ngModule;
- Controller;
- FILTER;
- Directive;
- Service;
- Template;
- Configs - contain config () and run () methods for the current ngModule.
')
Problem
When using RequrieJS, application files are most often connected as follows:
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');
There are obvious disadvantages:
- The code is very dependent on the project structure;
- The code is very dependent on the names of the modules;
- You have to write a lot with your hands.
Decision
RequireJS plugins for loading module components were written.
For example, there is such an application structure (by the way, very similar to the bundle structure in 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
In this case, we have 2 modules:
user and
menu . The files
/app/modules/menu/menu.js and
/app/modules/user/user.js are scripts with initialization of angularJS modules. Everything else - I think it is clear.
Now you need to set the configuration for the connection of all components. This is done using
requirejs.config :
requirejs.config({ baseUrl: '/application', paths: { 'text': '../bower_components/requirejs-text/text',
All paths of each component are defined within the module. The field
structure.prefix is the path to the module root, after
baseUrl .
Now, if we want to include the file
/app/modules/user/user.js :
1.
/app.js :
require('module!user')
2.
/app/modules/user/controllers/profile.js :
require('module!@')
Within the framework of one module - the name of the module can be omitted; the '@' symbol is enough. Thus, if you have to rename the module, you will not need to change the code.
Now, if we want to include the file
/app/modules/user/controllers/profile.js
from:
1.
/app.js :
require('controller!user:profile')
Before the colon - the name of the module, after the colon - the name of the controller.
2.
/app/modules/user/user.js :
require('controller!profile')
Within the framework of one module - the name of the module can be omitted; it is enough to indicate only the name of the controller. Also, if the controller lies one level lower, then it is possible to connect like this:
require('controller!additional/path/to/profile')
Similarly for all other components.
Result
It turned out a very flexible structure of the application with the support of code separation into modules and with minimal code dependence on the project structure even if you have to transfer any component from one module to another - then you will not have to change almost anything. And the excess code also became less.
Also, there are no problems when cutting back the project. In the test application there is an example of an assembled project in the / build folder and the Gruntfile for the build, but there is nothing ordinary in it.
References:
We use this approach in a large corporate application, the support and development of this approach will be supported and developed.