Esta serie de dos partes es una introducción suave al desarrollo web sin conexión. Lograr que una aplicación web haga algo sin conexión es sorprendentemente complicado, ya que requiere muchas cosas para estar en su lugar y funcionar correctamente. Vamos a cubrir todas estas piezas desde un alto nivel, con ejemplos prácticos. Esta publicación es una descripción general, pero hay muchos recursos más detallados enumerados a lo largo.
Serie de artículos:
- La configuración (¡usted está aquí!)
- La implementación
Enfoque básico
Haré un uso intensivo de la sintaxis async/await de JavaScript. Es compatible con todos los principales navegadores y Node, y simplifica enormemente el código basado en Promise. El enlace anterior explica bien async, pero en pocas palabras le permiten resolver una promesa y acceder a su valor directamente en el código con await
, en lugar de llamar .then
y acceder al valor en la devolución de llamada, lo que a menudo conduce a la temida “desviación hacia la derecha”.
¿Qué estamos construyendo?
Ampliaremos un proyecto de lista de libros existente para sincronizar los libros del usuario actual con IndexedDB y crearemos una página sin conexión simplificada que se mostrará incluso cuando el usuario no tenga conexión a la red.
Comenzando con un trabajador de servicio
Lo único no negociable que necesita para el desarrollo fuera de línea es un trabajador de servicio. Un service worker es un proceso en segundo plano que puede, entre otras cosas, interceptar solicitudes de red; redirigirlos; cortocircuitarlos devolviendo respuestas almacenadas en caché; o ejecútelos normalmente y haga cosas personalizadas con la respuesta, como el almacenamiento en caché.
Almacenamiento en caché básico
Probablemente lo primero, más básico, pero de alto impacto que hará con un trabajador de servicio es hacer que almacene en caché los recursos de su aplicación. El trabajador del servicio y el caché que usa son primitivos de nivel extremadamente bajo; todo es manual. Para almacenar en caché correctamente sus recursos, deberá buscarlos y agregarlos a un caché, pero luego también deberá realizar un seguimiento de los cambios en estos recursos. Realizará un seguimiento cuando cambien, eliminará la versión anterior y buscará y actualizará la nueva.
En la práctica, esto significa que su código de trabajador de servicio deberá generarse como parte de un paso de compilación, que genera un hash de sus archivos y genera un archivo que es lo suficientemente inteligente como para registrar estos cambios entre versiones y actualizar los cachés según sea necesario.
Abstracciones al rescate
Este es un código extremadamente tedioso y propenso a errores que probablemente nunca querrá escribir usted mismo. Afortunadamente, algunas personas inteligentes han escrito abstracciones para ayudar, a saber, sw-precache y sw-toolbox de la gran gente de Google. Tenga en cuenta que, desde entonces, Google ha desaprobado estas herramientas a favor de la Workbox más nueva. Todavía tengo que mover mi código desde sw-*
funciona muy bien, pero en cualquier caso las ideas son las mismas, y me dijeron que la conversión es fácil. Y cabe mencionar que sw-precache cuenta actualmente con unas 30.000 descargas por día, por lo que todavía es ampliamente utilizado.
Hola mundo, sw-precache
Empecemos de inmediato. Estamos usando un paquete web y, a medida que avanza el paquete web, hay un complemento, así que primero verifiquemos eso.
// inside your webpack config
new SWPrecacheWebpackPlugin({
mergeStaticsConfig: true,
filename: "service-worker.js",
staticFileGlobs: [ //static resources to cache
"static/bootstrap/css/bootstrap-booklist-build.css",
...
],
ignoreUrlParametersMatching: /./,
stripPrefixMulti: { //any paths that need adjusting
"static/": "react-redux/static/",
...
},
...
})
De forma predeterminada, TODOS los paquetes que crea el paquete web se almacenarán previamente en caché. También proporcionamos manualmente algunas rutas a los recursos estáticos que quiero almacenar en caché en el staticFileGlobs
propiedad, y estoy ajustando algunas rutas en stripPrefixMulti
.
// inside your webpack config
const getCache = ({ name, pattern, expires, maxEntries }) => ({
urlPattern: pattern,
handler: "cacheFirst",
options: {
cache: {
maxEntries: maxEntries || 500,
name: name,
maxAgeSeconds: expires || 60 * 60 * 24 * 365 * 2 //2 years
},
successResponses: /0|[123].*/
}
});
new SWPrecacheWebpackPlugin({
...
runtimeCaching: [ //pulls in sw-toolbox and caches dynamically based on a pattern
getCache({ pattern: /^https://images-na.ssl-images-amazon.com/, name: "amazon-images1" }),
getCache({ pattern: /book/searchBooks/, name: "book-search", expires: 60 * 7 }), //7 minutes
...
]
})
Añadiendo el runtimeCaching
sección a nuestra SWPrecacheWebpackPlugin
atrae sw-toolbox
y nos permite almacenar en caché URL que coincidan con un determinado patrón, de forma dinámica, según sea necesario, con getCache
ayudando a mantener el repetitivo al mínimo.
Hola mundo, sw-caja de herramientas
Todo el archivo del trabajador del servicio que se genera es bastante grande, pero solo veamos una pequeña parte, a saber, uno de los cachés dinámicos de arriba:
toolbox.router.get(/^https://images-na.ssl-images-amazon.com/, toolbox.cacheFirst, {
cache: { maxEntries: 500, name: "amazon-images1", maxAgeSeconds: 63072000 },
successResponses: /0|[123].*/
});
sw-toolbox
nos ha proporcionado un buen objeto de enrutador de alto nivel que podemos usar para enlazar varias solicitudes de URL, estilo MVC. Lo usaremos para configurar sin conexión en breve.
No te olvides de registrar el trabajador de servicio
Y, por supuesto, la existencia del archivo del trabajador del servicio que se generó arriba no sirve por sí mismo; necesita ser registrado. El código se ve así, pero asegúrese de tenerlo dentro de un onload
oyente, o algún otro lugar que se garantice que se ejecutará después de que se haya cargado la página.
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/service-worker.js");
}
¡Ahí lo tenemos! Tenemos un trabajador de servicio básico en ejecución, que almacena en caché los recursos de nuestra aplicación. Sintonízalo mañana cuando lo extendamos para admitir sin conexión.
Serie de artículos:
- La configuración (¡usted está aquí!)
- La implementación