Turbolinks and beyond
@h6165
Abhishek Yadav
ரூபீ ப்ரோக்ராமர்
Co-organizer: Chennai.js and Chennai.rb
The idea
Turbolinks
- Short-circuit all the links on the page
 - Load them using Ajax
 - Extract <body> from the response and replace in current page
 
The goal
Turbolinks
- Make link loads feel faster
 - Avoid having to use front-end frameworks
 
Demo
Turbolinks
- Turbolinks demo
 - Pjax demo
 
Demo
Turbolinks Demo
Pjax Demo
Turbolinks
http://pjax.herokuapp.com
The history
Turbolinks
- pjax (https://github.com/defunkt/jquery-pjax)
 - Turbolinks-classic
 - Turbolinks-5
 
The idea
Turbolinks
- Short-circuit all the links on the page - only the application links
 - Load them using Ajax - XmlHttpRequest
 - 
Extract <body> from the response and replace in current page 
	
- Change the page Url
 - Hack the back button too
 
 - 
Cache visited pages
	
- Use cached pages for back navigation
 - Use cache for temp-preview in forward navigation
 
 - Show a CSS based loader
 
Problems
Turbolinks
- 
Loss of events
	
- No page load -> no DOMContentLoaded -> no window.onload -> $(document).ready won't work
 
 - 
Over-caching
	
- Back button doesn't reload the previous page - can show stale data
 
 - 
Over-scripting
	
- <script> tags in header and body are evaluated on every page load
 - If the script makes a non-idempotent change on the page, it will be repeatedly applied.
 
 
Problems
Turbolinks
- Application may need to be rewritten (in parts at least)
 - Many plugins can stop working
 
Problems
Turbolinks

Problems - Solutions
Turbolinks
Loss of events
- 
No page load -> no DOMContentLoaded -> no window.onload -> $(document).ready won't work
	
- 
		
Listen on the turbolinks:load event
 - 
		
Use event delegation
 - 
		
Use MutationObserver
 
 - 
		
 
Problems - Loss of events
Turbolinks
Use turbolinks:load
After loading a new page, Turbolinks fires the turbolinks:load event. All/most $(document).ready can be replaced with that -
$(document).ready(function(){
  // page load stuff
})
// becomes
$(document).on("turbolinks:load", function(){
  // page load stuff
})
// or
document.addEventListener("turbolinks:load", function() {
  // page load stuff
})Problems - Loss of events
Turbolinks
Listening on turbolinks:load is not the best approach.
- Makes the app dependant on library specific event
 - Plugins can't use this approach
 
Problems - Loss of events
Turbolinks
Event delegation
- Is a popular technique (not specific to Turbolinks)
 - Attach event to future-elements (elements that may get added via Ajax) by binding to a top level element
 - eg - React event handling uses delegation only
 - Depends on event bubbling - comes with its own challenges - but is in general more reliable
 
Problems - Loss of events
Turbolinks
Event delegation
// Instead of -
$('.dance-button').on('click', function(){
  // start dancing
})
// This -
// Will work if .dance-button is loaded later by an Ajax call
// Will work with Turbolinks without change
$('body').on('click', '.dance-button' function(){
  // start dancing
})
Problems - Loss of events
Turbolinks
Mutation Observers
- Is a somewhat novel technique
 - We can observe changes to the DOM and respond to them
 - The idea is, DOM content can be changed by entities other than Turbolinks. Like Websockets.
 - This could be one place where all the content changes are captured and managed
 
Problems - Loss of events
Turbolinks
var el = document.getElementById('#my-widget');
 
// create an observer instance
var observer = new MutationObserver(function(mutations) {
  console.log("It changed");
});
observer.observe(el, { childList: true })
Mutation Observers
Problems - Over caching
Turbolinks
Opt out
Cache will not be used in restoration (back button)
or for previews (for visited links)
<meta name="turbolinks-cache-control" content="no-cache">Problems - Over caching
Turbolinks
Persist elements
- Elements marked as permanent will be left out during page loads
 - Suitable for things like cart-counter - whose change logic is independent of page loads
 
<div id="cart-counter" data-turbolinks-permanent>1 item</div>Problems - Over scripting
Turbolinks
Idempotent scripts
Scripts that can be run one or many times with the same result
// Overscripting example -
// This is an inline script 
<script>
  function foo(){
    $("#welcome").append("<b> Welcome to our site </b>");
  }
  function bar(){
    $("#welcome").html("<b> Welcome to our site </b>");
  }
  
  foo();
  bar();
</script>
// foo is not-idempotent
// bar is idempotentSimilar projects
Turbolinks
- Turbolinks classic
 - Jquery-turbolinks
 - Turbograft
 
Conclusion
Turbolinks
Why resist client-side Js frameworks - cons
- Your Ain't Gonna Need It Yet (YAGNI) - chances are - you are over-engineering.
 - 
Cost of addition
	
- Learning curve
 - Api
 
 - Poor UX
 - The Just use Jquery philosophy - Its still alive
 
Conclusion
Turbolinks
Why resist client-side Js frameworks - pros
- Are client-side frameworks the new Jquery ?
 - Your app will become complex enough eventually ? Plan for UI complexity
 - Resume driven development - if we don't know React, someone else gets the job
 
Open scenario
Turbolinks
- Form with dropdown
 - Subsequent elements change on differing value
 
Turbolinks and beyond
By Abhishek Yadav
Turbolinks and beyond
- 1,494