Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Alex Coles
December 06, 2016

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

Alex Coles

December 06, 2016
Tweet

More Decks by Alex Coles

Other Decks in Technology

Transcript

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

    gem install bower-rails source 'https://rubygems.org' gem 'bower-rails'
  2. 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
  3. 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
  4. Problem with Sprockets No standard plugin con guration style Cannot

    control pre/post-processing order Asset dependencies
  5. 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' } }
  6. Requiring JS single files and dependencies require('./another-file'); //= require ./another-file

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

    requireTemplate.keys().forEach(requireTemplate); //= require_tree ./app/controllers (Sprockets)
  8. 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');
  9. 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…'); }
  10. Loaders Loaders are transformations that are applied on les. They

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

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

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

    loaders: [ { test: /[\/]angular\.js$/, loader: 'exports?angular' } ] }
  16. 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
  17. 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') } }
  18. 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'] } } ] } }
  19. 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") ] }
  20. jQuery yarn add --dev jquery yarn add --dev expose-loader module.exports

    = { // ... module: { loaders: [ { test: require.resolve("jquery"), loader: "expose-loader?$!expose-loader?jQuery" } ] } }
  21. 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';
  22. 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 ] } }
  23. Foreman gem install foreman foreman start # Procfile rails: bundle

    exec rails server -e ${RAILS_ENV:="development"} -p 3000 webpack: yarn webpack -- --watch --progress
  24. in a new app rails new app --skip-sprockets rails new

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

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