Skip to content

Commit 173e1c0

Browse files
committed
Add browser polyfils for Node.js modules (webpack 5 backwards compat)
1 parent 7fc92a6 commit 173e1c0

File tree

7 files changed

+189
-7
lines changed

7 files changed

+189
-7
lines changed

packages/next/build/webpack-config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,16 @@ export default async function getBaseWebpackConfig(
356356
'next/router': 'next/dist/client/router.js',
357357
'next/config': 'next/dist/next-server/lib/runtime-config.js',
358358
'next/dynamic': 'next/dist/next-server/lib/dynamic.js',
359-
next: NEXT_PROJECT_ROOT,
359+
...(isServer
360+
? {}
361+
: {
362+
stream: 'stream-browserify',
363+
path: 'path-browserify',
364+
crypto: 'crypto-browserify',
365+
buffer: 'buffer',
366+
vm: 'vm-browserify',
367+
next: NEXT_PROJECT_ROOT,
368+
}),
360369
[PAGES_DIR_ALIAS]: pagesDir,
361370
[DOT_NEXT_ALIAS]: distDir,
362371
...getOptimizedAliases(isServer),

packages/next/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
"buffer": "5.6.0",
8888
"cacache": "13.0.1",
8989
"chokidar": "2.1.8",
90+
"crypto-browserify": "3.12.0",
9091
"css-loader": "3.5.3",
9192
"cssnano-simple": "1.0.6",
9293
"find-cache-dir": "3.3.1",
@@ -97,6 +98,7 @@
9798
"native-url": "0.3.4",
9899
"neo-async": "2.6.1",
99100
"node-html-parser": "^1.2.19",
101+
"path-browserify": "1.0.1",
100102
"pnp-webpack-plugin": "1.6.4",
101103
"postcss": "7.0.32",
102104
"process": "0.11.10",
@@ -107,9 +109,11 @@
107109
"resolve-url-loader": "3.1.1",
108110
"sass-loader": "8.0.2",
109111
"schema-utils": "2.6.6",
112+
"stream-browserify": "3.0.0",
110113
"style-loader": "1.2.1",
111114
"styled-jsx": "3.3.0",
112115
"use-subscription": "1.4.1",
116+
"vm-browserify": "1.1.2",
113117
"watchpack": "2.0.0-beta.13",
114118
"web-vitals": "0.2.1",
115119
"webpack": "4.44.1",
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Writable } from 'stream'
2+
import path from 'path'
3+
import crypto from 'crypto'
4+
import { Buffer } from 'buffer'
5+
import vm from 'vm'
6+
import { useEffect, useState } from 'react'
7+
8+
export default function NodeBrowserPolyfillPage() {
9+
const [state, setState] = useState({})
10+
useEffect(() => {
11+
let closedStream = false
12+
13+
const writable = new Writable({
14+
write(_chunk, _encoding, callback) {
15+
callback()
16+
},
17+
})
18+
19+
writable.on('finish', () => {
20+
closedStream = true
21+
})
22+
23+
writable.end()
24+
25+
setState({
26+
path: path.join('/hello/world', 'test.txt'),
27+
hash: crypto.createHash('sha256').update('hello world').digest('hex'),
28+
buffer: Buffer.from('hello world').toString('utf8'),
29+
vm: vm.runInNewContext('a + 5', { a: 100 }),
30+
stream: closedStream,
31+
})
32+
}, [])
33+
34+
useEffect(() => {
35+
if (state.vm) {
36+
window.didRender = true
37+
}
38+
}, [state])
39+
40+
return (
41+
<>
42+
<div
43+
id="node-browser-polyfills"
44+
dangerouslySetInnerHTML={{ __html: JSON.stringify(state) }}
45+
></div>
46+
</>
47+
)
48+
}

test/integration/basic/test/index.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { join } from 'path'
44
import { renderViaHTTP, findPort, launchApp, killApp } from 'next-test-utils'
5+
import webdriver from 'next-webdriver'
56

67
// test suits
78
import hmr from './hmr'
@@ -33,6 +34,24 @@ describe('Basic Features', () => {
3334
})
3435
afterAll(() => killApp(context.server))
3536

