Cómo indexar páginas que pueden funcionar sin conexión con la API de Content Indexing

Habilita los trabajadores del servicio para que les indiquen a los navegadores qué páginas funcionan sin conexión

¿Qué es la API de Content Indexing?

Usar una app web progresiva significa tener acceso a información que les interesa a las personas (imágenes, videos, artículos y mucho más), independientemente del estado actual de tu conexión de red. Tecnologías como los trabajadores en segundo plano, la API de almacenamiento en caché y IndexedDB te proporcionan los elementos básicos para almacenar y entregar datos cuando las personas interactúan directamente con una AWP. Sin embargo, compilar una AWP de alta calidad que priorice el uso sin conexión es solo una parte de la historia. Si los usuarios no se dan cuenta de que el contenido de una app web está disponible sin conexión, no aprovecharán al máximo el trabajo que dedicas a implementar esa funcionalidad.

Este es un problema de descubrimiento. ¿Cómo puede tu AWP informar a los usuarios sobre su contenido sin conexión para que puedan descubrir y ver lo que está disponible? La solución a este problema es la API de Content Indexing. La parte de esta solución destinada a los desarrolladores es una extensión de los trabajadores del servicio, que permite a los desarrolladores agregar URLs y metadatos de páginas que se pueden usar sin conexión a un índice local que mantiene el navegador. Esa mejora está disponible en Chrome 84 y versiones posteriores.

Una vez que el índice se propague con el contenido de tu AWP, así como con cualquier otra AWP instalada, el navegador lo mostrará como se muestra a continuación.

Captura de pantalla del elemento de menú Descargas en la página Nueva pestaña de Chrome.
Primero, selecciona el elemento de menú Descargas en la página Nueva pestaña de Chrome.
Contenido multimedia y artículos que se agregaron al índice.
El contenido multimedia y los artículos que se hayan agregado al índice se mostrarán en la sección Artículos para ti.

Además, Chrome puede recomendar contenido de forma proactiva cuando detecta que un usuario está sin conexión.

La API de Content Indexing no es una forma alternativa de almacenar contenido en caché. Es una forma de proporcionar metadatos sobre las páginas que ya están almacenadas en caché por el trabajador de tu servicio, de modo que el navegador pueda mostrar esas páginas cuando sea probable que los usuarios quieran verlas. La API de Content Indexing ayuda con la visibilidad de las páginas almacenadas en caché.

Observa cómo funciona

La mejor manera de conocer cómo funciona la API de Content Indexing es probar una aplicación de ejemplo.

  1. Asegúrate de usar un navegador y una plataforma compatibles. Por el momento, se limita a Chrome 84 o versiones posteriores en Android. Ve a about://version para ver qué versión de Chrome ejecutas.
  2. Visita https://contentindex.dev.
  3. Haz clic en el botón + junto a uno o más de los elementos de la lista.
  4. (Opcional) Inhabilita la conexión Wi-Fi y de datos móviles del dispositivo, o habilita el modo de avión para simular que el navegador no tiene conexión.
  5. Elige Descargas en el menú de Chrome y cambia a la pestaña Artículos para ti.
  6. Explora el contenido que guardaste anteriormente.

Puedes ver el código fuente de la aplicación de ejemplo en GitHub.

Otra aplicación de ejemplo, una PWA de Scrapbook, ilustra el uso de la API de Content Indexing con la API de Web Share Target. El código muestra una técnica para mantener la API de Content Indexing sincronizada con los elementos que almacena una app web mediante la API de Cache Storage.

Cómo usar la API

Para usar la API, tu app debe tener un service worker y URLs que se puedan navegar sin conexión. Si tu app web no tiene un service worker actualmente, las bibliotecas de Workbox pueden simplificar la creación de uno.

¿Qué tipo de URLs se pueden indexar para que funcionen sin conexión?

La API admite URLs de indexación correspondientes a documentos HTML. Por ejemplo, una URL de un archivo multimedia almacenado en caché no se puede indexar directamente. En su lugar, debes proporcionar una URL de una página que muestre contenido multimedia y que funcione sin conexión.

Un patrón recomendado es crear una página HTML de "lector" que acepte la URL de medios subyacente como parámetro de consulta y, luego, muestre el contenido del archivo, posiblemente con controles o contenido adicionales en la página.

Las apps web solo pueden agregar URLs al índice de contenido que estén dentro del alcance del trabajador de servicio actual. En otras palabras, una app web no podía agregar una URL que pertenezca a un dominio completamente diferente al índice de contenido.

Descripción general

La API de Content Indexing admite tres operaciones: agregar, mostrar y quitar metadatos. Estos métodos se exponen desde una propiedad nueva, index, que se agregó a la interfaz ServiceWorkerRegistration.

El primer paso para indexar contenido es obtener una referencia al ServiceWorkerRegistration actual. Usar navigator.serviceWorker.ready es la forma más directa:

const registration = await navigator.serviceWorker.ready;

// Remember to feature-detect before using the API:
if ('index' in registration) {
 
// Your Content Indexing API code goes here!
}

