Add Webpack to Rails 5
The push to use webpack with rails is getting too much to resist! You can setup some good stuff with sprockets, but it's a pain and a lot of it doesn't seem too updated. So... to get things like good ES6 support, minification, easier script managment with Yarn, and PostCSS support; It's time for webpacker
The push to use webpack with rails is getting too much to resist!
You can setup some good stuff with sprockets, but it's a pain and a lot of it doesn't seem too updated.
So... to get things like good ES6 support, minification, easier script managment with Yarn, and PostCSS support; It's time for webpacker
Add webpack/webpacker to the app
Add to gem to Gemfile
gem 'webpacker'
then
bundle install bundle exec rails webpacker:install yarn upgrade
The default install didn't add the rails stuff, so add other packages.
yarn add @rails/actioncable @rails/activestorage @rails/ujs turbolinks
Setup JS for Rails
This is what the default files for a Rails6 install look like. I didnt' have anything changed from the default Rails5 stuff, so I just added this files.
app/javascript/channels/consumer.js
// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `rails generate channel` command.
import { createConsumer } from "@rails/actioncable"
export default createConsumer()
app/javascript/channels/index.js
// Load all the channels within this directory and all subdirectories.
// Channel files must be named *_channel.js.
const channels = require.context('.', true, /_channel\.js$/)
channels.keys().forEach(channels)
The main entry point is the the app/javascript/packs/applications.js file.
Add some polyfill and default rails scripts
// Polyfill
import "core-js/stable";
import "regenerator-runtime/runtime";
require('@rails/ujs').start()
require('turbolinks').start()
require('@rails/activestorage').start()
require('./channels')
Lastly, update the javascript_include_tag
to javascript_pack_tag
in your
layouts.
Restart your dev server and give things a try!
Move custom JS stuff over
I'm using Bootstrap on this project so added those deps.
yarn add bootstrap jquery popper.js
app/javascript/packs/application.js
import $ from 'jquery'
import popper from 'popper.js'
import bootstrap from 'bootstrap'
window.$ = window.jQuery = $
window.bootstrap = bootstrap
window.popper = popper
Use Webpack for CSS
Since we're using it for JS, might as well use it for CSS.
Set extract_css
to true
in config/webpacker.yml
I needed to add postcss-cssnext
for the default config to be happy.
And sass
for Bootstrap.
yarn add postcss-cssnext sass
Copy your current sass files over to app/javascript/css/
.
I'm also using custom fonts, so copy those over and update any font-url
calls in your sass files to url
and fix the paths.
Install FontAwesome 4.
yarn add font-awesome
app/javascript/css/application.scss
$fa-font-path: "~font-awesome/fonts";
@import "font-awesome/scss/font-awesome";
Debugging
You can the dev server to see any errors. In some cases I had to restart the dev server, puma-dev in my case. Mostly for any config changes.
bin/webpack-dev-server
Using assets only available in gems
I had one dependency that's bundled in a gem as a Rails engine. I decided to continue to use the Asset Pipeline for it. It's only used on a few pages so loading it just on those pages works great.
Add the entry files to app/assets/js/app_recurring_select.js
and app/assets/css/app_recurring_select.css
.
Add the require
code as needed to those files.
//= require recurring_select
/*
*= require recurring_select
*/
Update the precompile config in config/initializers/assets.rb
.
Rails.application.config.assets.precompile += %w[app_recurring_select.js app_recurring_select.css]
Add them to the needed pages
- content_for :js_head do
= javascript_include_tag "app_recurring_select.js", 'data-turbolinks-track': 'reload'
= stylesheet_link_tag "app_recurring_select.css", media: 'all', 'data-turbolinks-track': 'reload'
Don't name the entry point file the same as the thing you're require
'ing, like I did :p.
Cleanup
Remove the unused files from app/assets/
remove any gems you were using,
like Bootstrap
, that are now provided by Yarn.
EB config
As always, needed to customize the Eleastic Beanstalk deploy.
Install Yarn. Already had a script to install NodeJS so just added Yarn to that.
.ebextensions/install_node.config
commands:
01_node_get:
# run this command from /tmp directory
cwd: /tmp
# flag -y for no-interaction installation (visit https://rpm.nodesource.com for latest)
command: 'curl --silent --location https://rpm.nodesource.com/setup_11.x | bash -'
02_node_install:
# run this command from /tmp directory
cwd: /tmp
command: 'yum -y install nodejs'
03_yarn_package:
cwd: /tmp
command: 'curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo'
04_yarn_install:
cwd: /tmp
command: 'yum -y install yarn'
Next needed to run yarn install
so all the webpack stuff is there for assets:precompile
.
.ebextensions/yarn.config
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/09_yarn_install.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
# Using similar syntax as the appdeploy pre hooks that is managed by AWS
set -xe
EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
EB_APP_STAGING_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_staging_dir)
. $EB_SUPPORT_DIR/envvars
cd $EB_APP_STAGING_DIR
su -s /bin/bash -c 'yarn install' webapp
Lastly, needed to update Nginx so CORS works for fonts.
.ebextensions/
files:
/etc/nginx/conf.d/proxy.conf:
mode: "000644"
owner: root
group: root
content: |
upstream custom_app {
server unix:///var/run/puma/my_app.sock;
}
server {
listen 80;
server_name _ localhost; # need to listen to localhost for worker tier
root /var/app/current/public;
try_files $uri @app;
location ^~ /assets/ {
root /var/app/current/public;
gzip_static on;
expires max;
add_header Cache-Control public;
location ~* \.(ttf|ttc|otf|eot|woff|woff2|svg|font.css)$ {
add_header Access-Control-Allow-Origin *;
}
}
location ^~ /packs/ {
root /var/app/current/public;
gzip_static on;
expires max;
add_header Cache-Control public;
location ~* \.(ttf|ttc|otf|eot|woff|woff2|svg|font.css)$ {
add_header Access-Control-Allow-Origin *;
}
}
location @app {
proxy_pass http://custom_app;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
container_commands:
reloadnginx:
command: "/etc/init.d/nginx reload"
Lastly, since I updated Nginx after testing the fonts, I had to invalid
/packs/media/fonts/*
in the AWS console to get them reloaded correcly in the
CDN.
References
Webmentions
These are webmentions via the IndieWeb and webmention.io. Mention this post from your site: