The case
I'm trying to get to the most convenient solution of setting up a big javascript project.
Requirements are:
- Modular javascript: just one object in the global namespace if necessary
- Compatible with bower components
- Compatible with grunt: building and deployment done by grunt (contrib-usemin or contrib-requirejs)
To my own suprise, this turns out to be a non trivial task. I'm running into the following issues when using AMD:
- Loading bower components cannot alwasy be done easily. Raphael for example cannot be loaded using AMD without modifying the source. Which is really not an option when using bower, since I only push the dependency list to git. Also: loading javascript libraries that do not support AMD, can be shimmed, but consist of more than one file (like jquery-ui) are problematic; I would need to hack that together.
- De requirejs optimizer builds everything into one file, not allowing the option to seperate libraries from site scripts. Something that seems a sane thing to do.
When I'm NOT using AMD I run into other issues:
- How do I control dependencies in a large project?
A possible solution
So I'm contemplating a solution that would:
- Keep it portable, don't force AMD on future users
- Prevent global namespace clutter
- Remain compatible with bower
- Allow usemin to build the whole lot in grunt
It would consist of a small script defining a require( <deps>, <factory> ) and a `define( , , ) function that implements basic module definition and injection. It would not implement any asynchronous loading or queuing of scripts with unmatched dependencies!
Furthermore I will define any module using the named module patter instead of using anonymous modules. Even though this will sacrifice a minimal amount of portability.
Now I can use either requirejs or that tiny dependency injector in combination with manual <script src=""></script> loading. When using the latter option I would still need to register the loaded non-amd libraries using something like this:
define( 'raphael', [], function() { return Raphael; })
What do you think? Am I doing something sane? Reinventing the wheel? Unnecessarily complex?
Update
I think I could use almond (https://github.com/jrburke/almond) to fullfill the abovementioned purpose.