Add runtime to hotUpdateMainFilename (#26256)
Updates the hotUpdateChunk to include `[runtime]` for web workers support. Fixes #26152 Fixes #19865 Fixes #26144 ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. ## Documentation / Examples - [ ] Make sure the linting passes
This commit is contained in:
parent
98acfaf8cc
commit
88ed5269b5
11 changed files with 143 additions and 15 deletions
|
@ -79,6 +79,7 @@
|
|||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"execa": "2.0.3",
|
||||
"express": "4.17.0",
|
||||
"faker": "5.5.3",
|
||||
"faunadb": "2.6.1",
|
||||
"firebase": "7.14.5",
|
||||
"fs-extra": "9.0.0",
|
||||
|
|
|
@ -510,7 +510,7 @@ export default async function getBaseWebpackConfig(
|
|||
|
||||
// Contains various versions of the Webpack SplitChunksPlugin used in different build types
|
||||
const splitChunksConfigs: {
|
||||
[propName: string]: webpack.Options.SplitChunksOptions
|
||||
[propName: string]: webpack.Options.SplitChunksOptions | false
|
||||
} = {
|
||||
dev: {
|
||||
cacheGroups: {
|
||||
|
@ -611,9 +611,9 @@ export default async function getBaseWebpackConfig(
|
|||
}
|
||||
|
||||
// Select appropriate SplitChunksPlugin config for this build
|
||||
let splitChunksConfig: webpack.Options.SplitChunksOptions
|
||||
let splitChunksConfig: webpack.Options.SplitChunksOptions | false
|
||||
if (dev) {
|
||||
splitChunksConfig = splitChunksConfigs.dev
|
||||
splitChunksConfig = isWebpack5 ? false : splitChunksConfigs.dev
|
||||
} else {
|
||||
splitChunksConfig = splitChunksConfigs.prodGranular
|
||||
}
|
||||
|
@ -940,7 +940,7 @@ export default async function getBaseWebpackConfig(
|
|||
: {}),
|
||||
// we must set publicPath to an empty value to override the default of
|
||||
// auto which doesn't work in IE11
|
||||
publicPath: '',
|
||||
publicPath: `${config.assetPrefix || ''}/_next/`,
|
||||
path:
|
||||
isServer && isWebpack5 && !dev
|
||||
? path.join(outputPath, 'chunks')
|
||||
|
@ -959,7 +959,7 @@ export default async function getBaseWebpackConfig(
|
|||
? 'static/webpack/[id].[fullhash].hot-update.js'
|
||||
: 'static/webpack/[id].[hash].hot-update.js',
|
||||
hotUpdateMainFilename: isWebpack5
|
||||
? 'static/webpack/[fullhash].hot-update.json'
|
||||
? 'static/webpack/[fullhash].[runtime].hot-update.json'
|
||||
: 'static/webpack/[hash].hot-update.json',
|
||||
// This saves chunks with the name given via `import()`
|
||||
chunkFilename: isServer
|
||||
|
|
|
@ -37,7 +37,12 @@ async function tryApplyUpdates() {
|
|||
return
|
||||
}
|
||||
try {
|
||||
const res = await fetch(`${hotUpdatePath}${curHash}.hot-update.json`)
|
||||
const res = await fetch(
|
||||
typeof __webpack_runtime_id__ !== 'undefined'
|
||||
? // eslint-disable-next-line no-undef
|
||||
`${hotUpdatePath}${curHash}.${__webpack_runtime_id__}.hot-update.json`
|
||||
: `${hotUpdatePath}${curHash}.hot-update.json`
|
||||
)
|
||||
const jsonData = await res.json()
|
||||
const curPage = page === '/' ? 'index' : page
|
||||
// webpack 5 uses an array instead
|
||||
|
|
|
@ -402,6 +402,8 @@ describe('AMP Usage', () => {
|
|||
|
||||
it('should not reload unless the page is edited for an AMP page', async () => {
|
||||
let browser
|
||||
const hmrTestPagePath = join(__dirname, '../', 'pages', 'hmr', 'test.js')
|
||||
const originalContent = readFileSync(hmrTestPagePath, 'utf8')
|
||||
try {
|
||||
await renderViaHTTP(dynamicAppPort, '/hmr/test')
|
||||
|
||||
|
@ -409,15 +411,7 @@ describe('AMP Usage', () => {
|
|||
await check(() => browser.elementByCss('p').text(), /I'm an AMP page!/)
|
||||
|
||||
const origDate = await browser.elementByCss('span').text()
|
||||
const hmrTestPagePath = join(
|
||||
__dirname,
|
||||
'../',
|
||||
'pages',
|
||||
'hmr',
|
||||
'test.js'
|
||||
)
|
||||
|
||||
const originalContent = readFileSync(hmrTestPagePath, 'utf8')
|
||||
const editedContent = originalContent.replace(
|
||||
`This is the hot AMP page.`,
|
||||
'replaced it!'
|
||||
|
@ -456,6 +450,7 @@ describe('AMP Usage', () => {
|
|||
|
||||
await check(() => getBrowserBodyText(browser), /I'm an AMP page!/)
|
||||
} finally {
|
||||
writeFileSync(hmrTestPagePath, originalContent, 'utf8')
|
||||
await browser.close()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -144,7 +144,7 @@ describe('Build Output', () => {
|
|||
const webpackSizeValue = webpackSize.endsWith('kB')
|
||||
? parseFloat(webpackSize)
|
||||
: parseFloat(webpackSize) / 1000
|
||||
expect(webpackSizeValue).toBeCloseTo(gz ? 0.76 : 1.45, 2)
|
||||
expect(webpackSizeValue).toBeCloseTo(gz ? 0.766 : 1.46, 2)
|
||||
expect(webpackSize.endsWith('kB') || webpackSize.endsWith(' B')).toBe(
|
||||
true
|
||||
)
|
||||
|
|
17
test/integration/worker-webpack5/lib/sharedCode.js
Normal file
17
test/integration/worker-webpack5/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)
|
||||
}
|
||||
}
|
8
test/integration/worker-webpack5/lib/worker.js
Normal file
8
test/integration/worker-webpack5/lib/worker.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Expensive } from './sharedCode'
|
||||
import faker from 'faker'
|
||||
|
||||
// Ensure a large libraries is added so that splitChunks would trigger if enabled.
|
||||
console.log(faker)
|
||||
|
||||
Expensive()
|
||||
self.postMessage(true)
|
1
test/integration/worker-webpack5/next.config.js
Normal file
1
test/integration/worker-webpack5/next.config.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = {}
|
38
test/integration/worker-webpack5/pages/index.js
Normal file
38
test/integration/worker-webpack5/pages/index.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import * as React from 'react'
|
||||
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 Worker(new URL('../lib/worker.js', import.meta.url))
|
||||
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>
|
||||
)
|
||||
}
|
58
test/integration/worker-webpack5/test/index.test.js
Normal file
58
test/integration/worker-webpack5/test/index.test.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* eslint-env jest */
|
||||
import {
|
||||
check,
|
||||
findPort,
|
||||
killApp,
|
||||
launchApp,
|
||||
nextStart,
|
||||
nextBuild,
|
||||
} from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
import { join } from 'path'
|
||||
|
||||
const appDir = join(__dirname, '../')
|
||||
|
||||
jest.setTimeout(1000 * 60 * 2)
|
||||
|
||||
let appPort
|
||||
let app
|
||||
|
||||
const runTests = () => {
|
||||
it('should pass on both client and worker', async () => {
|
||||
let browser
|
||||
try {
|
||||
browser = await webdriver(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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Web Workers with webpack 5', () => {
|
||||
describe('dev mode', () => {
|
||||
beforeAll(async () => {
|
||||
appPort = await findPort()
|
||||
app = await launchApp(appDir, appPort)
|
||||
})
|
||||
afterAll(() => killApp(app))
|
||||
|
||||
runTests()
|
||||
})
|
||||
|
||||
describe('server mode', () => {
|
||||
beforeAll(async () => {
|
||||
await nextBuild(appDir)
|
||||
appPort = await findPort()
|
||||
app = await nextStart(appDir, appPort)
|
||||
})
|
||||
afterAll(() => killApp(app))
|
||||
|
||||
runTests()
|
||||
})
|
||||
})
|
|
@ -8488,6 +8488,11 @@ extsprintf@^1.2.0:
|
|||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||
|
||||
faker@5.5.3:
|
||||
version "5.5.3"
|
||||
resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e"
|
||||
integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
|
||||
|
|
Loading…
Reference in a new issue