Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Taking Rails beyond the asset pipeline (Worksho...
Search
Alex Coles
December 06, 2016
Technology
89
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Taking Rails beyond the asset pipeline (Workshop at RubyDay Italia)
Alex Coles
December 06, 2016
More Decks by Alex Coles
See All by Alex Coles
How a language reflects its people (Brighton Ruby)
myabc
0
120
How a language reflects its people
myabc
0
100
Rails: beyond the asset pipeline (RubyC)
myabc
0
150
Frontend Choices (Tropical Ruby)
myabc
1
800
Frontend Choices (RubyConf Portugal)
myabc
1
480
Frontend Choices
myabc
0
69
Frontend Choices
myabc
0
310
Putting the Hype back in Hypermedia
myabc
1
250
DataMapper
myabc
2
240
Other Decks in Technology
See All in Technology
SRE歴2ヶ月でも開発6年の知見を活かして、チームで止まっていた環境改善を前に進めた話
a_ono
0
140
AWS Security Hub CSPMの成功・失敗体験
cmusudakeisuke
0
610
AI時代における最適なQA組織の作り方
ymty
3
260
徹底討論!ECS vs EKS!
daitak
3
1.8k
打造你的 AI 工作流:Agent Skill + MCP 實戰工作坊
appleboy
0
240
Why is RC4 still being used?
tamaiyutaro
0
250
デジタル・デザイン:次の50年を描く「進化する青写真」
y150saya
0
590
PostgreSQL 19 新機能概要 OSC Hokkaido 2026
nori_shinoda
0
260
週末にループ・エンジニアリングの理解を深めるためのスライド
nagatsu
0
690
4人目のSREはAgent
tanimuyk
0
310
組織における AI-DLC 実践
askul
0
220
きのこカンファレンス2026_肩書きを外したとき私は誰か
yamasatimi
1
110
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.3k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.1k
The Cult of Friendly URLs
andyhume
79
6.9k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
420
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
210
Documentation Writing (for coders)
carmenintech
77
5.4k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
400
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.2k
WCS-LA-2024
lcolladotor
0
660
Transcript
Taking Rails beyond the asset pipeline a workshop RubyDay Italia,
Firenze | Novembre 2016
Benvenuto
prima di iniziare
Pre-requisites recent Ruby (2.2+) recent Node (6.9.1+) an existing Rails
app (4.2/5.0) – or example app
Node on macOS brew update brew install yarn
Node on Windows & Linux https://yarnpkg.com/en/docs/install
Frontend has changed
asana
typecast
blocs
So how can Rails keep up?
psst… ditch the asset pipeline
buon pomeriggio RubyDay Italia!
About me @myabc github.com/myabc alexbcoles.com
where I work
what I work on
31 August 2011 Ciao Rails 3.1!
gem wrappers
$ gem list --remote jquery | wc -l 349
Bower
1. gem Using an integration like or gem bower-rails bower
gem install bower-rails source 'https://rubygems.org' gem 'bower-rails'
2. Load path config.assets.paths << File.join(Rails.root, 'bower_components')
3. rails-assets.org source 'https://rubygems.org' gem 'rails' source 'https://rails-assets.org' do gem
'rails-assets-bootstrap' gem 'rails-assets-angular' gem 'rails-assets-leaflet' end
Bower only solves dependency management
Things you might need Dependency management Pre and post-processing Code
loading Code bundling Tree shaking
Sprockets plugins alexspeller/non-stupid-digest-assets
Sprockets plugins Post-processing JS/CSS uses PostCSS project autopre xer uses
(formerly 6to5), requires Sprockets 3 ai/autopre xer-rails TannerRogalsky/sprockets-es6 Babel
Problem with Sprockets No standard plugin con guration style Cannot
control pre/post-processing order Asset dependencies
Things you might need Dependency management Pre and post-processing Code
loading Code bundling
Webpack
Webpack configuration + entry point // webpack.config.js module.exports = {
context: __dirname + '/app', entry: 'rubydayit-app.js', output: { filename: '[name].js', path: path.join(__dirname, '..', 'app', 'assets', 'javascripts', 'bundles'), publicPath: '/assets/bundles' } }
Requiring JS single files and dependencies require('./another-file'); //= require ./another-file
(Sprockets) var angular = require('angular'); var jQuery = require('jquery'); require('jquery-ui');
Requiring JS a tree var requireTemplate = require.context('./app/controllers', true, /\.js$/);
requireTemplate.keys().forEach(requireTemplate); //= require_tree ./app/controllers (Sprockets)
Requiring assets require('jquery-ui/ui/jquery-ui'); // .js (default) require('jquery-ui/themes/base/jquery.ui.core.css'); require('jquery-ui/themes/base/jquery.ui.datepicker.css'); require('select2/select2'); //
.js (default) require('select2/select2.css');
Requiring assets quick start require('jquery-ui/ui/jquery-ui'); // .js (default) require('!style-loader!css-loader!jquery-ui/themes/base/jquery.ui.core.css'); require('!style-loader!css-loader!jquery-ui/themes/base/jquery.ui.datepicker.css');
Requiring assets with a bit of config // webpack.config.js module.exports
= { context: __dirname + '/app', entry: 'rubydayit-app.js', module: { loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.png$/, loader: 'url-loader?limit=100000&mimetype=image/png' }, { test: /\.gif$/, loader: 'file-loader' }, { test: /\.jpg$/, loader: 'file-loader' } ]} } require('jquery-ui/ui/jquery-ui'); // .js (default) require('jquery-ui/themes/base/jquery.ui.core.css'); require('jquery-ui/themes/base/jquery.ui.datepicker.css');
Requiring assets body { background: url(/assets/bundles/background-texture.jpg) } /* border-image: url(border-image.png);
*/ .box { border-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAA…'); }
Loaders and plugins Webpack is built on the concept of
loaders and plugins
Loaders
Loaders Loaders are transformations that are applied on les. They
preprocess les. I. e. they can transform Co eeScript to JavaScript.
Chaining Loaders eslint ← co ee json ← yaml style
← postcss ← css ← sass ngtemplate-loader ← markdown
Requiring Rails- style translation files $ yarn add --dev json-loader
yaml-loader I18n.translations = I18n.translations || {}; I18n.translations.en = require('!json!yaml!config/locales/en_US.yml').en; I18n.translations.de = require('!json!yaml!config/locales/en_DE.yml').de;
Transpiling (ES6 → ES5) $ yarn add --dev babel-loader module:
{ loaders: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'} ] }
Transpiling (ES6 → ES5) // app-defaults.js export default { favouriteConf:
'RubyDay Italia' }; // app.js import appDefaults from './app-defaults.js'; class ExampleApp { constructor() { console.log(appDefaults.favouriteConf); } } export default ExampleApp;
Legacy code support $ yarn add --dev exports-loader module: {
loaders: [ { test: /[\/]angular\.js$/, loader: 'exports?angular' } ] }
One more thing…
http://xkcd.com/303/
Hot reloading
Hot reloading colektivo/song-song-song gaearon/react-hot-loader
Instructions Building a vanilla Rails 5 application
Generate a new Rails app rails new TimeTracker git init
and git commit after each step.
Generate Rails scaffolding
Project ./bin/rails generate scaffold Project name:string:required colour:string TimeEntry ./bin/rails generate
scaffold TimeEntry project:references begin_at:datetime end_at:datetime note ./bin/rake db:migrate
Add materialize-sass and spruce up the application
Example application https://github.com/myabc/webpack-rails-rubydayit
Transforming the application with Webpack 2.0
Webpack 2 yarn add --dev
[email protected]
In webpack.config.js const webpack
= require('webpack'); const path = require('path'); module.exports = { entry: './app/assets/javascripts/application.js', output: { filename: 'application.js', path: path.join(__dirname, 'public', 'javascripts') } }
Babel yarn add --dev babel-loader babel-core yarn add --dev babel-preset-es2015
module.exports = { // ... module: { loaders: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['es2015'] } } ] } }
Sass/CSS Support yarn add --dev sass-loader css-loader node-sass yarn add
--dev
[email protected]
const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { // ... module: { loaders: [ // ... { test: /\.scss$/, loader: ExtractTextPlugin.extract({loader: "css-loader!sass-loader"}) } ] }, plugins: [ new ExtractTextPlugin("../stylesheets/application.css") ] }
jQuery yarn add --dev jquery yarn add --dev expose-loader module.exports
= { // ... module: { loaders: [ { test: require.resolve("jquery"), loader: "expose-loader?$!expose-loader?jQuery" } ] } }
Materialize Framework yarn add --dev materialize-css
Rails libraries (asset pipeline analogues) yarn add --dev jquery-ujs yarn
add --dev turbolinks
Adapt application.js //= require jquery import jQuery from 'jquery'; //=
require jquery_ujs import 'jquery-ujs'; //= require turbolinks import Turbolinks from 'turbolinks'; Turbolinks.start(); //= require materialize-sprockets import 'materialize-css'; import './../stylesheets/application.scss';
Adapt application.css -@import "materialize/components/color"; +@import "~materialize-css/sass/components/color"; $primary-color: #5d4ca0 !default; $secondary-color:
#38d59c !default; -@import "materialize" +$roboto-font-path: "~materialize-css/fonts/roboto/"; +@import "~materialize-css/sass/materialize"; module.exports = { // ... module: { loaders: [ { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader" }, { test: /\.(woff|woff2)$/, loader: "url-loader?prefix=font/&limit=5000" { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url-loader?limit=10000&mimetype=application/ { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url-loader?limit=10000&mimetype=image/svg+xm ] } }
Run yarn run webpack
Integrate with Rails rake webpack – or – rake assets:precompile
Foreman gem install foreman foreman start # Procfile rails: bundle
exec rails server -e ${RAILS_ENV:="development"} -p 3000 webpack: yarn webpack -- --watch --progress
Disabling the Rails asset pipeline
in a new app rails new app --skip-sprockets rails new
app --skip-javascript --skip-turbolinks --skip-action-cable
in an existing app # config/application.rb -require 'rails/all' +require 'rails'
+require 'active_model/railtie' +require 'active_job/railtie' +require 'active_record/railtie' +require 'action_controller/railtie' +require 'action_mailer/railtie' +require 'action_view/railtie' +require 'action_cable/engine' +require 'rails/test_unit/railtie' - config.assets.debug = true - config.assets.quiet = true rm config/initializers/assets.rb
Rails integration /// manifest-84b43dda218a2c29ce11f4f7b9ca4e5f.json { "assets": { "1downarrow.png": "1downarrow-d2055955ce2927de07f2e33abdbfdc1b.png", "1uparrow.png":
"1uparrow-a4eef1942dd999e6a16e84c1c8122b8a.png", "2downarrow.png": "2downarrow-e8bc5b59fa922f68637dc22b4a467f5c.png" } }
Rails integration # app/helpers/application_helper.rb def webpack_bundle_tag(bundle) src = if Rails.configuration.webpack[:use_manifest]
manifest = Rails.configuration.webpack[:asset_manifest] filename = manifest[bundle] "#{compute_asset_host}/assets/#{filename}" else "#{compute_asset_host}/assets/#{bundle}-bundle" end javascript_include_tag(src) end http://clarkdave.net/2015/01/how-to-use-webpack-with-rails/
Conclusion
Grazie!
Domande?