Skip to content

Commit

Permalink
fix: transfer response buffer on safari
Browse files Browse the repository at this point in the history
  • Loading branch information
kettanaito committed Oct 15, 2023
1 parent 595d6f3 commit 92c7ecc
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/browser/setupWorker/glossary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export type ServiceWorkerOutgoingEventTypes =
| 'CLIENT_CLOSED'

export interface StringifiedResponse extends ResponseInit {
body: string | ReadableStream<Uint8Array> | null
body: string | ArrayBuffer | ReadableStream<Uint8Array> | null
}

/**
Expand Down
32 changes: 22 additions & 10 deletions src/browser/setupWorker/start/createRequestListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { handleRequest } from '~/core/utils/handleRequest'
import { RequiredDeep } from '~/core/typeUtils'
import { devUtils } from '~/core/utils/internal/devUtils'
import { toResponseInit } from '~/core/utils/toResponseInit'
import { supportsReadableStreamTransfer } from '../../utils/supportsReadableStreamTransfer'

export const createRequestListener = (
context: SetupWorkerInternalContext,
Expand Down Expand Up @@ -47,18 +48,29 @@ export const createRequestListener = (
// ".log()" method of the request handler.
const responseClone = response.clone()
const responseInit = toResponseInit(response)
const responseStream = responseClone.body

messageChannel.postMessage(
'MOCK_RESPONSE',
{
/**
* @note Safari doesn't support transferring a "ReadableStream".
* Check that the browser supports that before sending it to the worker.
*/
if (supportsReadableStreamTransfer()) {
const responseStream = response.body
messageChannel.postMessage(
'MOCK_RESPONSE',
{
...responseInit,
body: responseStream,
},
responseStream ? [responseStream] : undefined,
)
} else {
// As a fallback, send the response body buffer to the worker.
const responseBuffer = await responseClone.arrayBuffer()
messageChannel.postMessage('MOCK_RESPONSE', {
...responseInit,
body: responseStream,
},
// Transfer response's buffer so it could
// be sent over to the worker.
responseStream ? [responseStream] : undefined,
)
body: responseBuffer,
})
}

if (!options.quiet) {
context.emitter.once('response:mocked', ({ response }) => {
Expand Down
17 changes: 17 additions & 0 deletions src/browser/utils/supportsReadableStreamTransfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Returns a boolean indicating whether the current browser
* supports `ReadableStream` as a `Transferable` when posting
* messages.
*/
export function supportsReadableStreamTransfer() {
try {
const stream = new ReadableStream({
start: (controller) => controller.close(),
})
const message = new MessageChannel()
message.port1.postMessage(stream, [stream])
return true
} catch (error) {
return false
}
}

0 comments on commit 92c7ecc

Please sign in to comment.