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

Turbolinks: battery-included SPA for Rails

Turbolinks: battery-included SPA for Rails

Muhammad Mufid Afif

March 17, 2017
Tweet

More Decks by Muhammad Mufid Afif

Other Decks in Programming

Transcript

  1. ME • Rubying since 2012, but working with it profesionally

    since 2015 • Previously uses Java (Spring and Play) and C# (Xamarin.Android). And now, Ruby + Rails.
  2. OUTLINE • Rails Modularity: Where is theTL? • TL in

    a nutshell and browser performance • HowTL works • Usage and Caveats
  3. • One of the most “interesting” Ruby and Rails Philosophy

    • More is better. • Array#first or Array[0]? Up to you! • alias_method everywhere! • Trivia: other platform/framework discourage duplication because it is confusing. • Ruby and Rails encourage aliasing because, well, without it, it is confusing!
  4. Having more choice is good! Aspect Rails way Alternatives DB

    ActiveRecord Sequel Views ERB, Jbuilder HAMLIT, JB Cache Backbone Memcached Redis Testing MiniTest Rspec JS “Framework” Turbolinks Ember, React, Vue *via Sprockets
  5. Who use jQuery in 2017? Why not migrating to React.js

    or Ember? Isn’t this is the year of SPA?
  6. Tl;dr: Your use case may be unique, don’t force yourself

    into a framework Well, as you can see in previous Table, the choice is yours. Most default things in Rails can be replaced.
  7. TURBOLINKS * Note: olderTurbolinks version has dependency to jQuery, but

    it has been being stand-alone since years ago • No dependency to any Javascript framework! • Bring SPA-responsiveness to standard Rails application (Thanks toTurbolinks Preview and History Navigation) • Changing DOM • Less browser requests, less 304 Not Modified. That means faster response! • It is included in Rails. You may remove it, but you can also use it. Up to the devs.
  8. UNDERSTANDING BROWSER REQUEST AND 304 RESPONSE • 304 Not Modified

    may be sent if: • If-Modified-Since was the same with server’s version • ETag hash is the same with server’s version • But the request still happens... Even if the response’s body is 0 bytes. • Slower request!
  9. • Avatars got 304 (Even if it had the same

    fingerprint!) • JS and CSS got 304
  10. Ура! *cheering in Russian • Trivia: Adding DOM with same

    locator (URL) won’t download it twice. • Avatars wasn’t downloaded • JS and CSS wasn’t downloaded
  11. * Version: Turbolinks 5.0.0 HTML has been loaded Inject “click”

    event on parent element, with event capturing and bubbling 1. ANCHOR INJECTION Normal navigation will be replaced with Turbolinks’ Visit
  12. * Version: Turbolinks 5.0.0 DOMContentLoaded Inject “event” via document.addEventListener(‘click’) 1.

    ANCHOR INJECTION Normal navigation will be replaced with Turbolinks’ Visit
  13. * Version: Turbolinks 5.0.0 DOMContentLoaded Inject “event” via document.addEventListener(‘click’) 1.

    ANCHOR INJECTION Normal navigation will be replaced with Turbolinks’ Visit Rails automatically adds “Turbolinks-Location” for 3xx/Redirection
  14. * Version: Turbolinks 5.0.0 Exists in cache and the page

    was allowed to be previewed? 2. TURBOLINKS VISIT
  15. * Version: Turbolinks 5.0.0 Exists in cache and the page

    was allowed to be previewed? Asynchronously load target href 2. TURBOLINKS VISIT Load from cache, inject ‘data-turbolinks-preview=true’ in <html /> root YES NO Assets version changed? Page loaded Do a full reload YES Replace metas, title, and body NO Put in cache (if allowed)
  16. * Version: Turbolinks 5.0.0 Exists in cache and the page

    was allowed to be previewed? Asynchronously load target href 2. TURBOLINKS VISIT Load from cache, inject ‘data-turbolinks-preview=true’ in <html /> root YES NO Assets version changed? Page loaded Do a full reload YES Replace metas, title, and body NO Put in cache (if allowed)
  17. * Version: Turbolinks 5.0.0 Exists in cache and the page

    was allowed to be previewed? 2. TURBOLINKS VISIT
  18. * Version: Turbolinks 5.0.0 Exists in cache AND the page

    was allowed to be cached? Asynchronously load target href 3. HISTORY NAVIGATION Load from cache YES NO Assets version changed? Page loaded Do a full reload YES Replace metas, title, and body NO Put in cache (if allowed)
  19. * Version: Turbolinks 5.0.0 Exists in cache AND the page

    was allowed to be cached? Asynchronously load target href 3. HISTORY NAVIGATION Load from cache YES NO Assets version changed? Page loaded Do a full reload YES Replace metas, title, and body NO Put in cache (if allowed)
  20. • You can’t use $.ready since it will be fired

    only once or multiple times! • Careful: Don’t attach turbolinks:load in inline script, since it will be fired twice! • Recommended way: • Require all components in application.js • Since each page is unique; put initialization as inline script, at the end of the body – so that page specific JS won’t make main script dirty COMPONENT INITIALIZATION
  21. • Components may create their own DOM after initialization (e.g.:

    Select2) • Without cleanup, those components may work incorrectly since they are not designed forTurbolinks (obviously!) DOM CLEANUP
  22. Example: Cleanup for select2 var target; var removeSelector = ".select2-hidden-accessible";

    // Select2 Removal target = $(removeSelector).first(); if (target.length > 0) { target.each(function() { var par = $(this).parent(); par.find(removeSelector) .removeClass(removeSelector); par.find(".select2").remove(); }); }
  23. • Recommended way: Consider ujs-style event injection • put attributes

    in data- • Define actions in data- • Use .on, put .on inside main script that is included by application.js • If it is page specific, use inline script. EVENT INJECTION
  24. TIMEOUT AND INTERVAL • Be sure to clean it up

    before next Turbolinks’ visit (add cleanup via turbolinks:before-render) • Warning again: all inline scripts are executed twice with Turbolinks’ Preview!
  25. Example: Interval cleanup var timers = []; var attachInterval =

    function() { var handler = setInterval( ... ) timers.push(handler); } document.addEventListener('turbolinks:before-render', function() { $(timers).each(function() { clearInterval(this); }); timers = []; });
  26. CREDITS • Globe by Fatahillah from the Noun Project •

    Subway by Viktor Fedyuk from the Noun Project • Exhaust Problem by Oliviu Stoian from the Noun Project