Taking Rails beyond the asset pipeline (Workshop at RubyDay Italia)

9b1a71682de14fc6fc2b944a9c4814a0?s=47 Alex Coles
December 06, 2016

Taking Rails beyond the asset pipeline (Workshop at RubyDay Italia)

9b1a71682de14fc6fc2b944a9c4814a0?s=128

Alex Coles

December 06, 2016
Tweet

Transcript

  1. Taking Rails beyond the asset pipeline a workshop RubyDay Italia,

    Firenze | Novembre 2016
  2. Benvenuto

  3. prima di iniziare

  4. Pre-requisites recent Ruby (2.2+) recent Node (6.9.1+) an existing Rails

    app (4.2/5.0) – or example app
  5. Node on macOS brew update brew install yarn

  6. Node on Windows & Linux https://yarnpkg.com/en/docs/install

  7. Frontend has changed

  8. asana

  9. typecast

  10. blocs

  11. So how can Rails keep up?

  12. psst… ditch the asset pipeline

  13. buon pomeriggio RubyDay Italia!

  14. About me @myabc github.com/myabc alexbcoles.com

  15. where I work

  16. what I work on

  17. 31 August 2011 Ciao Rails 3.1!

  18. gem wrappers

  19. $ gem list --remote jquery | wc -l 349

  20. Bower

  21. 1. gem Using an integration like or gem bower-rails bower

    gem install bower-rails source 'https://rubygems.org' gem 'bower-rails'
  22. 2. Load path config.assets.paths << File.join(Rails.root, 'bower_components')

  23. 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
  24. Bower only solves dependency management

  25. Things you might need Dependency management Pre and post-processing Code

    loading Code bundling Tree shaking
  26. Sprockets plugins alexspeller/non-stupid-digest-assets

  27. 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
  28. Problem with Sprockets No standard plugin con guration style Cannot

    control pre/post-processing order Asset dependencies
  29. Things you might need Dependency management Pre and post-processing Code

    loading Code bundling
  30. Webpack

  31. 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' } }
  32. Requiring JS single files and dependencies require('./another-file'); //= require ./another-file

    (Sprockets) var angular = require('angular'); var jQuery = require('jquery'); require('jquery-ui');
  33. Requiring JS a tree var requireTemplate = require.context('./app/controllers', true, /\.js$/);

    requireTemplate.keys().forEach(requireTemplate); //= require_tree ./app/controllers (Sprockets)
  34. 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');
  35. 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');

  36. 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');
  37. 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…'); }
  38. Loaders and plugins Webpack is built on the concept of

    loaders and plugins
  39. Loaders

  40. Loaders Loaders are transformations that are applied on les. They

    preprocess les. I. e. they can transform Co eeScript to JavaScript.
  41. Chaining Loaders eslint ← co ee json ← yaml style

    ← postcss ← css ← sass ngtemplate-loader ← markdown
  42. 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;
  43. Transpiling (ES6 → ES5) $ yarn add --dev babel-loader module:

    { loaders: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'} ] }
  44. 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;
  45. Legacy code support $ yarn add --dev exports-loader module: {

    loaders: [ { test: /[\/]angular\.js$/, loader: 'exports?angular' } ] }
  46. One more thing…

  47. http://xkcd.com/303/

  48. Hot reloading

  49. Hot reloading colektivo/song-song-song gaearon/react-hot-loader

  50. Instructions Building a vanilla Rails 5 application

  51. Generate a new Rails app rails new TimeTracker git init

    and git commit after each step.
  52. Generate Rails scaffolding

  53. 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
  54. Add materialize-sass and spruce up the application

  55. Example application https://github.com/myabc/webpack-rails-rubydayit

  56. Transforming the application with Webpack 2.0

  57. Webpack 2 yarn add --dev webpack@2.1.0-beta.27 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') } }
  58. 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'] } } ] } }
  59. Sass/CSS Support yarn add --dev sass-loader css-loader node-sass yarn add

    --dev extract-text-webpack-plugin@2.0.0-beta.4 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") ] }
  60. jQuery yarn add --dev jquery yarn add --dev expose-loader module.exports

    = { // ... module: { loaders: [ { test: require.resolve("jquery"), loader: "expose-loader?$!expose-loader?jQuery" } ] } }
  61. Materialize Framework yarn add --dev materialize-css

  62. Rails libraries (asset pipeline analogues) yarn add --dev jquery-ujs yarn

    add --dev turbolinks
  63. 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';
  64. 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 ] } }
  65. Run yarn run webpack

  66. Integrate with Rails rake webpack – or – rake assets:precompile

  67. Foreman gem install foreman foreman start # Procfile rails: bundle

    exec rails server -e ${RAILS_ENV:="development"} -p 3000 webpack: yarn webpack -- --watch --progress
  68. Disabling the Rails asset pipeline

  69. in a new app rails new app --skip-sprockets rails new

    app --skip-javascript --skip-turbolinks --skip-action-cable
  70. 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
  71. Rails integration /// manifest-84b43dda218a2c29ce11f4f7b9ca4e5f.json { "assets": { "1downarrow.png": "1downarrow-d2055955ce2927de07f2e33abdbfdc1b.png", "1uparrow.png":

    "1uparrow-a4eef1942dd999e6a16e84c1c8122b8a.png", "2downarrow.png": "2downarrow-e8bc5b59fa922f68637dc22b4a467f5c.png" } }
  72. 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/
  73. Conclusion

  74. Grazie!

  75. Domande?