Offline функциональность

Offline функциональность становится критически важной для современных веб-приложений. Возможность работы приложения без подключения к интернету повышает удобство использования и надежность, особенно для пользователей мобильных устройств или нестабильного соединения. Vue.js предоставляет гибкие инструменты для реализации offline-first приложений, включая Service Worker, кеширование данных и локальное хранилище.


Service Worker и PWA

Service Worker — это скрипт, который браузер выполняет в фоновом режиме отдельно от веб-страницы. Он позволяет перехватывать сетевые запросы, кешировать ресурсы и синхронизировать данные в фоновом режиме.

Для интеграции Service Worker во Vue.js используется Vue CLI PWA Plugin. Установка и настройка:

vue add @vue/pwa

После установки создается файл service-worker.js, который можно настроить под конкретные нужды приложения. Основные возможности Service Worker:

  • Кеширование статических ресурсов: HTML, CSS, JS-файлы, изображения.
  • Фоновая синхронизация данных: отправка данных на сервер при восстановлении соединения.
  • Push-уведомления: уведомление пользователя о событиях, даже если приложение закрыто.

Пример кеширования ресурсов:

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('my-app-cache').then((cache) => {
      return cache.addAll([
        '/',
        '/index.html',
        '/css/app.css',
        '/js/app.js',
        '/images/logo.png'
      ]);
    })
  );
});

При запросе ресурсов Service Worker может отдавать их из кеша:

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

Работа с IndexedDB и LocalStorage

Для хранения данных в офлайн-режиме удобно использовать IndexedDB или LocalStorage.

  • LocalStorage подходит для небольших объемов данных (до 5 МБ).
  • IndexedDB — более мощное решение, позволяющее хранить сложные структуры данных и работать с большими объемами.

Пример работы с LocalStorage во Vue-компоненте:

export default {
  data() {
    return {
      tasks: []
    };
  },
  created() {
    const savedTasks = localStorage.getItem('tasks');
    if (savedTasks) {
      this.tasks = JSON.parse(savedTasks);
    }
  },
  methods: {
    addTask(task) {
      this.tasks.push(task);
      localStorage.setItem('tasks', JSON.stringify(this.tasks));
    }
  }
};

Для IndexedDB можно использовать библиотеку idb, упрощающую работу с асинхронными операциями:

import { openDB } from 'idb';

const dbPromise = openDB('tasks-db', 1, {
  upgrade(db) {
    db.createObjectStore('tasks', { keyPath: 'id', autoIncrement: true });
  }
});

async function saveTask(task) {
  const db = await dbPromise;
  await db.add('tasks', task);
}

async function getTasks() {
  const db = await dbPromise;
  return await db.getAll('tasks');
}

Кеширование API-запросов

Для офлайн-приложений важно сохранять ответы с сервера. Реализуется это через Service Worker или клиентские хранилища.

Пример с Service Worker:

self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('/api/')) {
    event.respondWith(
      caches.open('api-cache').then((cache) =>
        fetch(event.request)
          .then((response) => {
            cache.put(event.request, response.clone());
            return response;
          })
          .catch(() => caches.match(event.request))
      )
    );
  }
});

Такой подход позволяет приложению работать с последними доступными данными даже без подключения к интернету.


Состояние приложения при офлайн

Для управления состоянием Vue-приложения в офлайн важно предусмотреть:

  • Синхронизацию данных: использование очереди операций, которая выполняется при восстановлении соединения.
  • Обновление UI: уведомление пользователя о том, что данные могут быть устаревшими.
  • Фолбэк-данные: хранение критически важных данных локально для мгновенного отображения.

Пример очереди синхронизации:

const offlineQueue = [];

function addToQueue(request) {
  offlineQueue.push(request);
  localStorage.setItem('offlineQueue', JSON.stringify(offlineQueue));
}

window.addEventListener('online', () => {
  const queue = JSON.parse(localStorage.getItem('offlineQueue')) || [];
  queue.forEach(async (req) => {
    await fetch(req.url, req.options);
  });
  localStorage.removeItem('offlineQueue');
});

Интеграция с Vuex

При использовании Vuex для управления состоянием офлайн-функциональность расширяется. Состояние можно сохранять в LocalStorage или IndexedDB при каждом изменении:

import createPersistedState from 'vuex-persistedstate';

export default new Vuex.Store({
  state: {
    tasks: []
  },
  mutations: {
    addTask(state, task) {
      state.tasks.push(task);
    }
  },
  plugins: [createPersistedState({
    storage: window.localStorage
  })]
});

Это обеспечивает сохранение состояния приложения при перезагрузке или отсутствии сети.


Offline функциональность во Vue.js строится на трех ключевых принципах: кеширование ресурсов и данных, работа с локальными хранилищами и синхронизация состояния при восстановлении сети. Комбинирование Service Worker, IndexedDB и Vuex позволяет создавать приложения, которые остаются полностью функциональными без постоянного подключения к интернету.