Component.js has emerged as a very sensible way to package and share web components.
Read more about what makes it great in general if you want, but I want to point out two things:
- Namespacing via Github username
- Great for AngularJS modules
Namespacing via Github username
When everybody shares the same namespace, like with npm, Bower or Ruby gems, you quite quickly run into the issue where all the good names are taken. For example, it’s quite telling that in npm there are modules named progress
, progress-bar
, progress-component
, progress2
, progressbar
and progressify
, all of which are progress bars.
With component.js, components are instead identified by github-username/repo-name
. That gives each developer the freedom to choose names for their components based on what’s the most relevant, rather than just from the few ones that aren’t taken yet.
Great for AngularJS modules
Component.js knows about scripts, css, images and html. That makes it a good fit for AngularJS modules. But there’s more! :)
It implements CommonJS’ synchronous require()
(the same standard which Node.js uses for npm modules).
Here are some tips which will make your life and others’ a little easier, at least in regards to AngularJS modules shared as components:
Component name *-for-angular
If you name your components something-or-other-for-angular
, it can help people know it’s for angular. It will also make it easier to search and find components specifically for AngularJS.
Register the module and controllers/directives/etc immediately
Usually, I would recommend you follow the substack pattern and exporting a single function for the user to call, when writing your index.js
of a CommonsJS module. (UPDATE: Apparently what in some circles is known as the “substack pattern” appears to have been preceded by at least TJ Holowaychuk.)
In this case however, you are writing an AngularJS module too, and already registering it with angular. Those who will use it will use AngularJS’ dependency injection (DI) to obtain it. There is no need to force the user to call any exported function. Simply register with angular:
angular.module("myModule", []).directive("myDirective", function() { ... }); # no module.exports=...
The persons who then want to use it, have less stuff to do, in order to have your AngularJS module registered. They only have to do this:
require("my-module-for-angular"); angular.module("theirModule", ["myModule"]).directive(...);
A neat side-effect of this, is that it doesn’t matter if they call require("my-module-for-angular")
before each of their module declarations, it will only execute your code once, because of how require()
works.
Require() all *-for-angular
components automatically
If both above rules are followed, you can even skip specify to require()
each component individually. It can be automated.
I have prepared a tiny dependency-free component which does this, so you can use it with minimal impact on the size of your build. It’s really small and efficient. Just add this dependency to your component.json
:
"hugojosefson/require-all-for-angular-modules": "1.0.0"
…then call it in your code after the angular.js
script is loaded, but before it initializes at document ready. For example like this:
<script src="angular.js"></script> <script src="build/build.js"></script> <script> require("require-all-for-angular-modules")(); </script>
It will require()
all modules which end in -for-angular
, so they will have had their chance to run and register their angular.module
s before AngularJS starts.
Conclusion
Now the only places you have to maintain definitions of AngularJS modules, are of course in component.json
dependencies, and in each angular.module
‘s dependency array.
No more one-<script/>
-tag-per-module, nor one-require()
-per-module!
Happy coding!
Nice post, I wouldn’t call that the “Substack pattern” though, many people used it before him, including myself, in fact I was the one that suggested he did that with one of his earlier modules node-mkdirp haha
Aha! Thanks for sharing. Updated the text :)
I was about to email you to ask you more about this and I just saw this article. Nice stuff! I would love to see some example, is there any repo around using component.js and angular?
Thanks. There is the image-url-for-angular at https://github.com/hugojosefson/image-url-for-angular which is a component you can use like this. I don’t have anything public to share in terms of complete AngularJS project which uses it. If you follow the instructions above, it should work though. Let me know otherwise.
Very nice! Thanks for sharing.
Thanks for the post it helped me getting started with Angular.js and Component.js.
An other way to require Angular.js modules would be to add module.exports = ‘myModuleName’; at the end of your main Component.js module. Then you could do angular.module(‘app’, [ require(‘module-for-angular’) ]);. That way you don’t have to remember the names of both the component and module as well.