Four Key Reasons to Learn Markdown
Back-End Leveling UpWriting documentation is fun—really, really fun. I know some engineers may disagree with me, but as a technical writer, creating quality documentation that will...
TL;DR: Don’t manage vendor assets with Rails gems; use Bower and NPM. Check out the gist for quick reference.
So you’ve knocked out a few epics in Pivotal Tracker and have an MVP ready for Heroku, when your project manager announces that the Bootstrap-based frontend and choice of colors will likely turn off investors.
To mitigate your “button-and-text soup,” a graphic designer and frontend developer are brought on. Your beautifully simple Rails app is clobbered with masses of minified JavaScript and Convoluted Style Sheets, and your slim
templates are littered with classes and data attributes.
While you aren’t enthusiastic about gutting your clever Bootstrap forms to make way for some unheard of grid system (which doesn’t even have buttons), you acquiesce in hopes of a year-end bonus for your admirable cooperation. That is, until the frontend developer commits a mass of unreadable, minified JavaScript to public
.
Naturally, you advocate for Rails’ asset pipeline. When jquery-2.1.0.min.js
is chucked under app/assets/javascripts
, you set folks straight and tell them that only code written specifically for the app, not vendor code, belongs there. Next pull request, you find those assets have been moved to lib/assets
, which is a definite no-go.
To bypass further confusion, you kindly alert your cohorts that jquery
is bundled in the Gemfile, and in fact the tooltip library that was committed to lib/assets/javascripts
is part of the jquery-ui-bootstrap-rails
gem. The gem integrates with the asset pipeline, and will be far more elegant than copy-pasting an unversioned .min.js
to random directories.
Your unenlightened cohorts, in a moment of disgust, declare that they will be adding frontend tooling, such as NPM, to the pipeline for asset vendoring.
“Frontend tooling?” Don’t frontend developers just stick minified junk in a directory? After all, Rubyists know JavaScript as the class-deprived single-file language of popups and scrolling marquees. It is the veritable poster child for languages bereft of module managers and plagued by global scope.
Although we are loath to admit it, Rails developers have an infamous reputation among the web community. turbolinks
was perhaps the most ironic blow to the face of client-side programming, but day-to-day Rails developers have a habit of littering templates with copious IDs and div
s in an effort to appease their leaky JavaScript files.
When it comes to vendor assets, the web community shrieks at this increasingly common style of Gemfiles:
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'jquery-rails'
gem 'remotipart'
gem 'jquery-ui-rails'
gem 'jquery-ui-bootstrap-rails'
gem 'bootstrap-sass'
gem 'bootstrap-datepicker-rails'
gem 'pagedown-bootstrap-rails'
gem 'font-awesome-sass-rails'
gem 'chosen-rails'
In light of our shadowy past, what tools and workflows can we adopt to leverage conventions in both platforms while maximizing developer happiness?
While perusing your Twitter feed, you read a tweet about Bower. Okay! You add gem "bower-rails"
to your Gemfile to suppressed shouts of joy from your frontend cohort, who dives in to add normalize.css and a clean grid system, only to find there is no bower.json
file in the project. Confuzzled, your cohort searches the directory tree and stumbles upon the empty and extensionless Bowerfile
.
Distressed, your cohort decides to create a bower.json
configuration from scratch, then runs bower install
. However, Rails doesn’t seem to know anything about bower_components
.
In the midst of your colleague trampling your beautiful Bower-ified Rails setup, you come across some interesting configuration options in config/application.rb
while looking for a way to add app/assets/fonts
to the asset pipeline. As always in Rails, you find it’s as simple as:
config.assets.paths << Rails.root.join("app","assets","fonts")
On the call, your frontend cohort says your Bower setup is “unconventional” and represents a mixup of responsibilities. Managing a Bowerfile
to generate a bower.json
is the epitome of irony: who ever heard of a Ruby DSL being used to generate JavaScript?
Your cohort has already stripped out bower-rails
on a private branch and is able to install all components, but doesn’t know where to dump them for Rails’ asset pipeline. Despite your offense, you are struck with an epiphany: why can’t the bower_components
directory just be added to config.assets.paths
?
As the best developers are strongly opinionated, you say that bower_components
is a nonsensical place to put assets, as Rails has a directory for just such a purpose: vendor/assets
. However, Bower won’t unpackage JavaScript and CSS files into separate directories. As a compromise, you decide to install Bower packages under vendor/assets/components
and add it to the asset pipeline:
config.assets.paths << Rails.root.join("vendor","assets","components")
Delighted, your cohort quickly adds a .bowerrc
to tell Bower exactly where to dump these packages on any subsequent bower install
:
{
"directory": "vendor/assets/components"
}
Over the lunch break, the Gemfile has been stripped of gems even remotely related to assets, even gem "jquery-rails"
(incredibly, you discover there is a nice Bower package with the pertinent rails-ujs
file you still need for remote: true
links, and your cohort is only too eager to take control of the jquery
version from bower.json
).
Satisfied with the pleasant compromise (and simultaneously relieved to relinquish responsibility of frontend assets), you merge your cohort’s lengthy pull-request (primarily subtractions) and deploy master
to Heroku before heading to the kitchen for a few sticks of string cheese.
To your chagrin, the deployment failed: during the asset compilation step, it complained that it couldn’t find jquery
. Of course, you forgot to commit the files in vendor/assets/components
; but you certainly don’t want to pollute Git history with millions of vendor additions. Obviously, Heroku ought to run bower install
to grab the assets before compilation. But how?
Another pal suggests you look into custom buildpacks, an interesting Heroku feature that lets you bypass the language auto-detection normally used to compile apps. With some investigation, you find you can instruct Heroku to compile first as a Node.js app, then finish compilation as a Rails app with the buildpack-multi. It’s as simple as adding a .buildpacks
file:
https://github.com/heroku/heroku-buildpack-nodejs
https://github.com/heroku/heroku-buildpack-ruby
After a couple attempts (the first time, you forgot to pluralize .buildpacks
), it seems the file is ignored. A quick search, and you quickly update your BUILDPACK_URL
:
heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git
Just before you hit return, your smartphone buzzes with an email from Heroku: multi-buildpacks are now officially supported on their own fork, so you update the BUILDPACK_URL
again:
heroku config:add BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-multi.git
It seems that Node.js apps expect a package.json
manifest, but what for? Your cohort reminds you that Bower is itself an NPM package, so you should install and run it as part of the build process:
{
"name": "my-app",
"devDependencies": {
"bower": "latest"
},
"scripts": {
"postinstall": "./node_modules/bower/bin/bower install"
}
}
On your last stick of string cheese, the deploy completes successfully with no apparent changes to your site. You and your cohort are so pleased, you decide to present it to your coworkers as a Tech Talk.
Want the Cliff notes version? I’ve compiled the additions into a gist.
Do you have other patterns or tools you find enhance collaboration between frontend and backend?
Writing documentation is fun—really, really fun. I know some engineers may disagree with me, but as a technical writer, creating quality documentation that will...
Humanity has come a long way in its technological journey. We have reached the cusp of an age in which the concepts we have...
Go 1.18 has finally landed, and with it comes its own flavor of generics. In a previous post, we went over the accepted proposal and dove...