After working for quite some time now with RequireJS to handle AngularJS components, I found myself explaining to curious people how RequireJS makes perfect sense to work with AngularJS.
The main question I try to answer is “How come you are using RequireJS if AngularJS already handles dependencies?”.
AngularJS modules
As you may know, on AngularJS you have to declare modules in order to bootstrap applications. Those modules can contain all kinds of AngularJS components, such as directives, filters and services.
Here we created a module first which contains a very simple and friendly filter. Then, the dependencies comes to the equation.
AngularJS dependencies and injection
AngularJS was designed to enable modules to inject other modules as dependencies. Those injected modules should have other AngularJS components associated to make use of this functionality. Once you inject an already existing module to your newly created module, you may use every AngularJS component defined on the injected module. In other words, injection of modules promotes a healthy reusable code policy in order to let the developer partition functionality in smaller parts as much as it makes sense.
Here we created a module second which injects the module first. This conclusively means that we are going to be able to use filter ‘greet’ on an application bootstrapped by ‘second’ module. This said, it is important to mention that before ‘second’ module instantiates, the ‘first’ module should be already defined in order to inject it successfully. In other (official) words, “Depending on a module implies that required module needs to be loaded before the requiring module is loaded”. That last part is very important for this post as it is the key concept to make sense of RequireJS with AngularJS.
Let’s imagine we have both previously defined modules on separated files, firstModule.js and secondModule.js. To make everything work OK as explained, you will need to have those scripts loaded in your page.
Imagine the amount of scripts you would have to load if your application is constructed with lots of modules. This does not really scale, does it?
Using RequireJS
RequireJS is a well known and extensively used AMD script loader which helps when you need to load scripts before other scripts. In other words, it successfully manages script dependencies. Ring a bell?
Although AngularJS manages dependencies, internal AngularJS components injectable dependencies, you may use script loaders to manage scripts dependencies.
Here you can see that to define the second module we are loading firstly through RequireJS the first module in order to inject it. Again, this is because you need to have the injected modules loaded before you can inject them, much like having the <script> for the first module before the second module loads. Furthermore, this example shows how you should load AngularJS within its own variable inside the module in order to use it on the callback. This is to include AngularJS into the very same idea, not having any <script> not either for loading the framework. Notice that there is no need to return the created module; having the module loaded with angular before you inject it is enough.
To conclude the idea, once you load the second module on your application, you will be able to use the greet and goodbye filters.
RequireJS integrated into AngularJS
I found a very interesting video, from AngularJS Youtube channel where Brad Green and Igor Minar, AngularJS masterminds, answered a question about lazy loading, for which Igor answered that they are working on having RequireJS integrated into AngularJS. There is no other reference to this so I took the liberty to ask Brad via Twitter how this was going:
For which he replied:
Hopefully they can integrate it successfully but in the mean time, hope I could make a point on how RequireJS can be helpful on a rather big AngularJS application.
UPDATE 1:
Well, I should thank Sampo Haavisto for requesting news about RequireJS plans for AngularJS. This is what Brad Green replied.
UPDATE 2:
I had the chance to work on a very large AngularJS application that needed a very well thought modular architecture in order to enable reusability. In that sense, I used the following RequireJS pattern:
The main idea is to return basic information of the created module in order to let its usage by other modules. The second module uses the first module just by requiring the file through RequireJS and assuming that it returns an object with the module name created.
Making sense of RequireJS with AngularJS
A good marriage.