Rails asset pipeline vs Phoenix and Brunch
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:
- Run
npm install --save jquery
- Add
'jquery'
tonpm.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:
- use copy plugin like copycat-brunch
- rely on Brunch's support for Bower as discussed on Stack Overflow
- directly point Brunch to specific package like I did with Font Awesome
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.