Rails asset pipeline vs Phoenix and Brunch

SeriesPhoenix on Rails clock4 min read

Both Rails and Phoenix can manage and deploy assets for you. But the approaches and solutions differ greatly.

Development tools

As a NPM based tool, Brunch recognizes that modern JS is not just jQuery and browser stuff but also a wide choice of development tools. It allows dev-only JavaScript dependencies, just like in mix.deps or Gemfile, so tools like ESLint are no longer second-class citizens. This is how your package.json may look:

lang:js
"scripts": {
  "eslint": "node_modules/eslint/bin/eslint.js ."
},
"devDependencies": {
  "eslint": "^2.10.1"
}

This allows to lint the whole project with single npm run eslint command. Of course, you'll also want to create .eslintrc and perhaps .eslintignore, too.

To be fair, you may be able to get some of those tools as Rails gems, which can also be restricted to development only but only the most popular tools are available as gems plus that suffers from the same issues as any front-end gems (read below).

Development experience: reloaded

Phoenix has out-of-the-box solution for hot-reloading assets in development. This makes it a pleasure to work on front-end code and styles. And  it's something that I've also seen in Meteor and Middleman, so it's getting more and more popular across frameworks these days.

It's not just fancy. Phoenix is smart enough not to refresh the page when the only thing that changed is CSS. There are some serious reasons why this boosts productivity:

  • if you're styling a modal that only displays after a series of clicks, in Rails you'll have to refresh the page and do those clicks each time you've made a styling change
  • sometimes the refresh fails, eg. when posting some one-time forms and styling their response
  • some development servers are really slow and so every refresh may take some time

Hot reloading also plays nice with the Brunch building the assets asynchronously - you just save the CSS and wait for changes to apply. No need for bringing the development server into it. With Rails asset pipeline, the same server runs the backend responses and compiles the assets upon change. And by default it's WEBrick so it's all synchronous and just plain slow.

Concatenating files and ES6

Phoenix comes with ES6 support so you can forget about nasty comments with require and start using native JS imports which are supported by linters. Add sass-brunch or stylus-brunch to the party and you get the same in CSS, too.

Did I mention ES6? These days, it's no longer a curiosity, but a standard. And in Phoenix you get to use it from day one in your project. Here's how first lines in your app.js may look:

lang:js
import $ from 'jquery';

$(() => {
  $(document).on('click', '.alert a.close', (event) => {
    event.preventDefault();
    $(event.target).closest('.alert').remove();
  });
});

You can get Babel to work in Rails too, but according to this article, it's more of a workaround than first-class support. And that's just not good enough these days.

Front-end packages

In early days of Rails, I was amazed by how easily you could add front-end assets via gems. From jQuery or Underscore to monsters like Bootstrap, you could add it all simply by installing the gem and adding a require or two. After some years, I started to see limitations of such ecosystem. Using gems for front-end makes you dependent on the gem author when it comes to keeping up with the tool updates as well as with incompatibilities introduced by new Rails releases. 

It just can't get as good as reaching straight to the source, which there is just one these days: NPM. And this is exactly where Brunch points you to. This is how you can add jQuery to the app:

  1. Run npm install --save jquery
  2. Add 'jquery' to npm.whitelist in brunch-config.js 

Update: As of Phoenix 1.2, the default brunch-config.js was reorganized and now it doesn't include the npm.whitelist setting. Therefore, step 2 can now be safely omitted. 

That's it. It's as simple as with gems but you get to use NPM with the widest choice of front-end packages there is. Plus you can keep front-end dependencies separate from the actual server app deps so that adds up to a cleaner project structure.

With Brunch, you can also pull assets other than CSS/JS from NPM. This isn't perfect however as there isn't a single uniform way for pulling images, fonts or whatever from NPM yet. You can: 

Update: You can learn more about that in article Front-end packages with Phoenix and Brunch.

Summary

I can only see advantages of Phoenix team picking Brunch over building their own solution like Rails did. Don't get me wrong: asset pipeline did great in its early days but times have changed and now NPM is the most healthy front-end ecosystem and a way to go.

Obviously, I didn't cover all aspects of front-end differences between Rails and Phoenix,  so please leave a comment if there's something important missing in the article.