Skip to content

Using the Offline Mode

Available since: brezel-spa@3.8.0, brezel/api@0.97.0

The offline mode is a feature that allows you to use your application without an internet connection. This is useful when you are in a place with no internet connection or when you want to save data and synchronize it later.

Requirements

To use the offline mode, you need to fulfill the following requirements:

  • Brezel with ^brezel-spa@3.8.0 or higher, and ^brezel/api@0.97.0 or higher
  • A device with a browser that supports offline mode:
    • Chrome
    • Firefox
    • Safari
    • Edge
  • For the service worker, you need to have a secure connection (HTTPS).

Limitations

The offline mode has some limitations:

  • Workflows are not supported in offline mode. Requests made to workflows are instead queued and executed when the internet connection is available. Using workflows for pre-filling data is not recommended in offline mode. Instead, use Brezel Actions (to be documented).
  • Storage of large file uploads, or requests in general, is limited to the browser’s IndexedDB size, which counts against the browser’s storage quota. If the storage quota is exceeded, the service worker will not be able to store the request and will return an error.

Levels

Brezel has different levels of availability:

  1. Online: The application is connected to the internet and works as usual. In this mode, the background sync queue is not used, although it may still hold requests that were made while offline and will be synchronized when the Browser fires the sync event.
  2. Offline level 0: Used when the application is disconnected from the internet and the Brezel version is older than brezel-spa@3.8.0. All requests result in a “No connection” (Failed to fetch) error. No background sync queue is available.
  3. Offline level 1: Used when the application is disconnected from the internet, and VITE_APP_OFFLINE_MODE in the .env file is not set or set to false. In this mode, the service worker serves data from the spa-cache, abi-base-cache and the api-cf-cache, meaning that the application is visible and still navigable, but entities are not available. In the menu, the warning “You are offline” is displayed. Requests made to the API result in a “No connection” (Failed to fetch) error. The background sync queue is not available.
  4. Offline level 2: Used when the application is disconnected from the internet and VITE_APP_OFFLINE_MODE in the .env file is set to true. In this mode, the service worker serves data from the spa-cache, api-base-cache, api-cf-cache, and api-nf-cache. In the menu under the logo, the warning “You are offline” is displayed. Entities and offline resource tables are available, if they were previously loaded or explicitly downloaded. Requests made to the API are intercepted by the service worker and served from the cache with normal status codes. The application feels like it is online, but data may be outdated. The background sync queue is used to store requests made while offline.

Pre-downloads

In offline level 2, the service worker can pre-download data from the API after page load, or when the user clicks on the download button in the offline mode menu. To make entities of a module downloadable, you need to set the offline option in the module’s options:

[
{
"resource_module": "customers",
"import": true,
"resource": {
"identifier": "customers",
"title": "name",
"icon": "global",
"layouts": {
"detail": "${file('/modules/customers.detail.json')}"
},
"options": {
"offline": {
"enabled": true,
"download": {
"trigger": "manual"
}
}
},
"fields": [
{
"identifier": "name",
"type": "text",
"options": {
"rules": "required"
}
}
]
}
}
]

The offline option has the following type signature:

type OfflineOptions = {
enabled: boolean
download: DownloadOptions
}
export type DownloadOptions = {
trigger?: 'auto' | 'manual' | null | undefined
pages?: number | null | undefined
filters?: DNF | null | undefined
}
export type DNF = FilterClauses[]
export type FilterClauses = FilterClause[]
export type FilterClause = {
column: string | undefined
field: string | undefined
operator: string
value: string | unknown[] | unknown
}

How it works

The offline mode uses a service worker to cache the application files, modules, and data. When you open the application, the service worker checks if there is an internet connection. If there is no connection, the service worker loads data from the cache and serves it to SPA. The service worker is therefore a layer between the frontend in Brezel SPA and the Brezel API. It uses different strategies to cache the data. If PUT, POST, or DELETE requests are made, the service worker will store the data in the cache and synchronize it later when the internet connection is available using Background Sync.

Caches

In the Brezel offline mode, there are multiple caches for different types of data:

Cache nameDescriptionStrategyDataLevel 1Level 2
spa-cacheNon-API requestsPreCaching and NetworkFirstindex.html, main.js, app bundle, external resources
api-cf-cacheAPI responses for static-like dataCacheFirstContents of file entities
api-base-cacheAPI responses for static configurationStaleWhileRevalidateModules, layouts, translations, styles, menus, views, events, languages, countries, subscription plans
api-nf-cacheAPI responses for volatile dataNetworkFirstEntities (index, tables, show)

Background Sync

When you are offline and make a PUT, POST, or DELETE request, the service worker will store the request in the api-queue queue. When the internet connection is available again, the service worker will replay the requests from the queue and synchronize the data with the API.

File uploads also work in offline mode. When you upload a file, the service worker will store the upload request and attach a X-Local-Id header to the request. A mock response is returned with a local ID prefixed with local-. On replay, the service worker will intercept the returned real ID and replace all occurrences of the local ID in upcoming requests in the queue with the real ID. This strategy is also used on all other entity relations.

During replay, request headers are attached with X-Queue-Name, X-Queued-At and X-Queued-By, to log that the entity update was performed by a service worker.

Entity updates stored in the background sync queue are also virtually applied to the entities in the cache by the service worker on each request, so that the SPA always shows the latest data.

You can view the background sync queue by clicking on the cloud icon (when offline) or the sync icon (when back online) in the status bar of Brezel.

Offline Resource Tables

Many requests are so specific that they cannot all be reasonably cached, such as paginated lists of entities. To accommodate this, the Brezel service worker caches all resource tables and entities requests it has seen in the api-nf-cache. Then, when you are offline, the service worker intercepts your API requests for resource tables and does the following:

  1. loads all entities from both the api-nf-cache and the api-queue background sync queue,
  2. applies pre_filters and filters,
  3. sorts,
  4. paginates and
  5. mocks the API table response with the result.

Because this happens in the service worker layer, the SPA does not know that the data is not coming from the API.

Emulating Offline Mode

You can emulate the offline mode in your browser by following these steps:

  1. Open the developer tools in your browser.
  2. Go to the “Application” tab.
  3. In the “Service Workers” section, check the “Offline” checkbox.
  4. Reload the page.