Finally we decided to embrace the latest JavaScript improvements and use EcmaScript 6 on all new applications. First, we started applying it to Tracker (view source code on Github). Rails ecosystem provides Webpacker, a gem that allows packing assets using modern tools like yarn
and writing the latest flavour of JavaScript via Babel.
Tracker runs on Ruby on Rails 5.2.0.beta2 at the moment, and I'd like to list here the steps we took to install Webpacker.
Installation
Firstly we add webpacker gem to Gemfile:
# Gemfile
gem 'webpacker', '~> 3.3'
then we install it in the app:
Folder structure
There seem to be variances on folder structure among implementers, here's our own:
Stylesheets
The app/javascript/application.js
links all assets in both JavaScript and stylesheets. For stylesheets we'll use a manifest file, where we import all our stylesheets:
// app/javascript/stylesheets/application.scss
@import 'layout';
Then we import that file in our JavaScript manifest:
// app/javascript/packs/application.js
import '../stylesheets/application'
We need to add the new manifests to out layout file, app/views/layout/application.html.erb
:
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
Here we replaced the stylesheet_link_tag
and javascript_include_tag
helpers with the new stylesheet_pack_tag
and javascript_pack_tag
respectively. This replaces the asset pipeline with Webpack. If we run the app now, we should be able to see assets served by Webpack.
Webpacker notices when we change our assets, and compiles them when we refresh the page. This may take slightly longer that to what we are used to. To avoid, we tend to run bin/webpack-dev-server
on another console tab, which watches for changes, compiles the files automatically and also refreshes the web page, so we don't have to.
Bootstrap
Now we install some common front-end libraries. The best way to do this is to use yarn
:
Yarn install Bootstrap, jQuery and Popper, needed by Bootstrap to run. We need to add them as plugins too:
// config/webpack/environment.js
const webpack = require('webpack')
environment.plugins.append(
'Provide',
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default']
})
)
We then import them:
// app/javascript/packs/application.js
import 'jquery'
import 'bootstrap'
On the stylesheet side, we just add the parts of Bootstrap we need to a bootstrap_custom
file:
// app/javascript/stylesheets/bootstrap_custom.scss
@import 'bootstrap/functions';
@import 'bootstrap/variables';
@import 'bootstrap/mixins';
@import 'bootstrap/root';
@import 'bootstrap/reboot';
@import 'bootstrap/type';
// @import 'bootstrap/images';
// @import 'bootstrap/code';
@import 'bootstrap/grid';
// @import 'bootstrap/tables';
@import 'bootstrap/forms';
@import 'bootstrap/buttons';
@import 'bootstrap/transitions';
@import 'bootstrap/dropdown';
// @import 'bootstrap/button-group';
// @import 'bootstrap/input-group';
// @import 'bootstrap/custom-forms';
@import 'bootstrap/nav';
@import 'bootstrap/navbar';
@import 'bootstrap/card';
// @import 'bootstrap/breadcrumb';
// @import 'bootstrap/pagination';
@import 'bootstrap/badge';
// @import 'bootstrap/jumbotron';
@import 'bootstrap/alert';
// @import 'bootstrap/progress';
// @import 'bootstrap/media';
@import 'bootstrap/list-group';
@import 'bootstrap/close';
@import 'bootstrap/modal';
@import 'bootstrap/tooltip';
// @import 'bootstrap/popover';
// @import 'bootstrap/carousel';
@import 'bootstrap/utilities';
@import 'bootstrap/print';
and add that to the application.scss
manifest:
// app/javascript/stylesheets/application.scss
@import 'bootstrap_custom';
@import 'layout';
Images
Images are also included within the application.scss
:
// app/javascripts/packs/application.js
require.context('../images/', true, /\.(gif|jpg|png|svg|eot|ttf|woff|woff2)$/i)
Fonts
Font files are added to the app/javascripts/images/fonts
folder. In Tracker, we use Montserrat so we link them to the stylesheet:
// app/javascripts/stylesheets/fonts.scss
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-regular.eot"); /* IE9 Compat Modes */
src: local('Montserrat Regular'), local('Montserrat-Regular'),
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-regular.eot?#iefix") format('embedded-opentype'), /* IE6-IE8 */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-regular.woff2") format('woff2'), /* Super Modern Browsers */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-regular.woff") format('woff'), /* Modern Browsers */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-regular.ttf") format('truetype'), /* Safari, Android, iOS */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-regular.svg#Montserrat") format('svg'); /* Legacy iOS */
}
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 700;
src: url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-700.eot"); /* IE9 Compat Modes */
src: local('Montserrat Regular'), local('Montserrat-Regular'),
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-700.eot?#iefix") format('embedded-opentype'), /* IE6-IE8 */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-700.woff2") format('woff2'), /* Super Modern Browsers */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-700.woff") format('woff'), /* Modern Browsers */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-700.ttf") format('truetype'), /* Safari, Android, iOS */
url("../images/fonts/montserrat-v12-latin/montserrat-v12-latin-700.svg#Montserrat") format('svg'); /* Legacy iOS */
}
Then add the fonts file to the stylesheet manifest:
// app/javascript/stylesheets/application.scss
@import 'fonts';
Unobtrusive JS and Turbolinks
Rails comes with rails-ujs
and turbolinks
gems, which we don't need anymore and can remove from the Gemfile file. We can also remove the gem uglifier
used to parse the assets.
Since they are normal JavaScript files, we include them via yarn:
The we link them inside the manifest and start them:
// app/javascript/packs/application.js
import Rails from 'rails-ujs'
import Turbolinks from 'turbolinks'
Rails.start()
Turbolinks.start()