Turbo Drive

Is the most important part of Turbo, despite it seems the simplest, I think it’s because frames and streams seems more spectacular. It basically avoids full-reloading of HTML page, just replacing the <body>, giving a clean sense of navigation. Intercepting usual HTTP requests and use fetch for server calls. It also manages full browser history with advance/replace/restore actions.

We can decompose its main features in 15 points:

  1. Page navigation basics:
    • Visit (def.): Entire navigation lifecycle is: change browser history -> fetch request -> restoring a copy from cache -> rendering response -> updating scroll position.
    • Types of visits are: Application (as an action of advance/replace) and restoration (as an action of restore cache page)
    • You can also delete all cache with: Turbo.clearCache()
  2. Application Visits
    • Turbo.visit(location) tries to render a preview, if exists, of the actual view. Then replaces it and add to history with history.pushState.
    • If you want to replace the state of the browser-history, you can manage it by a tag <a href=”/edit” data-turbo-action=”replace”/>. Or by JavaScript: Turbo.visit(“/edit”,{action: “replace”}).
  3. Restoration visits: These are fired when you click on back/forward buttons in your browser or mouse.
  4. Canceling visits before they start: You can do it by listening the event “turbo:before-visit”. Preventing default behavior with event.preventDefault(). And finally you can check location in event.detail.url.
  5. Pausing rendering: You can do it by listening the event “turbo:before-render”. Preventing default behavior with event.preventDefault(). Do things you want to do. And resume rendering with event.detail.resume() function.
  6. Pausing requests: The same as before point but listening “turbo:before-fetch-request”.
  7. Links with different methods: Method fired by a link by default is GET. You can replace it: <a href=”/article/64″ turbo-data-method=”delete”>Delete article</a>.
  8. Disable Turbo on specific links or forms: It can be disabled for links <a href=”/articles” data-turbo=”false”>Disabled Turbo</a>. Or directly importing Turbo in JavaScript: Turbo.session.drive=false.
  9. Displaying progress: Drive installs a CSS Turbo progress bar by default:
    • Appears when action takes longer than 500ms (you can change this time with Turbo.setProgressBarDelay()).
    • To manipulate CSS appearance with class: .turbo-progress-bar.
    • Also puts to true “aria-busy” attribute, and false when all action is done.
  10. Reloading when assets change: When an asset changes in <head> full page is reloaded. For that purpose you have to put [data-turbo-track=”reload”] and version ID in all header assets.
  11. Force full reload for certain pages: Include in <head> the tag: <meta name=”turbo-visit-control” content=”reload”>
  12. Setting root location: You can have a concrete path for your app like “/app” and all others are completely different apps. Include in <head> this: <meta name=”turbo-root” content=”/app”/>. And Turbo will be disabled in other roots.
  13. Form submissions:
    • Form lifecycle can be manipulated through events (see Reference/Events)
    • Turbo also sends a “disable” attribute to submitter (submit button)
    • Events like: “turbo:submit-start”, “turbo:before-fetch-request”,…
  14. Redirecting after form submission: Turbo waits for 3xx redirect responses to fetch content. Except on 4xx (wrong inputs) or 5xx errors.
  15. Streaming after form submission:”Content-Type: text/vnd.turbo-stream.html” with content of several <turbo-stream> elements, so you can replace all of the in one action.

Introduction to Hotwire/Turbo

Turbo is the evolution of turbolinks Rails library, done to make your web app navigation faster. Giving the performance of a single-page application (like Reac) but with much less complexity and much cheaper development costs in money and time.

We can decompose Turbo in several parts:

  • Turbo Drive: avoids full-reloading of HTML page, just replacing the <body>, giving a clean sense of navigation. It intercepts usual HTTP requests and use fetch for server calls. It also manages full browser history with advance/replace/restore actions.
  • Tubo Frames: It decompose your page in parts using <turbo-frame> tag, which can be replaced by copies received by the server, just locating and replacing them thanks to identifiers.
  • Turbo Streams: Also decompose your page in <turbo-stream> parts with will be fetched to Websocket channels, so they will be replaced on change with no user action needed. Thanks to the broadcasting of Websockets, through ActiveCable channels connected to your clients’ browsers.
  • Turbo Native: Brings these capabilities to the Android/IOS development world, just developing your native mobile application from your web server, avoiding long and onerous upgrade processes in marketplaces. Note that you will use native APIs, you are reusing the view and HTML fragments parts.
  • Turbo Rails: Is the gem which simplifies views programming in Rails backends, including helpers like turbo_frame_tag or turbo_stream_from.

Enjoy the invent!

SPA Javascript Frameworks pros and cons

My perspective is Enterprise Applications Development with Ruby on Rails. I am talking about frameworks like AngularJS, Ember, React, Backbone ….

Javascript:

  • Ugly language. Yes, but it was improved since ECMA6. and now you can give structure with Stimulus.js, in order to do it more maintainable.
  • Verbose: we have to make one file and extend one class for each route in Emberjs for example.
  • Give +2 points for the ugliness of the language and the hell of maintenance.

Template engine:

  • Always based on HTML (like handlebars), now we have HAML or SLIM.
  • React is even worse because it has JWS templates mixing JS and HTML

Another Hell is the Authentication layer. Here you have the example with Ember.

Pro Arguments:

  • Smooth and modern fluid feeling in apps, avoiding to reload full page.
  • BTW you are building and testing your REST API. But at the same time you are spending lots of time maintaining horrible JavaScript.
  • You are separating front-end and back-end. But adding one more layer of abstraction you have an MC-MVC architecture instead of a simple MVC architecture. Increasing complexity exponentially.
  • Download all assets once, not overloading the server. Well, always you can scale your systems.

Conclusions:

  • Use Node and Yarn to manage all super-great libraries in the frontend.
  • Use Hotwire/Turbo to provide a modern SPA-feeling without reloadings. Then you can give abstraction to the most complicated parts.
  • Create your REST APIs at the same time in your App but do not lose your time with complicated frameworks.
  • Make your life easier with SASS, HAML or Slim.
  • If a client suggests you these frameworks advise that it will increment dramatically the costs of development.
  • These frameworks are recommended only if:
    • You want to develop a front-end over an API which you are not owning.
    • Your front-end requires complicated images rendering and actions in the browser, like an editor or something like this.