-
Notifications
You must be signed in to change notification settings - Fork 73
Angular boot script
This story is all about the angular.module
function call. Angular providers (services, factories), controllers etc, they all need to reside in modules.
The idea behind mean.io is to encapsulate functionality of each package into a module named mean.package_name
, where package_name
is, naturally, the name of the corresponding package.
In order to achieve this code architecture in an ordered manner, meanio core searches for the modules (they might be in node_modules
; a node module that declares a mean version in its package.json
is a mean module; or they might be in the packages
directory), and for each module it records a list of its angular dependencies. Each module code should create an instance of meanio.Module, and that module should call the angularDependencies
function to declare an array of angular dependencies.
When the modules are found, enlisted and enabled, a data structure enlisting all the modules by their name and their angular dependencies is sent over to the Web browser as a hard-coded JavaScript variable embedded directly into the window.modules
variable.
The window.modules
variable is an array of {module:package_name, angularDependencies:[...]} hash structures. It is used in the following way:
'use strict';
angular.element(document).ready(function() {
//Fixing facebook bug with redirect
if (window.location.hash === '#_=_') window.location.hash = '#!';
//Then init the app
angular.bootstrap(document, ['mean']);
});
// Dynamically add angular modules declared by packages
var packageModules = [];
for (var index in window.modules) {
angular.module(window.modules[index].module, window.modules[index].angularDependencies || []);
packageModules.push(window.modules[index].module);
}
// Default modules
var modules = ['ngCookies', 'ngResource', 'ui.bootstrap', 'ui.router'];
modules = modules.concat(packageModules);
// Combined modules
angular.module('mean', modules);
The script shown above resides in the packages/system/public/init.js
file. I will call the above script "the boot script"
Now, the problem with mean.io lies in the fact that the boot script (like contents of all other files from all other packages) will be aggregated into a minified-or-not file that will be sent over to the browser as a response to the aggregated.js
call.
Being aggregated with all the other code, it might easily turn out that the boot script will not be the first code to be ran out of all code from the packages. Some package scripts may be ran before the boot script.
Whatever script runs before the boot script, it better not try to use its angular module. Or it will get Angular errors reporting that a module mean.package_name
was not found or was misspelled.
But, when you take a look at how the aggregation code looked like throughout the meanio versions, you will find that never was care taken to somehow put the boot script at the beginning of all the aggregated package code. If you start wondering how the package code works then, you might stumble upon another patch, built into every module (well, almost every, perhaps for historic reasons) by the mean scaffolder.
When a scaffolder build a directory structure for a package named package1, you will get a directory named package1 in which you will have a public
subdirectory with a package1.js
file that will state
'use strict';
angular.module('mean.package1',[]);
Obviously, scaffolder tries to compensate for the probability that package1 code might be aggregated before the boot script, so that all the package1 code will run without a problem.
However, there is a huge problem: all the code that will declare/define the contents of the mean.package1
will be annulated when the boot script runs. Because boot script will destroy the mean.package1
module that package1 code created and just create an empty new mean.package1
module instead. So, the patch offered by packages/package1/public/package1.js
is useless. This is not the way how the synchronicity problem of aggregating the boot script should be approached.
The most reasonable solution might be:
- Move the boot script out of the
system
module into the core. - Install the core's boot script locally through bower by adding a following line into bower.json:
"web-bootstrap": "./node_modules/meanio/resources/web-bootstrap.js"
- Add the installed bower_component into
assets.json
by adding"bower_components/web-bootstrap/index.js"
intocore.js
part. - Remove the "angular.module patch" files from all of the packages.
- Stop producing the "angular.module patch" file by the scaffolder.
This way the boot script will be treated as "top-level class citizen", and it will surely be ran before any package code.
This problem has already been encountered throughout the mean.io community, and there is already an existing mean issue #963 that addresses just points 4 and 5 of the proposed solution. So, the solution here should be treated as a full-scale solution for #963