My workflow with Lineman

August 19, 2013    workflow beginners

So, we decided to create a new Angular.js application. What should we do? Integrate our application into our backend? Pick an existing seed and extend it?

Here I want to explain what is my workflow and why I go through that route.

Let’s say that we want to use Rails as a backend (I pick Rails because is what I am most comfortable with, but this applies to any backend) and our first thought could be: Great, we just need to dump our Angular stuff into the javascripts folder. Well, that is a solution that will work, but it contains some drawbacks in my opinion.

Rails’ assets pipeline is good but it can be a pain in the ass when it gets in our way. I saw some projects where you need to use .erb extension to inject ruby code in our javascript, something like this:

$routeProvider.when('/', {
	templateUrl: "<%= asset_path('templates/foo/bar.html') %>"
});

That works, but then we are coupling our Angular app with Rails and that is not good at all (and is ugly as hell). This turns really problematic if we want to use Angular-ui bootstrap in template-less mode because we would need to monkey patch the angular-ui’s javascript file to load the templates like in the last snippet.

Of course this can be solved using $templateCache but for me it sounds like a workaround because of the coupling.

The other issue I have with the assets pipeline is that even when it is powerful and easy to extend, there are not many custom tasks to facilitate our development like we have with Grunt.

On the other hand, we want to use a CSRF token and we know that we have one in our layout, so we can do something like this:

$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content');

That couples our app a little more with Rails.

The problem with this is that if we decide tomorrow that we don’t want to use Rails anymore we have to “pick” the parts of our Angular.js application from different places and then build them into another backend opinion. That implies moving our files to different folders and modifying the parts we coupled with Rails stuff to match our new backend.

I like to see this like when we buy a hosting with a free domain. Someday we decide that we want a different hosting, but our domain is “coupled” with that hosting and we need to do several things to move that domain to a new place (I was asked once to pay $100 for my domain if I left the hosting). This could be easily solved if we have our domains “decoupled” in a different place because we just need to point the DNS to a different place if we change our hosting.

The same applies to Angular. If we have our application decoupled from our backend, we can swap backends without having to touch any file or code from our Angular application.

Enters Lineman.js

An Angular application is as important as our backend, AKA a first-class web application. To achieve this we have to decouple our application from any backend opinion. For this, we are going to create our Angular application as a different and independent project. How? With Lineman.js

Lineman is a thin layer on top of Grunt which comes with a bunch of helpful tasks to aid us on our development. For those who don’t know what Grunt is, it is a task runner which provides us with a lot of tools to automate our repetitive tasks.

So, what can Lineman automate for us? Anything we want: Coffeescript compilation, Javascript linting, sass/less compilation, run our tests, concat our javascript, minify and uglify them…

The best part of it? We don’t have to do anything to get that running. Lineman is smartly configured to do all of those things by default for us, and if we need to modify something, that is easily done as well.

Since examples are better than words, let’s check an example:

First, clone this repository:

$ git clone https://github.com/davemo/lineman-angular-template.git our-application
$ cd our-application
$ npm install

Lineman itself is a generic solution for any kind of application, but there are several templates for different projects that bring custom tasks. In this case we are using a template made by my friend David Mosher which is absolutely awesome for Angular development.

If we open our project, we can see this folder:

That are the files to configure Lineman. As I said before, Lineman comes with predefined configuration, but we need to configure it for our needs. In this case, we have Lineman configured for Angular.

What extra things do we have with this template? Well, apart from the things I said before, here we have grunt-angular-templates that will cache every template we have in our application with $templateCache automagically for us, we also have grunt-ngmin that will add the inline annotation needed to be able to mangle our uglyfied javacript, and even source maps!

All of this sounds good, but having our application decoupled from the backend, how can we make a request to a backend (which we don’t have)? That is not a problem! Lineman comes with a fake backend where we can create some fake endpoints so we are able to develop our application without the need of a backend.

The fake backend is built in Express.js and looks like this:

File: /config/server.js

module.exports = {
  drawRoutes: function(app) {
    app.post('/login', function(req, res) {
      res.json({ message: 'logging in!' });
    });

    app.post('/logout', function(req, res) {
      res.json({ message: 'logging out!'});
    });

    app.get('/books', function (req, res) {
      res.json([
        {title: 'Great Expectations', author: 'Dickens'},
        {title: 'Foundation Series', author: 'Asimov'},
        {title: 'Treasure Island', author: 'Stephenson'}
      ]);
    });
  }
};

Here we see three fake endpoints that we can use in our development. This fake backend is THAT great that it even comes with pushState support (enabled by default). This configuration lies in /config/server.js.

Alright alright, you got me, but what if I have a real backend running somewhere and I want to use it instead of a fake one? That’s right, it is not a problem either. If we open config/application.js we can do something like this:

File: /config/application.js

server: {
  pushState: true,
  apiProxy: {
    enabled: true,
    port: 3000,
    prefix: 'api'
  }
}

With this we enable a proxy to a real backend and we specify that it is running at port 3000. With the prefix we forward any request that contains api to the proxy. Now if we do a request to /api/foo it will go to our real backend. Nice!

Last, we have a configuration file for our e2e tests (more on this later).

That is all for the configuration. Thanks to the amazing job of the Lineman team, we don’t need to touch almost anything to make everything work.

We also have a folder for our application itself:

The folders are self-descriptive with the exception of the pages one. Here we have our index.us page which we will use to generate our final index.html.

The best part of this is that it is not opinionated at all. Here is were you decide what project structure you want to follow. You like the angular-app way? Do it that way, the same applies for all the other seeds projects (angular-seed, ng-boilerplate, etc). If you decide to go with the angular-app way, you can delete the templates folder and configure grunt-angular-templates to look for templates in app/js/**/*.tpl.html

These templates contain some code to see how Lineman works. Do this:

$ lineman run

This will listen to any changes in our application to lint the files, compile our less, our coffee, concat our files, cache our templates… And of course, it runs the express server at port 8000. Easy as pie! We just need to clone the repository, install the npm dependencies and then run Lineman. Any changes we do in our app will be automatically processed by Grunt.

Testing with Lineman

Because we want to test our application, Lineman comes configured for testing as well. All we need to do is to create our unit tests inside the spec folder. lineman run will process our tests so the only thing remaining is just to launch our runner:

$ lineman spec

The first thing you will notice is that the runner is not Karma but Test'em. The Lineman guys decided to use Test'em and to be honest, I won’t go back to Karma. Test'em is awesome and it has an awesome CLI interface. Not only that, you can open any browser and open the URL that test'em uses to test our app in that browser. With this we can test our app in every OS X browser, Android ones, Iphone Safari, even Internet Explorer.

Ok. What about e2e testing?

For that we have a pre-configured Protractor ready for business. Protractor? Why not Karma this time? Angular team is dropping Karma in favor of Protractor so the Lineman team decided to start using Protractor here.

Deployment

That’s the easy part, you just need to do:

$ lineman build

and you will get a dist folder with the application ready for deployment. If you want to know how to deploy a Lineman application with Rails you can check this guide I wrote some time ago.

Conclusion

Our Angular applications are as important as the backends, so here we have a workflow to give them the attention they deserve. Lineman is an awesome tool packed with a lot of tasks that makes our development easy and fun. And Lineman gives much more, like continuous integration.

If you want to learn more about Lineman and this template, I recommend you to go to the Lineman homepage and Lineman angular template. On the other hand, my friend David has some awesome videos about it here (concretely the one about workflows and the one about testing, but what the heck, watch them all, they are awesome).

Well, see you in the next article.

comments powered by Disqus