Replies: 3 comments 14 replies
-
/// <reference lib="WebWorker" />
import { json } from "@remix-run/node";
export type {};
declare let self: ServiceWorkerGlobalScope;
function debug(...messages: unknown[]): void {
if (process.env.NODE_ENV === "development") {
console.debug(...messages);
}
}
const STATIC_ASSETS = ["/build/", "/icons/", "/"];
const ASSET_CACHE = "asset-cache";
const DATA_CACHE = "data-cache";
const DOCUMENT_CACHE = "document-cache";
function isMethod(request: Request, methods: string[]): boolean {
return methods.includes(request.method.toLowerCase());
}
function isAssetRequest(request: Request): boolean {
return (
isMethod(request, ["get"]) &&
STATIC_ASSETS.some((publicPath) => request.url.startsWith(publicPath))
);
}
function isLoaderRequest(request: Request): string | false | null {
const url = new URL(request.url);
return isMethod(request, ["get"]) && url.searchParams.get("_data");
}
function isDocumentGetRequest(request: Request): boolean {
return isMethod(request, ["get"]) && request.mode === "navigate";
}
async function handleFetch(event: FetchEvent): Promise<Response> {
const url = new URL(event.request.url);
if (isAssetRequest(event.request)) {
const cached = await caches.match(event.request, {
cacheName: ASSET_CACHE,
ignoreVary: true,
ignoreSearch: true,
});
if (cached) {
debug("Serving asset from cache", url.pathname);
return cached;
}
debug("Serving asset from network", url.pathname);
const response = await fetch(event.request);
if (response.status === 200) {
const cache = await caches.open(ASSET_CACHE);
await cache.put(event.request, response.clone());
}
return response;
}
if (isLoaderRequest(event.request)) {
try {
debug("Serving data from network", url.pathname + url.search);
const response = await fetch(event.request.clone());
const cache = await caches.open(DATA_CACHE);
await cache.put(event.request, response.clone());
return response;
} catch (error) {
debug(
"Serving data from network failed, falling back to cache",
url.pathname + url.search
);
const response = await caches.match(event.request);
if (response) {
response.headers.set("X-Remix-Worker", "yes");
return response;
}
return json(
{ message: "Network Error" },
{
status: 500,
headers: { "X-Remix-Catch": "yes", "X-Remix-Worker": "yes" },
}
);
}
}
if (isDocumentGetRequest(event.request)) {
try {
debug("Serving document from network", url.pathname);
const response = await fetch(event.request);
const cache = await caches.open(DOCUMENT_CACHE);
await cache.put(event.request, response.clone());
return response;
} catch (error) {
debug(
"Serving document from network failed, falling back to cache",
url.pathname
);
const response = await caches.match(event.request);
if (response) {
return response;
}
throw error;
}
}
return fetch(event.request.clone());
}
self.addEventListener("fetch", (event) => {
event.respondWith(
(async () => {
const result = {} as
| { error: unknown; response: Response }
| { error: undefined; response: Response };
try {
result.response = await handleFetch(event);
} catch (error) {
result.error = error;
}
return appHandleFetch(event, result);
})()
);
});
async function appHandleFetch(
event: FetchEvent,
{
error,
response,
}:
| { error: unknown; response: Response }
| { error: undefined; response: Response }
): Promise<Response> {
return response;
} |
Beta Was this translation helpful? Give feedback.
-
Interesting and weird, ran my app with the same command and it ran just fine. |
Beta Was this translation helpful? Give feedback.
-
The answer was embedded in a sea of replies, so here it is |
Beta Was this translation helpful? Give feedback.
-
Hello, I am using your code as a guideline to add a SW to my app. As of right now, I copied your
entry.worker.ts
file and rannpx esbuild ./app/entry.worker.ts --outfile=./public/entry.worker.js --bundle --format=esm --define:process.env.NODE_ENV='development' --platform=node
but when I turn on my dev server I get the following error:Beta Was this translation helpful? Give feedback.
All reactions