Skip to content

Integrate Service Worker ​

Purpose ​

This guide explains how to integrate the SDK’s built-in Service Worker in your application, resolve conflicts with your own Service Worker, and troubleshoot common issues.

Browsers allow multiple Service Workers per origin, but each must have a different scope. MessageWorker.js uses a scope (default /), so your application Service Worker cannot register at the same scope unless you merge it with MessageWorker.js when both must share one scope.

This section covers merging workers and customizing Service Worker registration options.

Service Worker overview ​

A Service Worker is a background script for offline support, push notifications, background sync, and more. After the page loads, it can intercept network requests, cache resources, and run other logic.

Common capabilities:

  • Offline: Cache resources for use without a network.
  • Push: Receive push messages from the server.
  • Background sync: Run tasks such as uploads or updates in the background.
  • Fetch interception: Handle requests (cache, modify headers, and so on).

How Foxit PDF SDK for Web uses Service Workers ​

The SDK uses a Service Worker to improve interaction and address related issues, including local font access permission and dynamic XFA JavaScript UI.

MessageWorker.js ​

MessageWorker.js is the SDK Service Worker used for synchronous messaging in the worker layer. Because it claims its own scope, merge it with your application Service Worker when you need the same scope.

Environment requirements ​

Before integrating:

  • Browser support: Chrome, Firefox, Edge, and others—see Can I use.

  • @foxitsoftware/foxit-pdf-sdk-for-web-library: Version 10.0.0 or later; lib must include MessageWorker.js.

  • HTTPS: Required in production; localhost and 127.0.0.1 are exceptions during development.

Registration and configuration ​

From 10.0.0, the PDFViewer constructor accepts messageSyncServiceWorker to control registration.

Two approaches:

  1. Specify url and options:

    • url — script URL to register.
    • options — registration options per MDN.
    javascript
    const viewer = new PDFViewer({
        messageSyncServiceWorker: {
            url: '/your-service-worker.js',
            options: { / Optional
                scope: '/foxit-lib/'
            }
        }
        / ... Other parameters
    })
  2. Specify registration:

    • registration — Promise<ServiceWorkerRegistration> from navigator.serviceWorker.register().
    javascript
    const viewer = new PDFViewer({
        messageSyncServiceWorker: {
            registration: navigator.serviceWorker.register('/your-service-worker.js', {
                scope: '/foxit-lib/'
            })
        }
        / ... Other parameters
    })

Method 1 lets the SDK choose when to register. Use method 2 if you register the Service Worker yourself.

See /examples/PDFViewCtrl/integrate-service-worker in the SDK package and its README to run the sample.

Service-Worker-Allowed response header ​

By default, maximum scope is limited by the script URL. For example, https://example.com/sub/worker.js can control only https://example.com/sub/ and below. Registering with a broader scope fails with:

The path of the provided scope ('/') is not under the max scope allowed ('/sub/').

To allow a wider scope, set the Service-Worker-Allowed response header on the Service Worker script.

Configure Service-Worker-Allowed ​

Add this header to the Service Worker script response; the value is the maximum allowed scope path:

http
Service-Worker-Allowed /;

Nginx example ​

Add the header in your Nginx config:

nginx
server {
    location /sw.js {
        add_header Service-Worker-Allowed /;
    }
}

Webpack Dev Server example ​

javascript
// webpack.config.js
module.exports = {
    //  Other configurations
    devServer: {
        headers: {
            'Service-Worker-Allowed': '/'
        }
    }
};

vue.config.js example ​

javascript
// vue.config.js
module.exports = {
    devServer: {
        headers: {
            'Service-Worker-Allowed': '/'
        }
    }
};

Special request URL ​

In your Service Worker fetch handler, ignore requests whose URL matches __foxitwebsdk-syncmsg__. See examples/PDFViewCtrl/integrate-service-worker/src/service-worker.js.

Troubleshooting ​

Service Worker not registered ​

Symptom ​

No Service Worker appears in DevTools.

Possible causes ​

  • Wrong path; script returns 404 or another error.
  • Browser does not support Service Workers.
  • HTTPS required except on localhost and 127.0.0.1.

Fix ​

  • Verify registration code and script path.
  • Check Can I use for browser support.
  • Serve over HTTPS in production.

Service Worker registration failed (scope) ​

Symptom ​

Registration fails because scope exceeds the maximum allowed path. Example:

text
register a ServiceWorker for scope ('http://localhost:9899/') with script ('http://localhost:9899/lib/MessageWorker.js?b=http://localhost:9899/__foxitwebsdk-syncmsg__'): The path of the provided scope ('/') is not under the max scope allowed ('/lib/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope.

Possible causes ​

Incorrect script path or scope. Maximum scope depends on the script URL (MDN).

Fix ​

  1. Understand scope rules.
  2. Review registration code and scope.
  3. Adjust scope.
  4. Set Service-Worker-Allowed for a wider scope.
  5. Verify script path and server configuration.

Unsupported MIME type ​

Symptom ​

unsupported MIME type ('***/***'). Example:

text
Failed to register a ServiceWorker for scope ('http://localhost:5173/assets/') with script ('http://localhost:5173/assets/service-worker.js'): The script has an unsupported MIME type ('text/html').

Possible causes ​

Wrong registration URL or missing file (server may return HTML with wrong MIME type).

Fix ​

  • Verify registration path and that the file exists.
  • Check server MIME type configuration.

Service Worker cannot intercept after hard refresh ​

Symptom ​

After a hard refresh (Shift + Refresh), per MDN: ServiceWorkerContainer.controller, the page may have no controller and navigator.serviceWorker.controller is null.

Possible causes ​

The SDK’s MessageWorker.js handles this case. If your worker does not reuse MessageWorker.js and does not handle hard refresh, fetches may not be intercepted.

Fix ​

  1. After registration, check whether navigator.serviceWorker.controller is null.
  2. If null, postMessage to the active worker, e.g. {id: 'clientsClaim'}.
  3. In the Service Worker, listen for that message and call clients.claim().

Simple examples:

js
const registration = await navigator.serviceWorker.register(
    "service-worker.js" /* ... more options */
);
if (!navigator.serviceWorker.controller && registration.active) {
    function onControllerChange() {
        navigator.serviceWorker.removeEventListener(
            "controllerchange",
            onControllerChange
        );
        if (navigator.serviceWorker.controller) {
            resolve(true);
        }
    }

    navigator.serviceWorker.addEventListener(
        "controllerchange",
        onControllerChange
    );
    registration.active.postMessage({id: "clientsClaim"});
}
const pdfViewer = new PDFViewCtrl.PDFViewer({
    messageSyncServiceWorker: {
        registration: registration,
    }
}
js
self.addEventListener("message", (e) => {
    if (e.data?.id === "clientsClaim") {
        / Set this service worker as controller for all clients in its scope
        clients.claim();
    }
});