37+
it('should polyfill Node.js modules', async () => {
38+
const browser = await webdriver(context.appPort, '/node-browser-polyfills')
39+
await browser.waitForCondition('window.didRender')
40+
41+
const data = await browser
42+
.waitForElementByCss('#node-browser-polyfills')
43+
.text()
44+
const parsedData = JSON.parse(data)
45+
46+
expect(parsedData.vm).toBe(105)
47+
expect(parsedData.hash).toBe(
48+
'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
49+
)
50+
expect(parsedData.path).toBe('/hello/world/test.txt')
51+
expect(parsedData.buffer).toBe('hello world')
52+
expect(parsedData.stream).toBe(true)
53+
})
54+
3655
dynamic(context, (p, q) => renderViaHTTP(context.appPort, p, q))
3756
hmr(context, (p, q) => renderViaHTTP(context.appPort, p, q))
3857
errorRecovery(context, (p, q) => renderViaHTTP(context.appPort, p, q))
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { Writable } from 'stream'
2+
import path from 'path'
3+
import crypto from 'crypto'
4+
import { Buffer } from 'buffer'
5+
import vm from 'vm'
6+
import { useEffect, useState } from 'react'
7+
8+
export default function NodeBrowserPolyfillPage() {
9+
const [state, setState] = useState({})
10+
useEffect(() => {
11+
let closedStream = false
12+
13+
const writable = new Writable({
14+
write(_chunk, _encoding, callback) {
15+
callback()
16+
},
17+
})
18+
19+
writable.on('finish', () => {
20+
closedStream = true
21+
})
22+
23+
writable.end()
24+
25+
setState({
26+
path: path.join('/hello/world', 'test.txt'),
27+
hash: crypto.createHash('sha256').update('hello world').digest('hex'),
28+
buffer: Buffer.from('hello world').toString('utf8'),
29+
vm: vm.runInNewContext('a + 5', { a: 100 }),
30+
stream: closedStream,
31+
})
32+
}, [])
33+
34+
useEffect(() => {
35+
if (state.vm) {
36+
window.didRender = true
37+
}
38+
}, [state])
39+
40+
return (
41+
<>
42+
<div
43+
id="node-browser-polyfills"
44+
dangerouslySetInnerHTML={{ __html: JSON.stringify(state) }}
45+
></div>
46+
</>
47+
)
48+
}

test/integration/production/test/index.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,24 @@ describe('Production Usage', () => {
7070
})
7171
}
7272

