-
Notifications
You must be signed in to change notification settings - Fork 127
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
improve bundled assets handling (#325)
- Loading branch information
1 parent
76a8bb4
commit 619beea
Showing
7 changed files
with
178 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
'@cloudflare/next-on-pages': patch | ||
--- | ||
|
||
bundle assets produced by the Vercel build and make them accessible via fetch | ||
|
||
Vercel/Next can allow access binary assets bundled with their edge functions in the following manner: | ||
|
||
``` | ||
const font = fetch(new URL('../../assets/asset-x', import.meta.url)).then( | ||
(res) => res.arrayBuffer(), | ||
); | ||
``` | ||
|
||
As you can see in this `@vercel/og` example: | ||
https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation/og-image-examples#using-a-custom-font | ||
|
||
This sort of access to bindings is necessary for the `@vercel/og` package to work and might be used in other packages | ||
as well, so it is something that we need to support. | ||
We do so by making sure that we properly bind the assets found in the Vercel build output into our worker | ||
and that fetches to such assets (using blob urls) are correctly handled (this requires us to patch the global `fetch` function) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
packages/next-on-pages/templates/_worker.js/utils/fetch.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
export function patchFetchToAllowBundledAssets(): void { | ||
const flagSymbol = Symbol.for('next-on-pages bundled assets fetch patch'); | ||
|
||
const alreadyPatched = ( | ||
globalThis.fetch as unknown as { [flagSymbol]: boolean } | ||
)[flagSymbol]; | ||
if (alreadyPatched) { | ||
return; | ||
} | ||
|
||
applyPatch(); | ||
|
||
(globalThis.fetch as unknown as { [flagSymbol]: boolean })[flagSymbol] = true; | ||
} | ||
|
||
function applyPatch() { | ||
const originalFetch = globalThis.fetch; | ||
globalThis.fetch = async (...args) => { | ||
const request = new Request(...args); | ||
|
||
if (request.url.startsWith('blob:')) { | ||
try { | ||
const url = new URL(request.url); | ||
const binaryContent = ( | ||
await import(`./__next-on-pages-dist__/assets/${url.pathname}.bin`) | ||
).default; | ||
|
||
// Note: we can't generate a real Response object here because this fetch might be called | ||
// at the top level of a dynamically imported module, and such cases produce the following | ||
// error: | ||
// Some functionality, such as asynchronous I/O, timeouts, and generating random values, | ||
// can only be performed while handling a request | ||
// this is a somewhat known workerd behavior (currently kept for security and performance reasons) | ||
// | ||
// if the above issue/constraint were to change we should replace the following with a real Response object | ||
const resp = { | ||
async arrayBuffer() { | ||
return binaryContent; | ||
}, | ||
get body(): ReadableStream<unknown> | null { | ||
return new ReadableStream({ | ||
start(controller) { | ||
return pump(); | ||
function pump() { | ||
const b = Buffer.from(binaryContent); | ||
controller.enqueue(b); | ||
controller.close(); | ||
return pump(); | ||
} | ||
}, | ||
}); | ||
}, | ||
async text() { | ||
const b = Buffer.from(binaryContent); | ||
return b.toString(); | ||
}, | ||
async json() { | ||
const b = Buffer.from(binaryContent); | ||
return JSON.stringify(b.toString()); | ||
}, | ||
async blob() { | ||
return new Blob(binaryContent); | ||
}, | ||
} as Response; | ||
|
||
// Note: clone is necessary so that body does work | ||
resp.clone = (): Response => { | ||
return resp; | ||
}; | ||
|
||
return resp; | ||
} catch { | ||
/* empty, let's just fallback to the original fetch */ | ||
} | ||
} | ||
|
||
return originalFetch(request); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters