Skip to content

Commit 2acfae1

Browse files
committed
refactor: extract shims into separate file
1 parent 1ec8203 commit 2acfae1

File tree

2 files changed

+65
-57
lines changed

2 files changed

+65
-57
lines changed

packages/runtime/src/helpers/edge.ts

Lines changed: 6 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { resolve, join } from 'path'
44
import type { NetlifyConfig, NetlifyPluginConstants } from '@netlify/build'
55
import { greenBright } from 'chalk'
66
import destr from 'destr'
7-
import { copy, copyFile, emptyDir, ensureDir, readJSON, readJson, writeJSON, writeJson } from 'fs-extra'
7+
import { copy, copyFile, emptyDir, ensureDir, readJSON, writeJSON, writeJson } from 'fs-extra'
88
import type { PrerenderManifest } from 'next/dist/build'
99
import type { MiddlewareManifest } from 'next/dist/build/webpack/plugins/middleware-plugin'
1010
import type { RouteHas } from 'next/dist/lib/load-custom-routes'
@@ -68,7 +68,7 @@ export interface FunctionManifest {
6868

6969
const maybeLoadJson = <T>(path: string): Promise<T> | null => {
7070
if (existsSync(path)) {
71-
return readJson(path)
71+
return readJSON(path)
7272
}
7373
}
7474
export const isAppDirRoute = (route: string, appPathRoutesManifest: Record<string, string> | null): boolean =>
@@ -88,60 +88,6 @@ export const loadPrerenderManifest = (netlifyConfig: NetlifyConfig): Promise<Pre
8888
*/
8989
const sanitizeName = (name: string) => `next_${name.replace(/\W/g, '_')}`
9090

91-
/**
92-
* Initialization added to the top of the edge function bundle
93-
*/
94-
const preamble = /* js */ `
95-
import {
96-
decode as _base64Decode,
97-
} from "https://deno.land/std@0.175.0/encoding/base64.ts";
98-
99-
import { AsyncLocalStorage } from "https://deno.land/std@0.175.0/node/async_hooks.ts";
100-
101-
// Deno defines "window", but naughty libraries think this means it's a browser
102-
delete globalThis.window
103-
globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT_PRIVATE_MINIMAL_MODE': '1' } }
104-
globalThis.EdgeRuntime = "netlify-edge"
105-
let _ENTRIES = {}
106-
107-
// Next.js expects this as a global
108-
globalThis.AsyncLocalStorage = AsyncLocalStorage
109-
110-
// Next.js uses this extension to the Headers API implemented by Cloudflare workerd
111-
if(!('getAll' in Headers.prototype)) {
112-
Headers.prototype.getAll = function getAll(name) {
113-
name = name.toLowerCase();
114-
if (name !== "set-cookie") {
115-
throw new Error("Headers.getAll is only supported for Set-Cookie");
116-
}
117-
return [...this.entries()]
118-
.filter(([key]) => key === name)
119-
.map(([, value]) => value);
120-
};
121-
}
122-
// Next uses blob: urls to refer to local assets, so we need to intercept these
123-
const _fetch = globalThis.fetch
124-
const fetch = async (url, init) => {
125-
try {
126-
if (typeof url === 'object' && url.href?.startsWith('blob:')) {
127-
const key = url.href.slice(5)
128-
if (key in _ASSETS) {
129-
return new Response(_base64Decode(_ASSETS[key]))
130-
}
131-
}
132-
return await _fetch(url, init)
133-
} catch (error) {
134-
console.error(error)
135-
throw error
136-
}
137-
}
138-
139-
// Next edge runtime uses "self" as a function-scoped global-like object, but some of the older polyfills expect it to equal globalThis
140-
// See https://nextjs.org/docs/basic-features/supported-browsers-features#polyfills
141-
const self = { ...globalThis, fetch }
142-
143-
`
144-
14591
// Slightly different spacing in different versions!
14692
const IMPORT_UNSUPPORTED = [
14793
`Object.defineProperty(globalThis,"__import_unsupported"`,
@@ -158,7 +104,10 @@ const getMiddlewareBundle = async ({
158104
netlifyConfig: NetlifyConfig
159105
}): Promise<string> => {
160106
const { publish } = netlifyConfig.build
161-
const chunks: Array<string> = [preamble]
107+
108+
const shims = await fs.readFile(getEdgeTemplatePath('shims.ts'), 'utf8')
109+
110+
const chunks: Array<string> = [shims]
162111

163112
chunks.push(`export const _DEFINITION = ${JSON.stringify(edgeFunctionDefinition)}`)
164113

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// deno-lint-ignore-file no-var prefer-const no-unused-vars no-explicit-any
2+
import { decode as _base64Decode } from 'https://deno.land/std@0.175.0/encoding/base64.ts'
3+
import { AsyncLocalStorage as ALSCompat } from 'https://deno.land/std@0.175.0/node/async_hooks.ts'
4+
5+
/**
6+
* These are the shims, polyfills and other kludges to make Next.js work in standards-compliant runtime.
7+
* This file isn't imported, but is instead inlined along with other chunks into the edge bundle.
8+
*/
9+
10+
declare global {
11+
var process: {
12+
env: Record<string, string>
13+
}
14+
var EdgeRuntime: string
15+
var AsyncLocalStorage: typeof ALSCompat
16+
var _ASSETS: Record<string, string>
17+
}
18+
19+
// Deno defines "window", but naughty libraries think this means it's a browser
20+
delete (globalThis as Omit<typeof globalThis, 'window'> & Pick<Partial<typeof globalThis>, 'window'>).window
21+
globalThis.process = {
22+
env: { ...Deno.env.toObject(), NEXT_RUNTIME: 'edge', NEXT_PRIVATE_MINIMAL_MODE: '1' },
23+
}
24+
globalThis.EdgeRuntime = 'netlify-edge'
25+
let _ENTRIES = {}
26+
27+
// Next.js expects this as a global
28+
globalThis.AsyncLocalStorage = ALSCompat
29+
30+
// Next.js uses this extension to the Headers API implemented by Cloudflare workerd
31+
if (!('getAll' in Headers.prototype)) {
32+
;(Headers as any).prototype.getAll = function getAll(name: string) {
33+
name = name.toLowerCase()
34+
if (name !== 'set-cookie') {
35+
throw new Error('Headers.getAll is only supported for Set-Cookie')
36+
}
37+
return [...this.entries()].filter(([key]) => key === name).map(([, value]) => value)
38+
}
39+
}
40+
// Next uses blob: urls to refer to local assets, so we need to intercept these
41+
const _fetch = globalThis.fetch
42+
const fetch: typeof globalThis.fetch = async (url, init) => {
43+
try {
44+
if (url instanceof URL && url.href?.startsWith('blob:')) {
45+
const key = url.href.slice(5)
46+
if (key in _ASSETS) {
47+
return new Response(_base64Decode(_ASSETS[key]))
48+
}
49+
}
50+
return await _fetch(url, init)
51+
} catch (error) {
52+
console.error(error)
53+
throw error
54+
}
55+
}
56+
57+
// Next edge runtime uses "self" as a function-scoped global-like object, but some of the older polyfills expect it to equal globalThis
58+
// See https://nextjs.org/docs/basic-features/supported-browsers-features#polyfills
59+
const self = { ...globalThis, fetch }

0 commit comments

Comments
 (0)