Towards atomic AngularJS components with Browserify

When I read Atomic Product Development a few weeks ago, it was a lightbulb moment for me. It managed to finally put words (and code!) to the handful of loose ideas that had been rattling around my head for the better part of a year. I've started contributing to the project, and you'll undoubtedly hear more about it from me in the future, but I thought it might be helpful to first show a basic application of the concepts to AngularJS.

Idiomatic Angular

The atomify projects (specifically atomify-js and atomify-css) were not created with frameworks like AngularJS in mind. If you take a look at the atomify-example, you can see it's more like Backbone or vanilla JS, but the principles and underlying tools are universally appealing.

Therefore, the challenge I've spent the last couple of weeks solving is how to utilize that foundation in the context of AngularJS. As it turns out, it's actually pretty simple.

Units and terminology

Since the traditionally generic term module has a very specific and concrete meaning in the Angular world, I've taken to using the term component when discussing this approach. Slightly confusing matters is the fact that components are packaged as Angular modules, but bear with me, it will all make sense in a minute.

The same, but different

At the heart of the atomify philosophy is the concept of fully self-contained, yet configurable pieces. Bundling JS, HTML, and CSS into an atomic unit. It just so happens that Angular has its own mechanism for doing most of that, which is its module API. The challenge, then, is how do you structure your Angular modules in a way that will enable you to develop them independently of a larger host application? How do you write a login form, or a column chart, in a way that it can live in its own repository, have its own versioning and releases, but also be seamlessly dropped into any number of contexts large or small? Well, let's take a look.

The whole package

As I mentioned before, our component is defined using the angular.module API. In our simple example, this is what that looks like.

var angular = require('angular');

module.exports = angular.module('demo-component', [])
  .constant('template', require('./template.html'))
  .directive('demoComponent', require('./DemoDirective'))
  .controller('DemoController', require('./DemoController'));

We are require()-ing Angular (thanks to browserify-shim), and then composing our module by defining our HTML template as a constant, and specifying a directive and a controller.

About that template

You'll notice that we are requiring an HTML file, which is not something you normally see. We are only able to do so thanks to partialify, which simply reads in the contents of the HTML (or XML, or JSON, or other plain text) file and assigns it like if we had written the markup inline as a string. This happens as part of the build, thanks to Browserify's transform mechanism.

Self directive

Our directive is super simple, but a bit different than what you're probably used to seeing. Essentially all the directive does is turn the template we've made available into a DOM element, compiles it with the scope it receives, and inserts the new node into the DOM wherever it was defined. You can see the full code below.

var angular = require('angular');

module.exports = function DemoDirective ($compile, template) {
  return {
    scope: {
      list: '='
    },
    restrict: 'E',
    controller: 'DemoController',
    link: function (scope, element) {

      var el = angular.element(template);
      el = $compile(el)(scope);
      angular.element(element[0]).append(el);

    }
  };
};

Not all of your directives will end up being this simple but I suspect many will. I also think it's easy to see how these standard directives could be generated by a utility function, removing the need to even create a separate file for them.

And then...

That's kind of it, at least for now. You define a controller like you would any other time and have it manage the $scope and user interactions for its little piece of the DOM. Maybe it requests data from the backend, communicates with other controllers, etc. but it's basically just a normal everyday controller. Now, to create truly reusable components you will need to be dilligent in avoiding tight coupling, defining and maintaining small, well defined API surface areas and the like, but those are all good things to worry about anyhow.

For now, simply specify your component module as a dependency of your app and toss <demo-component list="people"></demo-component> into your markup.

Conclusion

This is obviously just scratching the surface of this approach, but hopefully it gives you an idea of the possibilities. In future posts we'll look at bundling CSS with your component, defining required, default, and optional configuration properties for your components, and weaving it all together into a larger ecosystem. In my own work I plan to spend the vast majority of my time writing components. To create applications we'll snap together some existing pieces, write a couple of new ones and a little bit of glue code, and have a flexible, modular architecture by default.

What about you? Does this sort of architecture appeal to you? Have questions about how to get started or how to build more complex components? Take a look at the example application and then reach out on Twitter or via email (ben.clinkinbeard at gmail) with any questions, comments or otherwise about this post.

I'm also curious to know what sorts of posts people would like to see going forward. I have so many different topics I am interested in right now that it's really hard to choose what to write about. More Angular? More Browserify? More atomify? If there is a subject you'd like to see me explore in a future post let me know!