bit Bswup

Preparing the app for offline use, please wait...

0%

bit platform logo Bswup
NuGet GitHub

Service Worker Settings

Everything you can configure in service-worker.js before importing the Bswup engine.

javascript
self.assetsInclude = [/\/data\.db$/];
self.assetsExclude = [/\.scp\.css$/, /weather\.json$/];
self.defaultUrl = '/';
self.prohibitedUrls = [/\/admin\//];
self.serverHandledUrls = [/\/api\//];
self.serverRenderedUrls = [/\/privacy$/];
self.externalAssets = [
    {
        "url": "/"
    },
    {
        "url": "https://www.googletagmanager.com/gtag/js?id=G-G123456789"
    }
];
self.assetsUrl = '/service-worker-assets.js';
self.noPrerenderQuery = 'no-prerender=true';
self.cacheVersion = '2026.05.31-abc1234';

self.caseInsensitiveUrl = true;
self.ignoreDefaultInclude = true;
self.ignoreDefaultExclude = true;
self.isPassive = true;
self.enableIntegrityCheck = true;
self.enableDiagnostics = true;
self.enableFetchDiagnostics = true;

self.importScripts('_content/Bit.Bswup/bit-bswup.sw.js');

The most important line is the last one - the only mandatory config in this file:

javascript
self.importScripts('_content/Bit.Bswup/bit-bswup.sw.js');
Security: the service worker is part of your trusted base

Unlike the assets in service-worker-assets.js (which Bswup verifies with Subresource Integrity), the service worker script itself cannot be integrity-pinned: browsers support neither an integrity option on register() nor SRI for importScripts(). A tampered service-worker.js or bit-bswup.sw.js is effectively persistent, fully-privileged XSS. Serve both over HTTPS from an origin you control and apply a strict Content-Security-Policy.

Bswup registers with updateViaCache: 'none' so update checks bypass the HTTP cache for the whole service-worker.jsbit-bswup.sw.jsservice-worker-assets.js import chain. As defense-in-depth (support is uneven on older Safari/iOS, and proxies are not bound by it), also send Cache-Control: no-cache for these two files so every fetch revalidates against the origin.

How the URL-matching lists are matched

assetsInclude, assetsExclude, prohibitedUrls, serverHandledUrls and serverRenderedUrls all accept the same two kinds of entry:

  • a RegExp (e.g. /\/admin\//) is used as the pattern it is - what you want for anything non-trivial;
  • a string (e.g. '/admin/') is matched literally as a substring of the URL. It is regex-escaped, so 'v1.0' matches only v1.0 and never v1X0.
Strings are substring matches
'app.css' matches /css/app.css anywhere in the URL; anchor with a RegExp such as /\/app\.css$/ if that is too broad. Prefer a RegExp whenever you need anchoring, alternation or wildcards. Also note: before v-10-6-0 string entries were silently ignored - see the migration guide.

Asset selection

assetsInclude

The list of file names from the assets list to include when Bswup stores them in cache storage (regex supported).

assetsExclude

The list of file names from the assets list to exclude when Bswup stores them in cache storage (regex supported).

ignoreDefaultInclude / ignoreDefaultExclude

Ignore the default include / exclude arrays Bswup provides. The defaults are:

javascript
[/\.dll$/, /\.wasm/, /\.pdb/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/,
 /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/, /\.svg$/, /\.woff2$/, /\.ttf$/, /\.webp$/]

/\.wasm/, /\.pdb/ and /\.html/ are deliberately unanchored (mirroring the standard Blazor template), so variants such as foo.wasm.br also match. The default excludes keep the service worker's own scripts out of the cache:

javascript
[
    /^_content\/Bit\.Bswup\/bit-bswup\.sw\.js$/,
    /^_content\/Bit\.Bswup\/bit-bswup\.sw\.min\.js$/,
    /^_content\/Bit\.Bswup\/bit-bswup\.sw-cleanup\.js$/,
    /^_content\/Bit\.Bswup\/bit-bswup\.sw-cleanup\.min\.js$/,
    /^service-worker\.js$/,
]
Never cache service worker files
Caching service-worker-related files corrupts the update cycle of the service worker. Only the browser should handle these files.

externalAssets

The list of external assets to cache that are not included in the auto-generated assets file. For example, if you're not using index.html (like _host.cshtml), add { "url": "/" }.

javascript
self.externalAssets = [
    { "url": "/" },                                    // the host page itself (e.g. _host.cshtml)
    "https://fonts.example.com/app-font.woff2",        // bare string shorthand
    { "url": /_framework\/resource-collection\..*\.js/ }, // RegExp for server-generated names
    { "url": "/lib/chart.js", "hash": "sha256-..." }    // with SRI hash (cache busting + integrity)
];

Accepted entry shapes and behaviors:

  • An object with a url (a concrete string, or a RegExp for server-generated names unknown ahead of time), a bare string, or a bare RegExp; a single value also works without the array.
  • An entry may carry a hash (an SRI digest, sha256-...) that participates in ?v= cache busting and - when enableIntegrityCheck is on - in integrity verification, exactly like a manifest asset.
  • Entries whose url cannot be parsed are skipped with a non-fatal request error instead of breaking the worker.
  • Cross-origin entries are fetched in CORS mode first; when the host sends no CORS headers, Bswup retries with no-cors and caches the resulting opaque response so the asset still works offline. This fallback is skipped for integrity-checked assets. Browsers pad opaque responses in quota accounting (Chromium reserves several megabytes per entry), so prefer CORS-enabled hosts when you control them.
  • Media works too: requests carrying a Range header are answered with a real 206 Partial Content sliced from the cached full body (Safari refuses media served as 200 for a ranged request); uncached ranged requests pass through with their Range intact, and partial responses are never written to the cache.
  • Entries cached for RegExp patterns are kept across updates so the app still boots offline, but only the newest three generations per pattern survive each update.

Navigation & URLs

defaultUrl

The default page URL, served from cache for navigation requests (the SPA fallback). Defaults to index.html; use / when using _Host.cshtml. The value must match an entry that actually exists in service-worker-assets.js or externalAssets; the comparison uses resolved URLs, so equivalent spellings match. When nothing matches, offline navigation cannot work and Bswup logs a defaultUrl ... matches no asset warning at startup.

  • Navigations whose URL is itself a managed asset are served that asset instead of the default document (changed in v-10-6-0): opening /manifest.json directly shows that file, while route URLs (/counter, ...) still get the app shell.
  • If your host answers the shell URL with a redirect (e.g. //index.html, common on Cloudflare Pages and Netlify), Bswup rebuilds that response so offline deep-link navigation keeps working instead of failing with a redirect-mode error.

assetsUrl

The path of the compile-time assets manifest (default file name service-worker-assets.js). The default is resolved relative to the service worker script's own location - which is also where Blazor publishes the file - so it works unchanged for apps mounted on a sub-path. Set it explicitly only when the file lives somewhere else; a leading / makes the path origin-absolute.

prohibitedUrls

URLs that should not be accessed (regex supported). Matching requests are answered by the service worker with 403 Forbidden for every HTTP method (changed in v-10-6-0 - previously 405).

A convenience, not a security boundary
Enforcement happens only inside the service worker, which is bypassed whenever the page is not controlled (the very first visit, a hard reload, browsers without service worker support) and by any client that talks to the server directly. Access control must be enforced on the server.

serverHandledUrls

URLs that skip the service worker offline pipeline entirely and are handled only by the server (regex supported) - e.g. /api, /swagger.

serverRenderedUrls

URLs that should be rendered by the server rather than the client while navigating (regex supported) - e.g. /about.html, /privacy.

caseInsensitiveUrl

Enables case-insensitive URL checking - for asset cache matching and every URL-matching regex list: when enabled, patterns are compiled with the i flag so e.g. prohibitedUrls: [/\/admin\//] also blocks /ADMIN/.

noPrerenderQuery

The query string attached to the default document request to disable server prerendering, so an unwanted prerendered result is not cached - e.g. no-prerender=true.

forcePrerender

Forces prerendering of the default document for every navigation request to ensure the server always has the latest version of the app. Useful for server-rendered apps.

Install behavior & resiliency

isPassive

Enables passive mode: assets are not cached in advance but upon first request. Passive mode does not skip the full download entirely - on a first install, once Blazor has started, the service worker still tops up the cache in the background with every asset not yet fetched, so the app ends up fully offline-capable. What passive mode buys is that the first paint is never blocked behind a full precache. Assets lazily fetched by the app while the top-up runs can be downloaded twice in that window - a bandwidth cost, not a correctness issue.

errorTolerance

Controls how the service worker reacts to asset download / cache failures during install:

ValueBehavior
lax (default) Best-effort install. Asset failures never fail the install; missing assets are filled in lazily on first fetch. Failures are reported through the error event with fatal: false and still count toward progress so the bar reaches 100%. Tolerates optional externalAssets that may legitimately 404, and avoids leaving a first visit with no service worker to complete the startup handshake. The download runs under the install event's waitUntil, so updateReady is only announced once the background fill has settled.
strict Mirrors the standard Microsoft template / Workbox behavior. If any required asset fails, the install rejects, the partial cache is discarded, and the previous service worker (if any) keeps serving. Failed assets are not counted toward progress, so 100% means every asset succeeded; the abort is reported with reason: 'install-aborted' and fatal: true. On a first install (no previous version to fall back to) Bswup starts the app without a service worker so it still boots, and the install is retried on the next load.

maxRetries / retryDelay

maxRetries (default 2) is the number of additional download attempts after the first when an asset fails transiently during install (a rejected fetch, or HTTP 408/429/5xx). Deterministic failures - 404/403 and other permanent statuses, and SRI mismatches - are never retried, since identical bytes would fail identically.

retryDelay (default 300) is the base backoff in milliseconds: attempt n waits retryDelay * 2^(n-1) plus random jitter, so a mass failure doesn't re-hit the origin in one synchronized burst.

enableIntegrityCheck

Enables the browsers' built-in integrity verification by setting the integrity attribute on the requests the service worker creates to fetch assets.

Caching & updates

cacheVersion

Overrides the value used to name the cache bucket (bit-bswup:<scope-path> - <version>). By default this tracks Blazor's assetsManifest.version (a hash over the published assets), so the cache rotates automatically whenever any asset hash changes - and only then. Set it to take manual control:

  • Pin it to a stable string so noisy dev rebuilds don't needlessly evict the whole cache.
  • Bump it to force a refresh when a meaningful change lives outside Blazor's asset manifest.
  • Feed it a build-stamped value (commit SHA, build timestamp) so it bumps automatically per publish.

Only the cache bucket name is affected: per-asset ?v= cache busting and Subresource Integrity keep using each asset's own hash.

disableHashlessAssetsUpdate

Disables the automatic re-download of hash-less assets (e.g. external assets) that Bswup performs every time an update is found.

enableCacheControl

Adds cache-busting to each asset request (cache: 'no-store' plus a cache-control: no-cache header). The header is only attached to same-origin requests: it is not CORS-safelisted, so on a cross-origin asset it would force a preflight most third-party hosts reject; cross-origin requests rely on the cache: no-store option alone.

Diagnostics

  • enableDiagnostics: pushes service worker logs to the browser console.
  • enableFetchDiagnostics: additionally logs every fetch event the worker handles.

Modes

A mode is a preset bundle of defaults for the individual settings above (isPassive, defaultUrl, forcePrerender, errorTolerance, caseInsensitiveUrl, noPrerenderQuery): it only fills settings you have not assigned yourself, so any explicit assignment always wins over the preset - including explicit falsy values such as caseInsensitiveUrl = false.

ModeBehavior
NoPrerenderDisables prerendering of the default document for every navigation request.
InitialPrerenderEnables prerendering of the default document only for the initial navigation request.
AlwaysPrerenderEnables prerendering of the default document for every navigation request.
FullOfflineFull offline mode: all assets are cached and served from cache from the first time the app loads.