UNPKG

@fleek-platform/next-on-fleek

Version:

`@fleek-platform/next-on-fleek` is a CLI tool that you can use to build and develop [Next.js](https://nextjs.org/) applications so that they can run on [Fleek Functions](https://fleek.xyz/docs/platform/fleek-functions/).

92 lines (84 loc) 3.05 kB
/** * The next-on-pages worker needs to isolate the global scope for each route, they all sharing the same global scope * allows for race conditions and incorrect behaviors (see: https://github.com/fleek-platform/next-on-fleek/issues/805) * * So we set up an isolation system in which each route can access a proxy to the global scope that is route-specific, * they can do that by calling `globalThis.getProxyFor(route)`. * * The following function sets up such utility alongside a map that is used to store the various proxies. */ export function setupRoutesIsolation() { globalThis.__nextOnPagesRoutesIsolation ??= { _map: new Map(), getProxyFor, }; } /** * Utility to retrieve a route-specific proxy to the global scope, if the proxy doesn't yet exist it gets created * by the function. * * @param route the target route * @returns the proxy for the route */ function getProxyFor(route: string) { const existingProxy = globalThis.__nextOnPagesRoutesIsolation._map.get(route); if (existingProxy) { return existingProxy; } const newProxy = createNewRouteProxy(); globalThis.__nextOnPagesRoutesIsolation._map.set(route, newProxy); return newProxy; } /** * Creates a new route-specific proxy to the global scope. * * How the proxy works: setters on the proxy don't set the values to the actual global scope but * in an internal map specific to the proxy. getters retrieve values from such internal map, and * fall back to the actual global scope for values not present in such map. * * This makes it so that routes trying to modify the global scope will, though this proxy, work * exactly like if they were actually updating the global scope, but without actually doing so, * thus not effecting any other route. * * Note: this does not account for routes trying to update already existing objects in the global * scope (e.g. `globalScope.existing_field.x = 123`), fortunately such granular control doesn't * seem necessary in next-on-pages. * * @returns the created proxy. */ function createNewRouteProxy() { const overrides = new Map<string | symbol, unknown>(); return new Proxy(globalThis, { get: (_, property) => { if (overrides.has(property)) { return overrides.get(property); } return Reflect.get(globalThis, property); }, set: (_, property, value) => { if (sharedGlobalProperties.has(property)) { // this property should be shared across all routes return Reflect.set(globalThis, property, value); } overrides.set(property, value); return true; }, }); } /** * There are some properties that do need to be shared across all different routes, so we collect * them in this set and skip the global scope proxying for them */ const sharedGlobalProperties = new Set<string | symbol>([ '_nextOriginalFetch', 'fetch', '__incrementalCache', ]); type RoutesIsolation = { _map: Map<string, unknown>; getProxyFor: (route: string) => unknown; }; declare global { // eslint-disable-next-line no-var var __nextOnPagesRoutesIsolation: RoutesIsolation; }