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 488c64fa5ea7..91a834802d7e 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -626,40 +626,10 @@ export default async function getBaseWebpackConfig( setimmediate: 'next/dist/compiled/setimmediate', }, - ...(targetWeb + ...(isEdgeRuntime ? { - // 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), @@ -1280,6 +1250,81 @@ export default async function getBaseWebpackConfig( }, ] : []), + ...(!isServer && !isEdgeRuntime + ? [ + { + oneOf: [ + { + issuerLayer: 'middleware', + resolve: { + fallback: { + process: require.resolve('./polyfills/process'), + }, + }, + }, + { + 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/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..e5761b96ba24 100644 --- a/test/integration/middleware/core/test/index.test.js +++ b/test/integration/middleware/core/test/index.test.js @@ -131,6 +131,8 @@ describe('Middleware base tests', () => { env: { MIDDLEWARE_TEST: 'asdf', }, + // it's poflyfilled since there is the "process" module + // as a devDepencies of the next package nextTick: 'function', }, }) 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) + }) + }) +})