Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update server-only changes HMR handling #34298

Merged
merged 12 commits into from Feb 16, 2022
65 changes: 50 additions & 15 deletions packages/next/server/dev/hot-reloader.ts
Expand Up @@ -3,7 +3,7 @@ import { IncomingMessage, ServerResponse } from 'http'
import { WebpackHotMiddleware } from './hot-middleware'
import { join, relative, isAbsolute } from 'path'
import { UrlObject } from 'url'
import { webpack } from 'next/dist/compiled/webpack/webpack'
import { webpack, StringXor } from 'next/dist/compiled/webpack/webpack'
import type { webpack5 } from 'next/dist/compiled/webpack/webpack'
import {
createEntrypoints,
Expand Down Expand Up @@ -594,21 +594,56 @@ export default class HotReloader {
const trackPageChanges =
(pageHashMap: Map<string, string>, changedItems: Set<string>) =>
(stats: webpack5.Compilation) => {
stats.entrypoints.forEach((entry, key) => {
if (key.startsWith('pages/')) {
// TODO this doesn't handle on demand loaded chunks
entry.chunks.forEach((chunk: any) => {
if (chunk.id === key) {
const prevHash = pageHashMap.get(key)

if (prevHash && prevHash !== chunk.hash) {
changedItems.add(key)
try {
stats.entrypoints.forEach((entry, key) => {
if (key.startsWith('pages/')) {
// TODO this doesn't handle on demand loaded chunks
entry.chunks.forEach((chunk) => {
if (chunk.id === key) {
const modsIterable: any =
stats.chunkGraph.getChunkModulesIterable(chunk)

let chunksHash = new StringXor()

modsIterable.forEach((mod: any) => {
if (
mod.resource &&
mod.resource.replace(/\\/g, '/').includes(key)
) {
// use original source to calculate hash since mod.hash
// includes the source map in development which changes
// every time for both server and client so we calculate
// the hash without the source map for the page module
const hash = require('crypto')
.createHash('sha256')
.update(mod.originalSource().buffer())
.digest()
.toString('hex')

chunksHash.add(hash)
} else {
// for non-pages we can use the module hash directly
const hash = stats.chunkGraph.getModuleHash(
mod,
chunk.runtime
)
chunksHash.add(hash)
}
})
const prevHash = pageHashMap.get(key)
const curHash = chunksHash.toString()

if (prevHash && prevHash !== curHash) {
changedItems.add(key)
}
pageHashMap.set(key, curHash)
}
pageHashMap.set(key, chunk.hash)
}
})
}
})
})
}
})
} catch (err) {
console.error(err)
}
}

multiCompiler.compilers[0].hooks.emit.tap(
Expand Down
1 change: 1 addition & 0 deletions packages/next/types/webpack.d.ts
Expand Up @@ -35,6 +35,7 @@ declare module 'next/dist/compiled/webpack/webpack' {
export let BasicEvaluatedExpression: any
export let GraphHelpers: any
export let sources: typeof webpackSources
export let StringXor: any
// TODO change this to webpack5
export { webpack4 as webpack, loader, webpack4, webpack5 }
}
Expand Down
@@ -0,0 +1,3 @@
{
"hello": "world"
}
@@ -1,4 +1,5 @@
import { useRouter } from 'next/router'
import data from '../lib/data.json'

export default function Gsp(props) {
if (useRouter().isFallback) {
Expand All @@ -19,6 +20,7 @@ export const getStaticProps = async () => {
return {
props: {
count,
data,
random: Math.random(),
},
}
Expand Down