From de7827ee279c84285ac72deb5badd80bcca4d00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Fri, 11 Oct 2024 10:11:52 +0900 Subject: [PATCH] fix(service-worker): bind fetch to `globalThis` (#3500) * fix(service-worker): bind fetch to `globalThis` * chore: ignore lint error --- src/adapter/service-worker/handler.test.ts | 38 ++++++++++++++++++++++ src/adapter/service-worker/handler.ts | 4 +-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/adapter/service-worker/handler.test.ts b/src/adapter/service-worker/handler.test.ts index ae44a824..f9f2bb67 100644 --- a/src/adapter/service-worker/handler.test.ts +++ b/src/adapter/service-worker/handler.test.ts @@ -2,6 +2,31 @@ import { Hono } from '../../hono' import { handle } from './handler' import type { FetchEvent } from './types' +beforeAll(() => { + // fetch errors when it's not bound to globalThis in service worker + // set a fetch stub to emulate that behavior + vi.stubGlobal( + 'fetch', + function fetch(this: undefined | typeof globalThis, arg0: string | Request) { + if (this !== globalThis) { + const error = new Error( + // eslint-disable-next-line quotes + "Failed to execute 'fetch' on 'WorkerGlobalScope': Illegal invocation" + ) + error.name = 'TypeError' + throw error + } + if (arg0 instanceof Request && arg0.url === 'http://localhost/fallback') { + return new Response('hello world') + } + return Response.error() + } + ) +}) +afterAll(() => { + vi.unstubAllGlobals() +}) + describe('handle', () => { it('Success to fetch', async () => { const app = new Hono() @@ -20,6 +45,19 @@ describe('handle', () => { expect(json).toStrictEqual({ hello: 'world' }) }) it('Fallback 404', async () => { + const app = new Hono() + const handler = handle(app) + const text = await new Promise((resolve) => { + handler({ + request: new Request('http://localhost/fallback'), + respondWith(res) { + resolve(res) + }, + } as FetchEvent) + }).then((res) => res.text()) + expect(text).toBe('hello world') + }) + it('Fallback 404 with explicit fetch', async () => { const app = new Hono() const handler = handle(app, { async fetch() { diff --git a/src/adapter/service-worker/handler.ts b/src/adapter/service-worker/handler.ts index a85d6d61..3b255e8d 100644 --- a/src/adapter/service-worker/handler.ts +++ b/src/adapter/service-worker/handler.ts @@ -16,8 +16,8 @@ export const handle = ( opts: { fetch?: typeof fetch } = { - // To use `fetch` on a Service Worker correctly, first refer to `self.fetch`. - fetch: globalThis.self !== undefined ? globalThis.self.fetch : fetch, + // To use `fetch` on a Service Worker correctly, bind it to `globalThis`. + fetch: globalThis.fetch.bind(globalThis), } ): Handler => { return (evt) => {