Turbolinks rend la navigation dans votre application Web plus rapide.
Turbolinks est une solution d’optimisation du chargement Web provenant de Ruby on Rails. En termes simples, lorsque l’utilisateur clique sur un lien, il ne saute pas réellement à une nouvelle page mais lit plutôt le contenu de la page cible par le biais d’ajax et remplace la page actuelle. Cette méthode présente les avantages suivants :
- Évite le rechargement du JavaScript et du CSS
- Réduit la charge de travail de la rendition des pages Web
- Est conviviale pour les moteurs de recherche
- Ne nécessite pas de modifications backend
- Prend en charge les plateformes d’application (avec des SDK Android et iOS)
En plus de ces avantages fonctionnels, cette interaction en forme de “page” traditionnelle rend également plus facile la compréhension pour les utilisateurs (bien que l’interaction en style d’application soit plus populaire maintenant, cela nécessite des normes plus élevées des concepteurs et si elle n’est pas bien conçue, cela peut facilement causer des problèmes de navigation pour les utilisateurs).
Installer Turbolinks
Voir https://github.com/turbolinks/turbolinks, je ne vais pas répéter le contenu de la documentation ici.
Astuces de base
Éviter les fichiers CSS et JS géants
En raison du mécanisme de chargement de Turbolinks, les utilisateurs ont tendance à empaqueter tous les styles et scripts dans un fichier CSS et JS géant, ce qui peut affecter gravement le chargement initial. Turbolinks prend entièrement en charge le chargement de différents CSS et JS pour différentes pages.
Dans le projet Simple Psychology, la méthode suivante a été utilisée pour déterminer et charger automatiquement les styles et scripts requis pour la page actuelle :
/ Charger les fichiers de style, comme le fichier CSS pour pages#home, stocké dans app/assets/stylesheets/www/pages/home.sass
- if File.exist?(Rails.root.join("app/assets/stylesheets/#{request.subdomain.split('.')[0]}/#{params[:controller]}/#{params[:action]}.sass"))
= stylesheet_link_tag "#{request.subdomain.split('.')[0]}/#{params[:controller]}/#{params[:action]}"
/ Charger les fichiers de script, comme le fichier JS pour pages#home, stocké dans app/assets/javascripts/www/pages/home.coffee
- if File.exist?(Rails.root.join("app/assets/javascripts/#{request.subdomain.split('.')[0]}/#{params[:controller]}/#{params[:action]}.coffee"))
= javascript_include_tag "#{request.subdomain.split('.')[0]}/#{params[:controller]}/#{params[:action]}"
Simplifier les événements de chargement de page
En raison du mécanisme de chargement spécial de Turbolinks, nous devons souvent enregistrer et annuler l’enregistrement des événements manuellement. Chez Simple Psychology, nous avons simplifié ce code de cette manière :
_page_loaded = []
_page_unload = []
_page_unload_once = []
# Exécuter lorsque la page Web est chargée
window.$loaded = (func)->
_page_loaded.push(func)
# Exécuter en quittant la page Web
window.$unload = (func)->
_page_unload.push(func)
# Exécuter une fois en quittant la page Web
window.$unload_once = (func)->
_page_unload_once.push(func)
# Le code ci-dessous est l'implémentation des interfaces ci-dessus
window.addEventListener 'turbolinks:load', ->
func() for func in _page_loaded
window.addEventListener 'turbolinks:before-visit', ->
func() for func in _page_unload_once
_page_unload_once = []
func() for func in _page_unload
window.addEventListener 'beforeunload', ->
func() for func in _page_unload_once
_page_unload_once = []
func() for func in _page_unload
null
Compatibilité avec Vue.js 1.x
Lorsqu’un page a des interactions de plus en plus complexes, il est nécessaire d’utiliser des cadres comme Vue.js pour simplifier le code d’interaction. Cependant, Turbolinks ne cache pas les événements liés au DOM lors du cache de pages. Lorsqu’un utilisateur revient à une page qui utilise des composants Vue, ces composants ne fonctionnent plus.
Notre approche de résolution consiste à cacher les données des composants Vue et à annuler l’enregistrement des composants en quittant la page. Lors du retour, ré-render le composant et injectez les données précédemment mises en cache.
Il est également important de noter que Turbolinks se souvient également de la position de défilement actuelle de la page, enregistrée dans Turbolinks.controller.getCurrentRestorationData().scrollPosition
. Par conséquent, si votre composant est une longue liste et est chargée de manière asynchrone, vous devez manuellement mettre en cache cette position avant le chargement (car après le retour à la page, Turbolinks va automatiquement rafraîchir la valeur enregistrée), puis faire défiler la page vers la position mémorisée après que les données de la liste aient été chargées et rendues.
L’implémentation spécifique est la suivante : (Comme nous n’utilisons plus Vue.js, seules les solutions pour la version 1.x sont fournies)
vm_caches = {}
cache_data = (props, data)->
cache = {}
for k, v of $.extend(props, data)
if v && typeof v['raw'] isnt 'undefined'
continue if v.raw && v.raw.indexOf('$data') is 0
try
cache[k] = eval(v.raw)
catch error
cache[k] = v.raw
else
cache[k] = v
cache
cache_vm = (parent, cache)->
for child in parent.$children
continue if typeof child is 'undefined'
cache[child.constructor.name] = cache_data(child._data, child._props)
cache_vm child, cache
$loaded ->
window.vm = new Vue
el: 'body'
window.addEventListener 'turbolinks:before-cache', ->
list = []
while vm.$children.length > 0
child = vm.$children[0]
id = $.id() # $.id est une fonction pour générer un ID unique, que vous pouvez implémenter vous-même
vm_caches[id] =
data: cache_data(child._data, child._props)
children: {}
$(child.$el).after(child.$options.el.outerHTML.replace('><', " _cache_key=\"#{id}\"><"))
cache_vm child, vm_caches[id].children
child.$destroy(true)
Vue.define = (id, options)->
if options['props']
options.props.push '_cache_key'
else
options.props = []
if options['ready']
originalReady = options.ready
options.ready = ->
if vm_caches[@$parent._cache_key]
for k, v of vm_caches[@$parent._cache_key].children[@constructor.name]
Vue.set this, k, v
if vm_caches[@_cache_key]
for k, v of vm_caches[@_cache_key].data
Vue.set this, k, v
originalReady.call(this)
else
options.ready = ->
if @_cache_key
for k, v of vm_caches[@_cache_key]
Vue.set this, k, v
Vue.component id, options
Si vous avez plus d’astuces, n’hésitez pas à les partager et à les échanger.