diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 210d9b898a537..e80def16aed70 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -45,11 +45,12 @@ use crate::{ /// This is not identical to the list of entire node.js internals, refer /// https://vercel.com/docs/functions/runtimes/edge-runtime#compatible-node.js-modules /// for the allowed imports. -const EDGE_UNSUPPORTED_NODE_INTERNALS: [&str; 43] = [ +const EDGE_UNSUPPORTED_NODE_INTERNALS: [&str; 44] = [ "child_process", "cluster", "console", "constants", + "crypto", "dgram", "diagnostics_channel", "dns", diff --git a/test/development/basic/node-builtins.test.ts b/test/development/basic/node-builtins.test.ts index 96a3ce3caeaf9..b695df70cc194 100644 --- a/test/development/basic/node-builtins.test.ts +++ b/test/development/basic/node-builtins.test.ts @@ -167,4 +167,35 @@ describe('node builtins', () => { expect(parsedData.sys).toBe(true) expect(parsedData.timers).toBe(true) }) + + it('should throw when unsupported builtins are used in middleware', async () => { + const res = await next.fetch('/middleware-test') + expect(res.status).toBe(200) + expect(JSON.parse(res.headers.get('supported-result'))) + .toMatchInlineSnapshot(` + { + "assert": true, + "buffer": "hello world", + "eventEmitter": true, + "util": true, + } + `) + expect(JSON.parse(res.headers.get('unsupported-result'))) + .toMatchInlineSnapshot(` + { + "constants": false, + "crypto": false, + "domain": false, + "http": false, + "https": false, + "os": false, + "path": false, + "stream": false, + "timers": false, + "tty": false, + "vm": false, + "zlib": false, + } + `) + }) }) diff --git a/test/development/basic/node-builtins/app/middleware-test/page.tsx b/test/development/basic/node-builtins/app/middleware-test/page.tsx new file mode 100644 index 0000000000000..5a8ee22cb94bd --- /dev/null +++ b/test/development/basic/node-builtins/app/middleware-test/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return

Middleware Test

+} diff --git a/test/development/basic/node-builtins/middleware.js b/test/development/basic/node-builtins/middleware.js new file mode 100644 index 0000000000000..f683368408a8c --- /dev/null +++ b/test/development/basic/node-builtins/middleware.js @@ -0,0 +1,137 @@ +// Unsupported in edge +import { Writable } from 'stream' +import path from 'path' +import crypto from 'crypto' +import vm from 'vm' +import constants from 'constants' +import domain from 'domain' +import http from 'http' +import https from 'https' +import os from 'os' +// TODO: These are accidentally polyfilled in edge runtime currently. +// import punycode from 'punycode' +// import process from 'process' +// import querystring from 'querystring' +// import stringDecoder from 'string_decoder' +import sys from 'sys' +import timers from 'timers' +import tty from 'tty' +import zlib from 'zlib' +import 'setimmediate' +// Supported in edge +import { Buffer } from 'buffer' +import assert from 'assert' +import util from 'util' +import { EventEmitter } from 'events' + +// Other imports +import { NextResponse } from 'next/server' + +export default async function middleware(request) { + if (request.nextUrl.pathname !== '/middleware-test') { + return + } + const response = NextResponse.next() + + let emitted = false + class MyEmitter extends EventEmitter {} + const myEmitter = new MyEmitter() + // Only do this once so we don't loop forever + myEmitter.once('myEvent', (_event, _listener) => { + emitted = true + }) + myEmitter.emit('myEvent') + + assert.ok(emitted) + assert.ok(!!util.promisify) + assert.ok(true) + + const supportedResult = { + assert: true, + buffer: Buffer.from('hello world').toString('utf8'), + eventEmitter: true, + util: true, + } + + response.headers.set('supported-result', JSON.stringify(supportedResult)) + + // TODO: These are accidentally polyfilled in edge runtime currently. + // assert.throws(() => { + // console.log(punycode) + // }) + // assert.throws(() => { + // console.log(process.title) + // }) + // assert.throws(() => { + // console.log(querystring) + // }) + // assert.throws(() => { + // console.log(stringDecoder) + // }) + + assert.throws(() => { + console.log(domain) + }) + assert.throws(() => { + console.log(http) + }) + assert.throws(() => { + console.log(https) + }) + assert.throws(() => { + console.log(zlib.Gzip) + }) + assert.throws(() => { + console.log(constants.E2BIG) + }) + assert.throws(() => { + console.log(crypto.createHash) + }) + assert.throws(() => { + console.log(os.hostname) + }) + assert.throws(() => { + console.log(path.join) + }) + assert.throws(() => { + console.log(vm) + }) + assert.throws(() => { + console.log(tty.isatty) + }) + assert.throws(() => { + console.log(timers.clearImmediate) + }) + assert.throws(() => { + console.log(Writable) + }) + assert.throws(() => { + console.log(sys) + }) + + const unsupportedResult = { + // TODO: these are accidentally polyfilled in edge runtime currently. + // punycode: false, + // process: false, + // querystring: false, + // stringDecoder: false, + + domain: false, + http: false, + https: false, + zlib: false, + constants: false, + crypto: false, + os: false, + path: false, + + vm: false, + tty: false, + timers: false, + stream: false, + } + + response.headers.set('unsupported-result', JSON.stringify(unsupportedResult)) + + return response +}