Si realizas llamadas a la API de Content Indexing desde un trabajador de servicio, en lugar de hacerlo desde una página web, puedes hacer referencia a ServiceWorkerRegistration directamente a través de registration. Ya estará definido como parte de ServiceWorkerGlobalScope..

Cómo agregar al índice

Usa el método add() para indexar las URLs y sus metadatos asociados. Depende de ti elegir cuándo se agregan elementos al índice. Te recomendamos que agregues al índice en respuesta a una entrada, como hacer clic en un botón "Guardar sin conexión". También puedes agregar elementos automáticamente cada vez que se actualizan los datos almacenados en caché a través de un mecanismo como la sincronización en segundo plano periódica.

await registration.index.add({
 
// Required; set to something unique within your web app.
  id
: 'article-123',

 
// Required; url needs to be an offline-capable HTML page.
  url
: '/articles/123',

 
// Required; used in user-visible lists of content.
  title
: 'Article title',

 
// Required; used in user-visible lists of content.
  description
: 'Amazing article about things!',

 
// Required; used in user-visible lists of content.
  icons
: [{
    src
: '/img/article-123.png',
    sizes
: '64x64',
    type
: 'image/png',
 
}],

 
// Optional; valid categories are currently:
 
// 'homepage', 'article', 'video', 'audio', or '' (default).
  category
: 'article',
});

Agregar una entrada solo afecta el índice de contenido; no agrega nada a la caché.

Caso extremo: Llama a add() desde el contexto de window si tus íconos dependen de un controlador fetch.

Cuando llames a add(), Chrome realizará una solicitud para la URL de cada ícono para asegurarse de tener una copia del ícono que se usará cuando se muestre una lista de contenido indexado.

  • Si llamas a add() desde el contexto window (en otras palabras, desde tu página web), esta solicitud activará un evento fetch en tu service worker.

  • Si llamas a add() dentro de tu service worker (quizás dentro de otro controlador de eventos), la solicitud no activará el controlador fetch del service worker. Los íconos se recuperarán directamente, sin la participación de ningún trabajador de servicio. Ten esto en cuenta si tus íconos dependen del controlador fetch, quizás porque solo existen en la caché local y no en la red. Si es así, asegúrate de llamar a add() solo desde el contexto de window.

Cómo enumerar el contenido del índice

El método getAll() muestra una promesa para una lista iterable de entradas indexadas y sus metadatos. Las entradas que se muestran contendrán todos los datos guardados con add().

const entries = await registration.index.getAll();
for (const entry of entries) {
 
// entry.id, entry.launchUrl, etc. are all exposed.
}

Cómo quitar elementos del índice

Para quitar un elemento del índice, llama a delete() con el id del elemento que quieres quitar:

await registration.index.delete('article-123');

Llamar a delete() solo afecta al índice. No borra nada de la caché.

Controla un evento de eliminación de un usuario

Cuando el navegador muestra el contenido indexado, puede incluir su propia interfaz de usuario con un elemento de menú Borrar, lo que da a las personas la oportunidad de indicar que terminaron de ver el contenido indexado previamente. Así se ve la interfaz de eliminación en Chrome 80:

El elemento del menú Borrar.

Cuando alguien seleccione ese elemento de menú, el service worker de tu aplicación web recibirá un evento contentdelete. Si bien controlar este evento es opcional, le brinda a tu trabajador de servicio la oportunidad de "limpiar" el contenido, como los archivos multimedia almacenados en caché de forma local, que alguien indicó que ya no necesita.

No es necesario que llames a registration.index.delete() dentro de tu controlador contentdelete. Si se activó el evento, el navegador ya realizó la eliminación de índice relevante.

self.addEventListener('contentdelete', (event) => {
 
// event.id will correspond to the id value used
 
// when the indexed content was added.
 
// Use that value to determine what content, if any,
 
// to delete from wherever your app stores it—usually
 
// the Cache Storage API or perhaps IndexedDB.
});

Comentarios sobre el diseño de la API

¿Hay algo en la API que sea incómodo o no funcione como se espera? ¿O ¿faltan piezas que necesitas para implementar tu idea?

Informa un problema en el repositorio de GitHub de la explicación de Content Indexing API o agrega tus comentarios a un problema existente.

¿Tienes problemas con la implementación?

¿Encontraste un error en la implementación de Chrome?

Envía un informe de errores a https://new.crbug.com. Incluye la mayor cantidad de detalles posible, instrucciones simples para reproducirlo y establece Componentes en Blink>ContentIndexing.

¿Tienes pensado usar la API?

¿Planeas usar la API de Content Indexing en tu app web? Tu apoyo público ayuda a Chrome a priorizar las funciones y les muestra a otros proveedores de navegadores lo importante que es admitirlas.

¿Cuáles son algunas de las consecuencias de seguridad y privacidad de la indexación de contenido?

Consulta las respuestas del cuestionario de seguridad y privacidad de W3C. Si tienes más preguntas, inicia una conversación a través del repositorio de GitHub del proyecto.

Hero image de Maksym Kaharlytskyi en Unsplash.