73+
it('should polyfill Node.js modules', async () => {
74+
const browser = await webdriver(appPort, '/node-browser-polyfills')
75+
await browser.waitForCondition('window.didRender')
76+
77+
const data = await browser
78+
.waitForElementByCss('#node-browser-polyfills')
79+
.text()
80+
const parsedData = JSON.parse(data)
81+
82+
expect(parsedData.vm).toBe(105)
83+
expect(parsedData.hash).toBe(
84+
'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
85+
)
86+
expect(parsedData.path).toBe('/hello/world/test.txt')
87+
expect(parsedData.buffer).toBe('hello world')
88+
expect(parsedData.stream).toBe(true)
89+
})
90+
7391
it('should allow etag header support', async () => {
7492
const url = `http://localhost:${appPort}/`
7593
const etag = (await fetch(url)).headers.get('ETag')

yarn.lock

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4121,7 +4121,7 @@ browserify-zlib@^0.2.0:
41214121
dependencies:
41224122
pako "~1.0.5"
41234123

4124-
[email protected], 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:
4124+
[email protected], 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:
41254125
version "4.13.0"
41264126
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.13.0.tgz#42556cba011e1b0a2775b611cba6a8eca18e940d"
41274127
integrity sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==
@@ -4131,6 +4131,14 @@ [email protected], browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7
41314131
escalade "^3.0.1"
41324132
node-releases "^1.1.58"
41334133

4134+
browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
4135+
version "1.7.7"
4136+
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
4137+
integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=
4138+
dependencies:
4139+
caniuse-db "^1.0.30000639"
4140+
electron-to-chromium "^1.2.7"
4141+
41344142
41354143
version "1.4.0"
41364144
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:
44604468
version "1.0.30001023"
44614469
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001023.tgz#f856f71af16a5a44e81f1fcefc1673912a43da72"
44624470

4463-
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:
4471+
caniuse-db@^1.0.30000639:
4472+
version "1.0.30001112"
4473+
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001112.tgz#89cb249402af2ebf2c23a5585d1bd78cb5e38732"
4474+
integrity sha512-Xrn3lVEIsvAAUmFVHKKComfyCRM59NfuV3EwCXqs2XLgOxAqYgrfEs0vDk+Dk7KctlAMh6CH/CSd1srJt503ZA==
4475+
4476+
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001019, caniuse-lite@^1.0.30001020:
44644477
version "1.0.30001066"
44654478
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001066.tgz#0a8a58a10108f2b9bf38e7b65c237b12fd9c5f04"
44664479
integrity sha512-Gfj/WAastBtfxLws0RCh2sDbTK/8rJuSeZMecrSkNGYxPcv7EzblmDGfWQCFEQcSqYE2BRgQiJh8HOD07N5hIw==
44674480

4481+
caniuse-lite@^1.0.30001093:
4482+
version "1.0.30001112"
4483+
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001112.tgz#0fffc3b934ff56ff0548c37bc9dad7d882bcf672"
4484+
integrity sha512-J05RTQlqsatidif/38aN3PGULCLrg8OYQOlJUKbeYVzC2mGZkZLIztwRlB3MtrfLmawUmjFlNJvy/uhwniIe1Q==
4485+
44684486
44694487
version "1.0.0"
44704488
resolved "https://registry.yarnpkg.com/capitalize/-/capitalize-1.0.0.tgz#dc802c580aee101929020d2ca14b4ca8a0ae44be"
@@ -5376,7 +5394,7 @@ cross-spawn@^7.0.0:
53765394
shebang-command "^2.0.0"
53775395
which "^2.0.1"
53785396

5379-
crypto-browserify@^3.11.0:
5397+
crypto-browserify@3.12.0, crypto-browserify@^3.11.0:
53805398
version "3.12.0"
53815399
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
53825400
integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
@@ -6190,6 +6208,11 @@ ejs@^2.6.1:
61906208
version "2.7.4"
61916209
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
61926210

6211+
electron-to-chromium@^1.2.7:
6212+
version "1.3.526"
6213+
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.526.tgz#0e004899edf75afc172cce1b8189aac5dca646aa"
6214+
integrity sha512-HiroW5ZbGwgT8kCnoEO8qnGjoTPzJxduvV/Vv/wH63eo2N6Zj3xT5fmmaSPAPUM05iN9/5fIEkIg3owTtV6QZg==
6215+
61936216
electron-to-chromium@^1.3.488:
61946217
version "1.3.501"
61956218
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.501.tgz#faa17a2cb0105ee30d5e1ca87eae7d8e85dd3175"
@@ -8103,7 +8126,7 @@ inflight@^1.0.4:
81038126
once "^1.3.0"
81048127
wrappy "1"
81058128

8106-
inherits@2, [email protected], inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
8129+
inherits@2, [email protected], 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:
81078130
version "2.0.4"
81088131
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
81098132

@@ -11690,6 +11713,11 @@ [email protected]:
1169011713
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
1169111714
integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
1169211715

11716+
11717+
version "1.0.1"
11718+
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
11719+
integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
11720+
1169311721
path-case@^2.1.0:
1169411722
version "2.1.1"
1169511723
resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
@@ -13332,7 +13360,7 @@ read@1, read@~1.0.1:
1333213360
string_decoder "^1.1.1"
1333313361
util-deprecate "^1.0.1"
1333413362

13335-
readable-stream@^3.4.0, readable-stream@^3.6.0:
13363+
readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0:
1333613364
version "3.6.0"
1333713365
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
1333813366
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@@ -14712,6 +14740,14 @@ stealthy-require@^1.1.1:
1471214740
version "1.1.1"
1471314741
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
1471414742

14743+
14744+
version "3.0.0"
14745+
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f"
14746+
integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==
14747+
dependencies:
14748+
inherits "~2.0.4"
14749+
readable-stream "^3.5.0"
14750+
1471514751
stream-browserify@^2.0.1:
1471614752
version "2.0.2"
1471714753
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
@@ -15965,7 +16001,7 @@ vlq@^0.2.1, vlq@^0.2.2:
1596516001
version "0.2.3"
1596616002
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
1596716003

15968-
vm-browserify@^1.0.1:
16004+
vm-browserify@1.1.2, vm-browserify@^1.0.1:
1596916005
version "1.1.2"
1597016006
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
1597116007
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==

0 commit comments

Comments
 (0)