Add browser polyfils for Node.js modules (webpack 5 backwards compat) (#16022)
This adds the following Node.js core polyfills only when the import is used: - `path` - `stream` - `vm` - `crypto` - `buffer` Fixes #15948 We'll have a separate issue about adding warnings for the usage of these modules in the browser, some polyfills like crypto are quite heavy and generally not needed for most applications (included accidentally through node_modules).
This commit is contained in:
parent
394e24073d
commit
843d58425b
7 changed files with 189 additions and 7 deletions
|
@ -356,7 +356,16 @@ export default async function getBaseWebpackConfig(
|
|||
'next/router': 'next/dist/client/router.js',
|
||||
'next/config': 'next/dist/next-server/lib/runtime-config.js',
|
||||
'next/dynamic': 'next/dist/next-server/lib/dynamic.js',
|
||||
next: NEXT_PROJECT_ROOT,
|
||||
...(isServer
|
||||
? {}
|
||||
: {
|
||||
stream: 'stream-browserify',
|
||||
path: 'path-browserify',
|
||||
crypto: 'crypto-browserify',
|
||||
buffer: 'buffer',
|
||||
vm: 'vm-browserify',
|
||||
next: NEXT_PROJECT_ROOT,
|
||||
}),
|
||||
[PAGES_DIR_ALIAS]: pagesDir,
|
||||
[DOT_NEXT_ALIAS]: distDir,
|
||||
...getOptimizedAliases(isServer),
|
||||
|
|
|
@ -87,6 +87,7 @@
|
|||
"buffer": "5.6.0",
|
||||
"cacache": "13.0.1",
|
||||
"chokidar": "2.1.8",
|
||||
"crypto-browserify": "3.12.0",
|
||||
"css-loader": "3.5.3",
|
||||
"cssnano-simple": "1.0.6",
|
||||
"find-cache-dir": "3.3.1",
|
||||
|
@ -97,6 +98,7 @@
|
|||
"native-url": "0.3.4",
|
||||
"neo-async": "2.6.1",
|
||||
"node-html-parser": "^1.2.19",
|
||||
"path-browserify": "1.0.1",
|
||||
"pnp-webpack-plugin": "1.6.4",
|
||||
"postcss": "7.0.32",
|
||||
"process": "0.11.10",
|
||||
|
@ -107,9 +109,11 @@
|
|||
"resolve-url-loader": "3.1.1",
|
||||
"sass-loader": "8.0.2",
|
||||
"schema-utils": "2.6.6",
|
||||
"stream-browserify": "3.0.0",
|
||||
"style-loader": "1.2.1",
|
||||
"styled-jsx": "3.3.0",
|
||||
"use-subscription": "1.4.1",
|
||||
"vm-browserify": "1.1.2",
|
||||
"watchpack": "2.0.0-beta.13",
|
||||
"web-vitals": "0.2.1",
|
||||
"webpack": "4.44.1",
|
||||
|
|
48
test/integration/basic/pages/node-browser-polyfills.js
Normal file
48
test/integration/basic/pages/node-browser-polyfills.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { Writable } from 'stream'
|
||||
import path from 'path'
|
||||
import crypto from 'crypto'
|
||||
import { Buffer } from 'buffer'
|
||||
import vm from 'vm'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export default function NodeBrowserPolyfillPage() {
|
||||
const [state, setState] = useState({})
|
||||
useEffect(() => {
|
||||
let closedStream = false
|
||||
|
||||
const writable = new Writable({
|
||||
write(_chunk, _encoding, callback) {
|
||||
callback()
|
||||
},
|
||||
})
|
||||
|
||||
writable.on('finish', () => {
|
||||
closedStream = true
|
||||
})
|
||||
|
||||
writable.end()
|
||||
|
||||
setState({
|
||||
path: path.join('/hello/world', 'test.txt'),
|
||||
hash: crypto.createHash('sha256').update('hello world').digest('hex'),
|
||||
buffer: Buffer.from('hello world').toString('utf8'),
|
||||
vm: vm.runInNewContext('a + 5', { a: 100 }),
|
||||
stream: closedStream,
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (state.vm) {
|
||||
window.didRender = true
|
||||
}
|
||||
}, [state])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
id="node-browser-polyfills"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(state) }}
|
||||
></div>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { join } from 'path'
|
||||
import { renderViaHTTP, findPort, launchApp, killApp } from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
|
||||
// test suits
|
||||
import hmr from './hmr'
|
||||
|
@ -33,6 +34,24 @@ describe('Basic Features', () => {
|
|||
})
|
||||
afterAll(() => killApp(context.server))
|
||||
|
||||
it('should polyfill Node.js modules', async () => {
|
||||
const browser = await webdriver(context.appPort, '/node-browser-polyfills')
|
||||
await browser.waitForCondition('window.didRender')
|
||||
|
||||
const data = await browser
|
||||
.waitForElementByCss('#node-browser-polyfills')
|
||||
.text()
|
||||
const parsedData = JSON.parse(data)
|
||||
|
||||
expect(parsedData.vm).toBe(105)
|
||||
expect(parsedData.hash).toBe(
|
||||
'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
|
||||
)
|
||||
expect(parsedData.path).toBe('/hello/world/test.txt')
|
||||
expect(parsedData.buffer).toBe('hello world')
|
||||
expect(parsedData.stream).toBe(true)
|
||||
})
|
||||
|
||||
dynamic(context, (p, q) => renderViaHTTP(context.appPort, p, q))
|
||||
hmr(context, (p, q) => renderViaHTTP(context.appPort, p, q))
|
||||
errorRecovery(context, (p, q) => renderViaHTTP(context.appPort, p, q))
|
||||
|
|
48
test/integration/production/pages/node-browser-polyfills.js
Normal file
48
test/integration/production/pages/node-browser-polyfills.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { Writable } from 'stream'
|
||||
import path from 'path'
|
||||
import crypto from 'crypto'
|
||||
import { Buffer } from 'buffer'
|
||||
import vm from 'vm'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export default function NodeBrowserPolyfillPage() {
|
||||
const [state, setState] = useState({})
|
||||
useEffect(() => {
|
||||
let closedStream = false
|
||||
|
||||
const writable = new Writable({
|
||||
write(_chunk, _encoding, callback) {
|
||||
callback()
|
||||
},
|
||||
})
|
||||
|
||||
writable.on('finish', () => {
|
||||
closedStream = true
|
||||
})
|
||||
|
||||
writable.end()
|
||||
|
||||
setState({
|
||||
path: path.join('/hello/world', 'test.txt'),
|
||||
hash: crypto.createHash('sha256').update('hello world').digest('hex'),
|
||||
buffer: Buffer.from('hello world').toString('utf8'),
|
||||
vm: vm.runInNewContext('a + 5', { a: 100 }),
|
||||
stream: closedStream,
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (state.vm) {
|
||||
window.didRender = true
|
||||
}
|
||||
}, [state])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
id="node-browser-polyfills"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(state) }}
|
||||
></div>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -70,6 +70,24 @@ describe('Production Usage', () => {
|
|||
})
|
||||
}
|
||||
|
||||
it('should polyfill Node.js modules', async () => {
|
||||
const browser = await webdriver(appPort, '/node-browser-polyfills')
|
||||
await browser.waitForCondition('window.didRender')
|
||||
|
||||
const data = await browser
|
||||
.waitForElementByCss('#node-browser-polyfills')
|
||||
.text()
|
||||
const parsedData = JSON.parse(data)
|
||||
|
||||
expect(parsedData.vm).toBe(105)
|
||||
expect(parsedData.hash).toBe(
|
||||
'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
|
||||
)
|
||||
expect(parsedData.path).toBe('/hello/world/test.txt')
|
||||
expect(parsedData.buffer).toBe('hello world')
|
||||
expect(parsedData.stream).toBe(true)
|
||||
})
|
||||
|
||||
it('should allow etag header support', async () => {
|
||||
const url = `http://localhost:${appPort}/`
|
||||
const etag = (await fetch(url)).headers.get('ETag')
|
||||
|
|
48
yarn.lock
48
yarn.lock
|
@ -4121,7 +4121,7 @@ browserify-zlib@^0.2.0:
|
|||
dependencies:
|
||||
pako "~1.0.5"
|
||||
|
||||
browserslist@4.13.0, browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6, browserslist@^4.0.0, browserslist@^4.11.1, browserslist@^4.13.0, browserslist@^4.3.6, browserslist@^4.6.4, browserslist@^4.8.3, browserslist@^4.8.5:
|
||||
browserslist@4.13.0, browserslist@^4.0.0, browserslist@^4.11.1, browserslist@^4.13.0, browserslist@^4.3.6, browserslist@^4.6.4, browserslist@^4.8.3, browserslist@^4.8.5:
|
||||
version "4.13.0"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.13.0.tgz#42556cba011e1b0a2775b611cba6a8eca18e940d"
|
||||
integrity sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==
|
||||
|
@ -4131,6 +4131,14 @@ browserslist@4.13.0, browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7
|
|||
escalade "^3.0.1"
|
||||
node-releases "^1.1.58"
|
||||
|
||||
browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
|
||||
version "1.7.7"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
|
||||
integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=
|
||||
dependencies:
|
||||
caniuse-db "^1.0.30000639"
|
||||
electron-to-chromium "^1.2.7"
|
||||
|
||||
browserstack-local@1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/browserstack-local/-/browserstack-local-1.4.0.tgz#d979cac056f57b9af159b3bcd7fdc09b4354537c"
|
||||
|
@ -4460,11 +4468,21 @@ caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634:
|
|||
version "1.0.30001023"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001023.tgz#f856f71af16a5a44e81f1fcefc1673912a43da72"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001019, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001093:
|
||||
caniuse-db@^1.0.30000639:
|
||||
version "1.0.30001112"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001112.tgz#89cb249402af2ebf2c23a5585d1bd78cb5e38732"
|
||||
integrity sha512-Xrn3lVEIsvAAUmFVHKKComfyCRM59NfuV3EwCXqs2XLgOxAqYgrfEs0vDk+Dk7KctlAMh6CH/CSd1srJt503ZA==
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001019, caniuse-lite@^1.0.30001020:
|
||||
version "1.0.30001066"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001066.tgz#0a8a58a10108f2b9bf38e7b65c237b12fd9c5f04"
|
||||
integrity sha512-Gfj/WAastBtfxLws0RCh2sDbTK/8rJuSeZMecrSkNGYxPcv7EzblmDGfWQCFEQcSqYE2BRgQiJh8HOD07N5hIw==
|
||||
|
||||
caniuse-lite@^1.0.30001093:
|
||||
version "1.0.30001112"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001112.tgz#0fffc3b934ff56ff0548c37bc9dad7d882bcf672"
|
||||
integrity sha512-J05RTQlqsatidif/38aN3PGULCLrg8OYQOlJUKbeYVzC2mGZkZLIztwRlB3MtrfLmawUmjFlNJvy/uhwniIe1Q==
|
||||
|
||||
capitalize@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/capitalize/-/capitalize-1.0.0.tgz#dc802c580aee101929020d2ca14b4ca8a0ae44be"
|
||||
|
@ -5376,7 +5394,7 @@ cross-spawn@^7.0.0:
|
|||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
crypto-browserify@^3.11.0:
|
||||
crypto-browserify@3.12.0, crypto-browserify@^3.11.0:
|
||||
version "3.12.0"
|
||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
||||
integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
|
||||
|
@ -6190,6 +6208,11 @@ ejs@^2.6.1:
|
|||
version "2.7.4"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
|
||||
|
||||
electron-to-chromium@^1.2.7:
|
||||
version "1.3.526"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.526.tgz#0e004899edf75afc172cce1b8189aac5dca646aa"
|
||||
integrity sha512-HiroW5ZbGwgT8kCnoEO8qnGjoTPzJxduvV/Vv/wH63eo2N6Zj3xT5fmmaSPAPUM05iN9/5fIEkIg3owTtV6QZg==
|
||||
|
||||
electron-to-chromium@^1.3.488:
|
||||
version "1.3.501"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.501.tgz#faa17a2cb0105ee30d5e1ca87eae7d8e85dd3175"
|
||||
|
@ -8108,7 +8131,7 @@ inflight@^1.0.4:
|
|||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
|
||||
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
|
||||
|
@ -11695,6 +11718,11 @@ path-browserify@0.0.1:
|
|||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
|
||||
integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
|
||||
|
||||
path-browserify@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
|
||||
integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
|
||||
|
||||
path-case@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
|
||||
|
@ -13337,7 +13365,7 @@ read@1, read@~1.0.1:
|
|||
string_decoder "^1.1.1"
|
||||
util-deprecate "^1.0.1"
|
||||
|
||||
readable-stream@^3.4.0, readable-stream@^3.6.0:
|
||||
readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
|
||||
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
|
||||
|
@ -14717,6 +14745,14 @@ stealthy-require@^1.1.1:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
||||
|
||||
stream-browserify@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f"
|
||||
integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==
|
||||
dependencies:
|
||||
inherits "~2.0.4"
|
||||
readable-stream "^3.5.0"
|
||||
|
||||
stream-browserify@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
|
||||
|
@ -15970,7 +16006,7 @@ vlq@^0.2.1, vlq@^0.2.2:
|
|||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
|
||||
|
||||
vm-browserify@^1.0.1:
|
||||
vm-browserify@1.1.2, vm-browserify@^1.0.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||
|
|
Loading…
Reference in a new issue