Joe Pea b960519608
feat: output type definitions, and allow new Docsify(opts) to accept options for ESM usage (#2392)
This `new Docsify(opts)` API can be safely converted to a Custom Element constructor with backwards compatibility later.
2025-12-03 21:49:44 -08:00

100 lines
2.8 KiB
JavaScript

// The purpose of this service worker is to help with loading
// node_modules modules when using ES modules in the browser.
//
// Specifically, this service worker helps with non-standard module paths
// that do not include file extensions, such as:
//
// /node_modules/some-lib/foo/bar
// /node_modules/some-lib/foo/bar/
//
// In these cases, the service worker will try to resolve them to actual files
// by appending ".js" or "/index.js" as needed.
//
// This service worker only handles requests under /node_modules/.
// All other requests are passed through unmodified.
export {};
const scope = /** @type {ServiceWorkerGlobalScope} */ (
/** @type {any} */ (self)
);
scope.addEventListener('install', event => {
// Always activate worker immediately, for purposes of testing.
event.waitUntil(scope.skipWaiting());
});
scope.addEventListener('activate', event => {
// Always activate worker immediately, for purposes of testing.
event.waitUntil(scope.clients.claim());
});
scope.addEventListener('fetch', event => {
const url = new URL(event.request.url);
// Don't handle non-node_modules paths
if (!url.pathname.startsWith('/node_modules/')) {
event.respondWith(fetch(url.href));
return;
}
// 6
// Special handling for non-standard module paths in node_modules
const parts = url.pathname.split('/');
const fileName = /** @type {string} */ (parts.pop());
const ext = fileName.includes('.') ? fileName.split('.').pop() : '';
// Handle imports like 'some-lib/foo/bar' without an extension.
if (fileName !== '' && ext === '') {
event.respondWith(
// eslint-disable-next-line no-async-promise-executor
new Promise(async resolve => {
try {
// First try adding .js
const response = await tryJs();
const mimeType = response.headers.get('Content-Type') || '';
if (response.ok && mimeType.includes('javascript')) {
resolve(response);
} else {
throw new Error('Not JS');
}
} catch {
// If that fails, try adding /index.js
resolve(await tryIndexJs());
}
async function tryJs() {
const tryJs = new URL(url);
tryJs.href += '.js';
const response = await fetch(tryJs);
return response;
}
async function tryIndexJs() {
const tryIndexJs = new URL(url);
tryIndexJs.href += '/index.js';
const response = await fetch(tryIndexJs);
return response;
}
}),
);
return;
}
// Handle imports like 'some-lib/foo/bar/' (ending with a slash).
if (fileName === '') {
// adding index.js
const tryIndexJs = new URL(url);
tryIndexJs.href += 'index.js';
event.respondWith(fetch(tryIndexJs));
return;
}
// For all other cases, just fetch normally.
event.respondWith(fetch(url));
});