From 78a9d90baa45d2f406f446b3ee4a0bddbfb1a465 Mon Sep 17 00:00:00 2001 From: "C. Lewis" Date: Sat, 2 Oct 2021 11:42:28 -0500 Subject: [PATCH 1/4] feat(server): isolate component modules --- packages/next/server/require.ts | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/next/server/require.ts b/packages/next/server/require.ts index 7e3fcd06179e1..9cce12943f853 100644 --- a/packages/next/server/require.ts +++ b/packages/next/server/require.ts @@ -1,3 +1,4 @@ +import { createContext, runInNewContext } from 'vm' import { promises } from 'fs' import { join } from 'path' import { @@ -6,10 +7,32 @@ import { SERVERLESS_DIRECTORY, FONT_MANIFEST, } from '../shared/lib/constants' + import { normalizePagePath, denormalizePagePath } from './normalize-page-path' import { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin' import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path' +/** + * `require(...)` a module within an isolated VM context, which prevents the + * module from sharing the same context as Next and potentially contaminating + * Next's own logic (i.e., by shimming globals). + * + * This should be used to load all React components for SSR. + * @see requirePage + * + * @see https://github.com/Agoric/dapp-card-store/issues/37 + * + * @param specifier The module to load. + * @returns The loaded module. + */ +export function isolatedRequire(specifier: string) { + const sandbox = createContext({ + require, + }) + + return runInNewContext(`require(${JSON.stringify(specifier)})`, sandbox) +} + export function pageNotFoundError(page: string): Error { const err: any = new Error(`Cannot find module for page: ${page}`) err.code = 'ENOENT' @@ -65,7 +88,11 @@ export function requirePage( if (pagePath.endsWith('.html')) { return promises.readFile(pagePath, 'utf8') } - return require(pagePath) + /** + * Use isolated require() to avoid cross-module contamination with Next's own + * logic. + */ + return isolatedRequire(pagePath) } export function requireFontManifest(distDir: string, serverless: boolean) { From 5bafaa400f2c2d910b740f5da5886dde6df22a50 Mon Sep 17 00:00:00 2001 From: "C. Lewis" Date: Sat, 2 Oct 2021 11:54:49 -0500 Subject: [PATCH 2/4] chore: comment formatting --- packages/next/server/require.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/next/server/require.ts b/packages/next/server/require.ts index 9cce12943f853..cf8a61f7bde99 100644 --- a/packages/next/server/require.ts +++ b/packages/next/server/require.ts @@ -20,8 +20,6 @@ import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path' * This should be used to load all React components for SSR. * @see requirePage * - * @see https://github.com/Agoric/dapp-card-store/issues/37 - * * @param specifier The module to load. * @returns The loaded module. */ From 9fbf115cdbb62d0f1e681e05d97dbfc929ba51ef Mon Sep 17 00:00:00 2001 From: "C. Lewis" Date: Fri, 14 Jan 2022 02:05:52 -0600 Subject: [PATCH 3/4] format: styling --- packages/next/server/require.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/next/server/require.ts b/packages/next/server/require.ts index 71f328e67f952..d26cae844677e 100644 --- a/packages/next/server/require.ts +++ b/packages/next/server/require.ts @@ -26,10 +26,7 @@ import type { MiddlewareManifest } from '../build/webpack/plugins/middleware-plu * @returns The loaded module. */ export function isolatedRequire(specifier: string) { - const sandbox = createContext({ - require, - }) - + const sandbox = createContext({ require }) return runInNewContext(`require(${JSON.stringify(specifier)})`, sandbox) } From 5351f694b0ec5fa385477a3390fb1130583c9568 Mon Sep 17 00:00:00 2001 From: "C. Lewis" Date: Fri, 14 Jan 2022 02:08:14 -0600 Subject: [PATCH 4/4] chore: update snapshot This source for the module in this error overlay test changes from `(eval)` to `(unknown)` when injected by Jest, and is purely cosmetic. --- .../acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap b/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap index 9490683c29ee0..9a86a72689a24 100644 --- a/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap +++ b/test/development/acceptance/__snapshots__/ReactRefreshLogBox.test.ts.snap @@ -80,12 +80,12 @@ Caused by: `; exports[`ReactRefreshLogBox module init error not shown 1`] = ` -"index.js (4:14) @ eval +"index.js (4:8) @ 2 | // top offset for snapshot 3 | import * as React from 'react'; > 4 | throw new Error('no') - | ^ + | ^ 5 | class ClassDefault extends React.Component { 6 | render() { 7 | return

Default Export

;"