Fix Web Workers with Fast Refresh (#15145)
This commit is contained in:
parent
b088881a5d
commit
a131909857
9 changed files with 159 additions and 10 deletions
|
@ -122,7 +122,8 @@
|
|||
"tree-kill": "1.2.1",
|
||||
"typescript": "3.8.3",
|
||||
"wait-port": "0.2.2",
|
||||
"webpack-bundle-analyzer": "3.6.1"
|
||||
"webpack-bundle-analyzer": "3.6.1",
|
||||
"worker-loader": "2.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"browserslist": "^4.8.3",
|
||||
|
|
|
@ -6,8 +6,31 @@ import {
|
|||
// @ts-ignore exists in webpack 5
|
||||
RuntimeGlobals,
|
||||
version,
|
||||
compilation as Compilation,
|
||||
} from 'webpack'
|
||||
|
||||
// Shared between webpack 4 and 5:
|
||||
function injectRefreshFunctions(compilation: Compilation.Compilation) {
|
||||
const hookVars: typeof compilation['mainTemplate']['hooks']['requireExtensions'] = (compilation
|
||||
.mainTemplate.hooks as any).localVars
|
||||
|
||||
hookVars.tap('ReactFreshWebpackPlugin', (source) =>
|
||||
Template.asString([
|
||||
source,
|
||||
'',
|
||||
'// noop fns to prevent runtime errors during initialization',
|
||||
'if (typeof self !== "undefined") {',
|
||||
Template.indent('self.$RefreshReg$ = function () {};'),
|
||||
Template.indent('self.$RefreshSig$ = function () {'),
|
||||
Template.indent(Template.indent('return function (type) {')),
|
||||
Template.indent(Template.indent(Template.indent('return type;'))),
|
||||
Template.indent(Template.indent('};')),
|
||||
Template.indent('};'),
|
||||
'}',
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
function webpack4(compiler: Compiler) {
|
||||
// Webpack 4 does not have a method to handle interception of module
|
||||
// execution.
|
||||
|
@ -16,6 +39,8 @@ function webpack4(compiler: Compiler) {
|
|||
// https://github.com/webpack/webpack/blob/4c644bf1f7cb067c748a52614500e0e2182b2700/lib/MainTemplate.js#L200
|
||||
|
||||
compiler.hooks.compilation.tap('ReactFreshWebpackPlugin', (compilation) => {
|
||||
injectRefreshFunctions(compilation)
|
||||
|
||||
const hookRequire: typeof compilation['mainTemplate']['hooks']['requireExtensions'] = (compilation
|
||||
.mainTemplate.hooks as any).require
|
||||
|
||||
|
@ -106,6 +131,8 @@ function webpack5(compiler: Compiler) {
|
|||
}
|
||||
|
||||
compiler.hooks.compilation.tap('ReactFreshWebpackPlugin', (compilation) => {
|
||||
injectRefreshFunctions(compilation)
|
||||
|
||||
// @ts-ignore Exists in webpack 5
|
||||
compilation.hooks.additionalTreeRuntimeRequirements.tap(
|
||||
'ReactFreshWebpackPlugin',
|
||||
|
|
|
@ -13,14 +13,6 @@ declare const self: Window & RefreshRuntimeGlobals
|
|||
// Hook into ReactDOM initialization
|
||||
RefreshRuntime.injectIntoGlobalHook(self)
|
||||
|
||||
// noop fns to prevent runtime errors during initialization
|
||||
self.$RefreshReg$ = function () {}
|
||||
self.$RefreshSig$ = function () {
|
||||
return function (type) {
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
// Register global helpers
|
||||
self.$RefreshHelpers$ = RefreshHelpers
|
||||
|
||||
|
|
4
test/integration/worker-loader/lib/demo.worker.js
Normal file
4
test/integration/worker-loader/lib/demo.worker.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
const { Expensive } = require('./sharedCode')
|
||||
|
||||
Expensive()
|
||||
self.postMessage(true)
|
17
test/integration/worker-loader/lib/sharedCode.js
Normal file
17
test/integration/worker-loader/lib/sharedCode.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
export function Expensive() {
|
||||
const start = performance.now()
|
||||
let i = 99999
|
||||
|
||||
const bigArray = []
|
||||
while (--i) {
|
||||
bigArray.push(i)
|
||||
}
|
||||
|
||||
const endTime = performance.now()
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
console.log('[WORKER] Completed expensive function in', endTime - start)
|
||||
} else {
|
||||
console.log('[WEB] Completed expensive function in', endTime - start)
|
||||
}
|
||||
}
|
18
test/integration/worker-loader/next.config.js
Normal file
18
test/integration/worker-loader/next.config.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
module.exports = {
|
||||
webpack: (config, { isServer }) => {
|
||||
config.module.rules.unshift({
|
||||
test: /\.worker\.(js|ts|tsx)$/,
|
||||
loader: 'worker-loader',
|
||||
options: {
|
||||
name: 'static/[hash].worker.js',
|
||||
publicPath: '/_next/',
|
||||
},
|
||||
})
|
||||
|
||||
if (!isServer) {
|
||||
config.output.globalObject = 'self'
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
}
|
39
test/integration/worker-loader/pages/index.js
Normal file
39
test/integration/worker-loader/pages/index.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import * as React from 'react'
|
||||
import DemoWorker from '../lib/demo.worker'
|
||||
import { Expensive } from '../lib/sharedCode'
|
||||
|
||||
export default function Home() {
|
||||
const [expensiveWebStatus, setExpensiveWebStatus] = React.useState('WAIT')
|
||||
const [expensiveWorkerStatus, setExpensiveWorkerComplete] = React.useState(
|
||||
'WAIT'
|
||||
)
|
||||
const worker = React.useRef()
|
||||
|
||||
React.useEffect(() => {
|
||||
worker.current = new DemoWorker()
|
||||
worker.current.addEventListener('message', ({ data }) => {
|
||||
if (data) {
|
||||
setExpensiveWorkerComplete('PASS')
|
||||
}
|
||||
})
|
||||
worker.current.addEventListener('error', (data) => {
|
||||
setExpensiveWorkerComplete('FAIL')
|
||||
})
|
||||
}, [worker, setExpensiveWorkerComplete])
|
||||
React.useEffect(() => {
|
||||
try {
|
||||
Expensive()
|
||||
setExpensiveWebStatus('PASS')
|
||||
} catch {
|
||||
setExpensiveWebStatus('FAIL')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>$RefreshRegistry repro</h1>
|
||||
<div id="web-status">Web: {expensiveWebStatus}</div>
|
||||
<div id="worker-status">Worker: {expensiveWorkerStatus}</div>
|
||||
</main>
|
||||
)
|
||||
}
|
35
test/integration/worker-loader/test/index.test.js
Normal file
35
test/integration/worker-loader/test/index.test.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* eslint-env jest */
|
||||
|
||||
import { check, findPort, killApp, launchApp } from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
import { join } from 'path'
|
||||
|
||||
const appDir = join(__dirname, '../')
|
||||
const context = {}
|
||||
|
||||
jest.setTimeout(1000 * 60 * 2)
|
||||
|
||||
describe('Web Workers with Fast Refresh', () => {
|
||||
beforeAll(async () => {
|
||||
context.appPort = await findPort()
|
||||
context.server = await launchApp(appDir, context.appPort)
|
||||
})
|
||||
afterAll(() => {
|
||||
killApp(context.server)
|
||||
})
|
||||
|
||||
it('should pass on both client and worker', async () => {
|
||||
let browser
|
||||
try {
|
||||
browser = await webdriver(context.appPort, '/')
|
||||
await browser.waitForElementByCss('#web-status')
|
||||
await check(() => browser.elementByCss('#web-status').text(), /PASS/i)
|
||||
await browser.waitForElementByCss('#worker-status')
|
||||
await check(() => browser.elementByCss('#worker-status').text(), /PASS/i)
|
||||
} finally {
|
||||
if (browser) {
|
||||
await browser.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
18
yarn.lock
18
yarn.lock
|
@ -9853,7 +9853,7 @@ loader-utils@2.0.0, loader-utils@^2.0.0:
|
|||
emojis-list "^3.0.0"
|
||||
json5 "^2.1.2"
|
||||
|
||||
loader-utils@^1.4.0:
|
||||
loader-utils@^1.0.0, loader-utils@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
|
||||
dependencies:
|
||||
|
@ -14193,6 +14193,14 @@ schema-utils@2.6.6, schema-utils@^2.0.0, schema-utils@^2.6.1, schema-utils@^2.6.
|
|||
ajv "^6.12.0"
|
||||
ajv-keywords "^3.4.1"
|
||||
|
||||
schema-utils@^0.4.0:
|
||||
version "0.4.7"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187"
|
||||
integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==
|
||||
dependencies:
|
||||
ajv "^6.1.0"
|
||||
ajv-keywords "^3.1.0"
|
||||
|
||||
schema-utils@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
|
||||
|
@ -16244,6 +16252,14 @@ worker-farm@^1.7.0:
|
|||
dependencies:
|
||||
errno "~0.1.7"
|
||||
|
||||
worker-loader@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/worker-loader/-/worker-loader-2.0.0.tgz#45fda3ef76aca815771a89107399ee4119b430ac"
|
||||
integrity sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==
|
||||
dependencies:
|
||||
loader-utils "^1.0.0"
|
||||
schema-utils "^0.4.0"
|
||||
|
||||
wrap-ansi@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
|
||||
|
|
Loading…
Reference in a new issue