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

The Rails 6 Front End: Building with Webpacker and Stimulus

The Rails 6 Front End: Building with Webpacker and Stimulus

Sometimes you need to have something happen in the browser. You don’t need a Single Page App, but you do want some client-side interactions. Rails 6 has great tools for simplifying the complex JavaScript ecosystem. We’ve got Webpacker, the default asset pipeline for JavaScript tooling, and Stimulus, a small library from Basecamp that brings Rails convention over configuration to JavaScript tools. As a result, it’s easier than ever to build user interactions with Rails-friendly tools. In this hands-on workshop, you’ll take a simple Rails app, and use Webpacker and Stimulus to add some front-end flair. No prior knowledge of Webpack or Stimulus is required.

6b767d8a4c9910e007c122d81eb4de73?s=128

Noel Rappin

April 29, 2019
Tweet

Transcript

  1. Let's make sure everybody is on board 1. https://github.com/noelrappin/rails_conf_north_by 2.

    bundle install 3. yarn install 4. rails server -> http://localhost:3000/schedule 5. The toggle buttons should not work 6. http://bit.ly/workshop_snippets Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  2. Rails 6, Webpacker, and Stimulus Noel Rappin (@noelrap) http://www.tablexi.com http://techdoneright.io

    http://www.noelrappin.com Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  3. We are going to • Walk-through adding a stimulus feature

    • talk about webpack and webpacker • see where we are on time • work together to add more stimulus code Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  4. Some ground rules: Noel Rappin | Rails 6, Webpacker, and

    Stimulus | RailsConf 2019 | @noelrap
  5. Feel free to ask questions Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  6. Pair... if you are comfortable doing so Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  7. Everybody knows that the best way to learn is under

    intense, life- threatening pressure! Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  8. We have a Rails app Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  9. We want to improve the user experience Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  10. But we don't need a single page app Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  11. There are a lot of Questions Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  12. Logistics: How to convert our code into something nice that

    we can send to the browser Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  13. Webpack(er) Noel Rappin | Rails 6, Webpacker, and Stimulus |

    RailsConf 2019 | @noelrap
  14. Structure: What's a good structure for non- SPA JavaScript interactions

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  15. Stimulus Noel Rappin | Rails 6, Webpacker, and Stimulus |

    RailsConf 2019 | @noelrap
  16. "A Modest JavaScript Framework for the HTML you already have"

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  17. Stimulus has four basic concepts Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  18. Controllers Actions Targets Data Maps Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  19. Controllers Noel Rappin | Rails 6, Webpacker, and Stimulus |

    RailsConf 2019 | @noelrap
  20. A controller is where Stimulus code is executed Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  21. A controller is associated with an HTML Element Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  22. The controller is active across that element and its children

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  23. Let's create a controller! Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  24. All the stuff to enter in this section is in

    http://bit.ly/ workshop_snippets Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  25. app/views/schedule/ show.html.erb:29-30 <section class="day-body" id="day-body-<%= schedule_day.day.by_example("2006-01-02") %>" data-controller="toggle"> Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  26. The code for the controller exists in app/javascript/ controllers/ toggle_controller.js

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  27. import { Controller } from "stimulus" export default class extends

    Controller { connect() { console.log("The Controller is Connected") } } Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  28. Reload the page Noel Rappin | Rails 6, Webpacker, and

    Stimulus | RailsConf 2019 | @noelrap
  29. You'll see in the log [Webpacker] Compiling… Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  30. And the message in the console Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  31. An element can have multiple controllers Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  32. A controller can be instantiated multiple times Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  33. Action Noel Rappin | Rails 6, Webpacker, and Stimulus |

    RailsConf 2019 | @noelrap
  34. Actions are associated with an HTML element Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  35. app/views/schedule/ show.html.erb:34 <div class="button is-primary" data-action="click->toggle#toggle"> Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  36. app/javascript/controllers/ toggle_controller.rb toggle() { console.log("click") } Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  37. An action associates an arbitrary event to a controller method

    event->controller#method Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  38. When the event happens, Stimulus dispatches to the controller method

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  39. The HTML element must be within the controller being referenced

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  40. Target Noel Rappin | Rails 6, Webpacker, and Stimulus |

    RailsConf 2019 | @noelrap
  41. A Target is an HTML element of interest to a

    controller Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  42. Targets are associated with an HTML element Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  43. app/views/schedule/ show.html.erb:39 <section data-target="toggle.thingToHide"> Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  44. And then are registered with the controller: static targets =

    ["thingToHide"] Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  45. Targets make it easy to look up elements of interest

    You get: • this.thingToHideTarget • this.thingToHideTargets • this.hasThingToHideTarget Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  46. Let's update our action Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  47. toggle() { this.thingToHideTarget.classList.toggle("is-hidden") } Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  48. Data Map Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  49. A Data Map allows you to associate data with a

    controller Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  50. app/views/schedule/ show.html.haml <section class="day-body" id="day-body-<%= schedule_day.day.by_example("2006-01-02") %>" data-controller="toggle" data-toggle-hidden="false"> Noel

    Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  51. Data maps belong to the controller data-controllername-key • get(key) •

    has(key) • set(key, stringValue) • delete(key) Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  52. If we add another target: <span data-target="toggle.text">Hide</span> Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  53. We can glue it all together Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  54. import { Controller } from "stimulus" export default class extends

    Controller { static targets = ["text", "thingToHide"] hidden() { return this.data.get("hidden") === "true" } flip() { this.data.set("hidden", this.hidden() ? "false" : "true") } toggle() { this.flip() this.thingToHideTarget.classList.toggle("is-hidden", this.isHidden()) this.textTarget.innerText = this.isHidden() ? "Show" : "Hide" } } Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  55. Stimulus Cheatsheet Item Attribute Value Naming Controller data-controller controller-name Action

    data-action event->controller- name#methodName Target data-target controller- name.targetName Data Map data-controller-name- attribute value as string Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  56. How does this all work? Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  57. At compile, webpack loads all controllers import { Application }

    from "stimulus" import { definitionsFromContext } from "stimulus/webpack-helpers" const application = Application.start() const context = require.context("controllers", true, /_controller\.js$/) application.load(definitionsFromContext(context)) Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  58. On page load, Stimulus detects the data-controller attributes and instantiates

    new controller instances. Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  59. Stimulus also finds all the actions and sets up event

    listeners Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  60. When the event is triggered, the stimulus listener sends control

    to the method. Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  61. In the method, Stimulus generates the data and target properties

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  62. Why Stimulus? Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  63. Low Overhead Easy to follow Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  64. Removes a lot of boilerplate event listeners Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  65. Makes it easy to write small modular effects Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  66. Great at handling dynamic changes to the page. Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  67. Why not Stimulus? Noel Rappin | Rails 6, Webpacker, and

    Stimulus | RailsConf 2019 | @noelrap
  68. No support for router/ SPA Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  69. Not super-helpful if there's a lot of state, or controlled

    access to state. Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  70. Let's talk about: Webpack and Webpacker Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  71. When executing our code: Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  72. Our code knew how to find other modules via include

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  73. The browser got all of our individual files in one

    pack Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  74. Our changes were automatically compiled on page reload. Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  75. Webpack Webpacker Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  76. Webpack's mission in life: Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  77. "At its core, webpack is a static module bundler for

    modern JavaScript applications. Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  78. Entry Output Loaders / Plugins Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  79. Entry: A file. Often JavaScript. Usually referencing other files in

    use. Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  80. Webpack uses entry points to build a "dependency graph" Noel

    Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  81. Output: where the bundle ends up Often the code is

    turned into a single file. Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  82. Loaders: transform files add them the graph Noel Rappin |

    Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  83. For Example: TypeScript compiler CSS Loader File loader Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  84. Webpacker's mission in life Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  85. "Webpack is really complicated" Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  86. Webpacker provides Useful defaults Makes some behavior easier to override

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  87. Webpacker is the default for new Rails 6 apps Noel

    Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  88. rails webpacker:install Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  89. It has default configs for • Angular • Coffeescript •

    Elm • Erb Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  90. It has default configs for • React • Stimulus •

    TypeScript • Vue Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  91. Important files: Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  92. package.json /node_modules Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  93. config/webpacker.yml config/webpack/ Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  94. babel.config.js postcss.config.js Noel Rappin | Rails 6, Webpacker, and Stimulus

    | RailsConf 2019 | @noelrap
  95. What are the defaults? Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  96. Any file in application/ javascript/packs is considered an entry point

    for a pack Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  97. Using javascript_pack_tag or stylesheet_pack_tag adds the pack to a page

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  98. Program note: If you have both JS and CSS in

    the same pack, import them both in the same .js file, and use both javascript_pack_tag and stylesheet_pack_tag to load them Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  99. Rails automatically compiles when you hit a page in development

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  100. Or you can use webpack-dev-server Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  101. Which compiles on change Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  102. And live reloads Noel Rappin | Rails 6, Webpacker, and

    Stimulus | RailsConf 2019 | @noelrap
  103. Hands-On Noel Rappin | Rails 6, Webpacker, and Stimulus |

    RailsConf 2019 | @noelrap
  104. Let's build a different date filter Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  105. If no dates have been clicked, all dates show If

    any dates have been clicked, only clicked dates show Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  106. What do we need? Noel Rappin | Rails 6, Webpacker,

    and Stimulus | RailsConf 2019 | @noelrap
  107. • Controller • Action for each date • Action for

    show all • Targets for each date body • Data for current state Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  108. put the controller in the HTML Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  109. Add the targets and starting data Noel Rappin | Rails

    6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  110. Add the action Noel Rappin | Rails 6, Webpacker, and

    Stimulus | RailsConf 2019 | @noelrap
  111. Add the show all action Noel Rappin | Rails 6,

    Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  112. Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf

    2019 | @noelrap
  113. Takeaways Noel Rappin | Rails 6, Webpacker, and Stimulus |

    RailsConf 2019 | @noelrap
  114. Webpack and Webpacker are there to help you write your

    code the way you want... Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  115. And deliver it to the browser as needed Noel Rappin

    | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  116. Stimulus is great for small JS interactions that aren't SPA

    worthy Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap
  117. Noel Rappin (@noelrap) http://pragprog.com/book/nrtest3 (20% off with RailsConf2019_Rappin) http://stickynote.game http://techdoneright.io/46

    Noel Rappin | Rails 6, Webpacker, and Stimulus | RailsConf 2019 | @noelrap