From c296a680bb4c5387abf6926db308de0bde980475 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 15 Apr 2022 20:38:48 +0700 Subject: [PATCH 01/10] do not polyfill node built-in modules --- packages/next/build/index.ts | 9 +- packages/next/build/webpack-config.ts | 107 ++++++++++++------ .../pages/using-child-process/_middleware.js | 7 ++ .../pages/using-path/_middleware.js | 7 ++ .../with-builtin-module/test/index.test.js | 90 +++++++++++++++ 5 files changed, 182 insertions(+), 38 deletions(-) create mode 100644 test/integration/middleware/with-builtin-module/pages/using-child-process/_middleware.js create mode 100644 test/integration/middleware/with-builtin-module/pages/using-path/_middleware.js create mode 100644 test/integration/middleware/with-builtin-module/test/index.test.js diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 268c315debbb..bf12b637200f 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -723,7 +723,7 @@ export default async function build( if (result.errors.length > 5) { result.errors.length = 5 } - const error = result.errors.join('\n\n') + let error = result.errors.join('\n\n') console.error(chalk.red('Failed to compile.\n')) @@ -739,6 +739,13 @@ export default async function build( ) } + const breakingChangeIndex = error.indexOf( + '\n\nBREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.' + ) + if (breakingChangeIndex >= 0) { + error = error.slice(0, breakingChangeIndex) + } + console.error(error) console.error() diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 9166fefdf483..eca1cc0cb1c6 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -626,43 +626,6 @@ export default async function getBaseWebpackConfig( setimmediate: 'next/dist/compiled/setimmediate', }, - ...(targetWeb - ? { - // Full list of old polyfills is accessible here: - // https://github.com/webpack/webpack/blob/2a0536cf510768111a3a6dceeb14cb79b9f59273/lib/ModuleNotFoundError.js#L13-L42 - fallback: { - assert: require.resolve('next/dist/compiled/assert'), - buffer: require.resolve('next/dist/compiled/buffer/'), - constants: require.resolve( - 'next/dist/compiled/constants-browserify' - ), - crypto: require.resolve('next/dist/compiled/crypto-browserify'), - domain: require.resolve('next/dist/compiled/domain-browser'), - http: require.resolve('next/dist/compiled/stream-http'), - https: require.resolve('next/dist/compiled/https-browserify'), - os: require.resolve('next/dist/compiled/os-browserify'), - path: require.resolve('next/dist/compiled/path-browserify'), - punycode: require.resolve('next/dist/compiled/punycode'), - process: require.resolve('./polyfills/process'), - // Handled in separate alias - querystring: require.resolve('next/dist/compiled/querystring-es3'), - stream: require.resolve('next/dist/compiled/stream-browserify'), - string_decoder: require.resolve( - 'next/dist/compiled/string_decoder' - ), - sys: require.resolve('next/dist/compiled/util/'), - timers: require.resolve('next/dist/compiled/timers-browserify'), - tty: require.resolve('next/dist/compiled/tty-browserify'), - // Handled in separate alias - // url: require.resolve('url/'), - util: require.resolve('next/dist/compiled/util/'), - vm: require.resolve('next/dist/compiled/vm-browserify'), - zlib: require.resolve('next/dist/compiled/browserify-zlib'), - events: require.resolve('next/dist/compiled/events/'), - setImmediate: require.resolve('next/dist/compiled/setimmediate'), - }, - } - : undefined), mainFields: targetWeb ? (isEdgeRuntime ? [] : ['browser']).concat(['module', 'main']) : ['main', 'module'], @@ -1284,6 +1247,76 @@ export default async function getBaseWebpackConfig( }, ] : []), + ...(!isServer && !isEdgeRuntime + ? [ + { + oneOf: [ + { + issuerLayer: 'middleware', + }, + { + resolve: { + // Full list of old polyfills is accessible here: + // https://github.com/webpack/webpack/blob/2a0536cf510768111a3a6dceeb14cb79b9f59273/lib/ModuleNotFoundError.js#L13-L42 + fallback: { + assert: require.resolve('next/dist/compiled/assert'), + buffer: require.resolve('next/dist/compiled/buffer/'), + constants: require.resolve( + 'next/dist/compiled/constants-browserify' + ), + crypto: require.resolve( + 'next/dist/compiled/crypto-browserify' + ), + domain: require.resolve( + 'next/dist/compiled/domain-browser' + ), + http: require.resolve('next/dist/compiled/stream-http'), + https: require.resolve( + 'next/dist/compiled/https-browserify' + ), + os: require.resolve('next/dist/compiled/os-browserify'), + path: require.resolve( + 'next/dist/compiled/path-browserify' + ), + punycode: require.resolve( + 'next/dist/compiled/punycode' + ), + process: require.resolve('./polyfills/process'), + // Handled in separate alias + querystring: require.resolve( + 'next/dist/compiled/querystring-es3' + ), + stream: require.resolve( + 'next/dist/compiled/stream-browserify' + ), + string_decoder: require.resolve( + 'next/dist/compiled/string_decoder' + ), + sys: require.resolve('next/dist/compiled/util/'), + timers: require.resolve( + 'next/dist/compiled/timers-browserify' + ), + tty: require.resolve( + 'next/dist/compiled/tty-browserify' + ), + // Handled in separate alias + // url: require.resolve('url/'), + util: require.resolve('next/dist/compiled/util/'), + vm: require.resolve('next/dist/compiled/vm-browserify'), + zlib: require.resolve( + 'next/dist/compiled/browserify-zlib' + ), + events: require.resolve('next/dist/compiled/events/'), + setImmediate: require.resolve( + 'next/dist/compiled/setimmediate' + ), + }, + }, + }, + ], + }, + ] + : []), ].filter(Boolean), }, plugins: [ diff --git a/test/integration/middleware/with-builtin-module/pages/using-child-process/_middleware.js b/test/integration/middleware/with-builtin-module/pages/using-child-process/_middleware.js new file mode 100644 index 000000000000..e4501469fd8c --- /dev/null +++ b/test/integration/middleware/with-builtin-module/pages/using-child-process/_middleware.js @@ -0,0 +1,7 @@ +import { NextResponse } from 'next/server' +import { spawn } from 'child_process' + +export async function middleware(request) { + console.log(spawn('ls', ['-lh', '/usr'])) + return NextResponse.next() +} diff --git a/test/integration/middleware/with-builtin-module/pages/using-path/_middleware.js b/test/integration/middleware/with-builtin-module/pages/using-path/_middleware.js new file mode 100644 index 000000000000..c10aadb272eb --- /dev/null +++ b/test/integration/middleware/with-builtin-module/pages/using-path/_middleware.js @@ -0,0 +1,7 @@ +import { NextResponse } from 'next/server' +import { basename } from 'path' + +export async function middleware(request) { + console.log(basename('/foo/bar/baz/asdf/quux.html')) + return NextResponse.next() +} diff --git a/test/integration/middleware/with-builtin-module/test/index.test.js b/test/integration/middleware/with-builtin-module/test/index.test.js new file mode 100644 index 000000000000..a2705422da2a --- /dev/null +++ b/test/integration/middleware/with-builtin-module/test/index.test.js @@ -0,0 +1,90 @@ +/* eslint-env jest */ + +import stripAnsi from 'next/dist/compiled/strip-ansi' +import { join } from 'path' +import { + fetchViaHTTP, + findPort, + killApp, + launchApp, + nextBuild, + waitFor, +} from 'next-test-utils' + +const context = {} +const WEBPACK_BREAKING_CHANGE = 'BREAKING CHANGE:' + +jest.setTimeout(1000 * 60 * 2) +context.appDir = join(__dirname, '../') + +describe('Middleware importing Node.js built-in module', () => { + function getModuleNotFound(name) { + return `Module not found: Can't resolve '${name}'` + } + + function getBuiltinApisNotSupported(name) { + return `Native Node.js APIs are not supported in the Edge Runtime. Found \`${name}\` imported.\n` + } + + describe('dev mode', () => { + let output = '' + + beforeAll(async () => { + context.appPort = await findPort() + context.app = await launchApp(context.appDir, context.appPort, { + env: { __NEXT_TEST_WITH_DEVTOOL: 1 }, + onStdout(msg) { + output += msg + }, + onStderr(msg) { + output += msg + }, + }) + }) + + beforeEach(() => (output = '')) + afterAll(() => killApp(context.app)) + + it('shows error when importing path module', async () => { + const res = await fetchViaHTTP(context.appPort, '/using-path') + await waitFor(500) + expect(res.status).toBe(500) + expect(output).toContain(getModuleNotFound('path')) + expect(output).toContain(getBuiltinApisNotSupported('path')) + expect(stripAnsi(output)).toContain("import { basename } from 'path'") + expect(output).not.toContain(WEBPACK_BREAKING_CHANGE) + }) + + it('shows error when importing child_process module', async () => { + const res = await fetchViaHTTP(context.appPort, '/using-child-process') + await waitFor(500) + expect(res.status).toBe(500) + expect(output).toContain(getModuleNotFound('child_process')) + expect(output).toContain(getBuiltinApisNotSupported('child_process')) + expect(stripAnsi(output)).toContain( + "import { spawn } from 'child_process'" + ) + expect(output).not.toContain(WEBPACK_BREAKING_CHANGE) + }) + }) + + describe('production mode', () => { + let buildResult + + beforeAll(async () => { + buildResult = await nextBuild(context.appDir, undefined, { + stderr: true, + stdout: true, + }) + }) + + it('should have middleware error during build', () => { + expect(buildResult.stderr).toContain(getModuleNotFound('child_process')) + expect(buildResult.stderr).toContain(getModuleNotFound('path')) + expect(buildResult.stderr).toContain( + getBuiltinApisNotSupported('child_process') + ) + expect(buildResult.stderr).not.toContain(WEBPACK_BREAKING_CHANGE) + }) + }) +}) From 94db083eeab25106de35b3d8c3c624ffd7425824 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Tue, 19 Apr 2022 15:41:52 +0700 Subject: [PATCH 02/10] polyfill built-in modules for edge runtime for now --- packages/next/build/webpack-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 7ad4ac636916..6640a02550e2 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1243,7 +1243,7 @@ export default async function getBaseWebpackConfig( }, ] : []), - ...(!isServer && !isEdgeRuntime + ...(targetWeb ? [ { oneOf: [ From 92146aaa85a6d3c5250b2931d2e4d91de33a7927 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 22 Apr 2022 19:50:46 +0700 Subject: [PATCH 03/10] Revert "polyfill built-in modules for edge runtime for now" This reverts commit 94db083eeab25106de35b3d8c3c624ffd7425824. --- packages/next/build/webpack-config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 6640a02550e2..7ad4ac636916 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1243,7 +1243,7 @@ export default async function getBaseWebpackConfig( }, ] : []), - ...(targetWeb + ...(!isServer && !isEdgeRuntime ? [ { oneOf: [ From 0ffa3238f2299684e0c882073205273f1ad12251 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Fri, 22 Apr 2022 15:21:39 +0200 Subject: [PATCH 04/10] update internal path import --- packages/next/server/base-server.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 4df12587419f..409f831f3269 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -18,7 +18,7 @@ import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plug import type { BaseNextRequest, BaseNextResponse } from './base-http' import type { PayloadOptions } from './send-payload' -import { join, resolve } from 'path' +import path from '../shared/lib/isomorphic/path' import { parse as parseQs } from 'querystring' import { format as formatUrl, parse as parseUrl } from 'url' import { getRedirectStatus } from '../lib/load-custom-routes' @@ -66,6 +66,8 @@ import { PrerenderManifest } from '../build' import { ImageConfigComplete } from '../shared/lib/image-config' import { replaceBasePath } from './router-utils' +const { join, resolve } = path + export type FindComponentsResult = { components: LoadComponentsReturnType query: NextParsedUrlQuery From 1c91e94a4d20c8aca54f6970b05807e21f6bdace Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 22 Apr 2022 21:06:20 +0700 Subject: [PATCH 05/10] remove use of process polyfill --- packages/next/server/web/sandbox/context.ts | 1 - packages/next/server/web/sandbox/polyfills.ts | 3 +-- test/integration/middleware/core/test/index.test.js | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/next/server/web/sandbox/context.ts b/packages/next/server/web/sandbox/context.ts index 71c221a6078c..292b5fa87bfb 100644 --- a/packages/next/server/web/sandbox/context.ts +++ b/packages/next/server/web/sandbox/context.ts @@ -210,7 +210,6 @@ function createContext(options: { File, FormData, process: { - ...polyfills.process, env: buildEnvironmentVariablesFrom(options.env), }, ReadableStream, diff --git a/packages/next/server/web/sandbox/polyfills.ts b/packages/next/server/web/sandbox/polyfills.ts index 85d8c42cfe52..26ddf0c9d6bc 100644 --- a/packages/next/server/web/sandbox/polyfills.ts +++ b/packages/next/server/web/sandbox/polyfills.ts @@ -1,7 +1,6 @@ import { Crypto as WebCrypto } from 'next/dist/compiled/@peculiar/webcrypto' import { CryptoKey } from 'next/dist/compiled/@peculiar/webcrypto' import { v4 as uuid } from 'next/dist/compiled/uuid' -import processPolyfill from 'next/dist/compiled/process' import crypto from 'crypto' @@ -13,7 +12,7 @@ export function btoa(str: string) { return Buffer.from(str, 'binary').toString('base64') } -export { CryptoKey, processPolyfill as process } +export { CryptoKey } export class Crypto extends WebCrypto { // @ts-ignore Remove once types are updated and we deprecate node 12 diff --git a/test/integration/middleware/core/test/index.test.js b/test/integration/middleware/core/test/index.test.js index c224307ef734..11d259abfa41 100644 --- a/test/integration/middleware/core/test/index.test.js +++ b/test/integration/middleware/core/test/index.test.js @@ -123,7 +123,7 @@ describe('Middleware base tests', () => { }) }) - it('should contains process polyfill', async () => { + it('should contains process.env without other properties', async () => { const res = await fetchViaHTTP(context.appPort, `/global`) const json = await res.json() expect(json).toEqual({ @@ -131,7 +131,7 @@ describe('Middleware base tests', () => { env: { MIDDLEWARE_TEST: 'asdf', }, - nextTick: 'function', + nextTick: 'undefined', }, }) }) From 8127b1bfb5595d1ad1f05f483b8c12a601b01400 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 22 Apr 2022 21:20:29 +0700 Subject: [PATCH 06/10] fix for lint --- packages/next/server/base-server.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 409f831f3269..e93f4eefb8bd 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -18,7 +18,7 @@ import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plug import type { BaseNextRequest, BaseNextResponse } from './base-http' import type { PayloadOptions } from './send-payload' -import path from '../shared/lib/isomorphic/path' +import { join, resolve } from '../shared/lib/isomorphic/path' import { parse as parseQs } from 'querystring' import { format as formatUrl, parse as parseUrl } from 'url' import { getRedirectStatus } from '../lib/load-custom-routes' @@ -66,8 +66,6 @@ import { PrerenderManifest } from '../build' import { ImageConfigComplete } from '../shared/lib/image-config' import { replaceBasePath } from './router-utils' -const { join, resolve } = path - export type FindComponentsResult = { components: LoadComponentsReturnType query: NextParsedUrlQuery From 7cd01cf2937f23ba5b9b53ffd349542eece8477d Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 22 Apr 2022 21:20:29 +0700 Subject: [PATCH 07/10] fix for lint --- packages/next/server/base-server.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index e93f4eefb8bd..5ff236049c2d 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -18,7 +18,7 @@ import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plug import type { BaseNextRequest, BaseNextResponse } from './base-http' import type { PayloadOptions } from './send-payload' -import { join, resolve } from '../shared/lib/isomorphic/path' +import isomorphicPath from '../shared/lib/isomorphic/path' import { parse as parseQs } from 'querystring' import { format as formatUrl, parse as parseUrl } from 'url' import { getRedirectStatus } from '../lib/load-custom-routes' @@ -66,6 +66,8 @@ import { PrerenderManifest } from '../build' import { ImageConfigComplete } from '../shared/lib/image-config' import { replaceBasePath } from './router-utils' +const { join, resolve } = isomorphicPath + export type FindComponentsResult = { components: LoadComponentsReturnType query: NextParsedUrlQuery From 0fdb15946bd2fbe018b6642d80b878eaa5c52682 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Fri, 22 Apr 2022 21:55:47 +0700 Subject: [PATCH 08/10] fix a test --- test/integration/middleware/core/test/index.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/integration/middleware/core/test/index.test.js b/test/integration/middleware/core/test/index.test.js index 11d259abfa41..e5761b96ba24 100644 --- a/test/integration/middleware/core/test/index.test.js +++ b/test/integration/middleware/core/test/index.test.js @@ -123,7 +123,7 @@ describe('Middleware base tests', () => { }) }) - it('should contains process.env without other properties', async () => { + it('should contains process polyfill', async () => { const res = await fetchViaHTTP(context.appPort, `/global`) const json = await res.json() expect(json).toEqual({ @@ -131,7 +131,9 @@ describe('Middleware base tests', () => { env: { MIDDLEWARE_TEST: 'asdf', }, - nextTick: 'undefined', + // it's poflyfilled since there is the "process" module + // as a devDepencies of the next package + nextTick: 'function', }, }) }) From 526a79591acf65d94e1559d9fceda30c6eeebcc6 Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 25 Apr 2022 15:23:50 +0700 Subject: [PATCH 09/10] disable fallback check for process on edge runtime --- packages/next/build/webpack-config.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 7ad4ac636916..d027b4212feb 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -626,6 +626,13 @@ export default async function getBaseWebpackConfig( setimmediate: 'next/dist/compiled/setimmediate', }, + ...(isEdgeRuntime + ? { + fallback: { + process: false, + }, + } + : undefined), mainFields: targetWeb ? (isEdgeRuntime ? [] : ['browser']).concat(['module', 'main']) : ['main', 'module'], @@ -1249,6 +1256,11 @@ export default async function getBaseWebpackConfig( oneOf: [ { issuerLayer: 'middleware', + resolve: { + fallback: { + process: false, + }, + }, }, { resolve: { From 5dfd5a42ef85e1d619f4be0b8860450b6872352d Mon Sep 17 00:00:00 2001 From: nkzawa Date: Mon, 25 Apr 2022 15:49:06 +0700 Subject: [PATCH 10/10] set existing polyfill instead --- packages/next/build/webpack-config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index d027b4212feb..91a834802d7e 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -629,7 +629,7 @@ export default async function getBaseWebpackConfig( ...(isEdgeRuntime ? { fallback: { - process: false, + process: require.resolve('./polyfills/process'), }, } : undefined), @@ -1258,7 +1258,7 @@ export default async function getBaseWebpackConfig( issuerLayer: 'middleware', resolve: { fallback: { - process: false, + process: require.resolve('./polyfills/process'), }, }, },