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

Fix next dev not working for server components in app #37403

Merged
merged 2 commits into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,11 @@ export default async function getBaseWebpackConfig(
const {
NextJsRequireCacheHotReloader,
} = require('./webpack/plugins/nextjs-require-cache-hot-reloader')
const devPlugins = [new NextJsRequireCacheHotReloader()]
const devPlugins = [
new NextJsRequireCacheHotReloader({
hasServerComponents: config.experimental.serverComponents,
}),
]

if (isClient || isEdgeServer) {
devPlugins.push(new webpack.HotModuleReplacementPlugin())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { clearModuleContext } from '../../../server/web/sandbox'
import { realpathSync } from 'fs'
import path from 'path'
import isError from '../../../lib/is-error'
import { NEXT_CLIENT_SSR_ENTRY_SUFFIX } from '../../../shared/lib/constants'

type Compiler = webpack5.Compiler
type WebpackPluginInstance = webpack5.WebpackPluginInstance
Expand Down Expand Up @@ -34,25 +35,52 @@ function deleteCache(filePath: string) {
for (const child of module.children) {
child.parent = null
}
delete require.cache[filePath]
return true
}
delete require.cache[filePath]
return false
}

const PLUGIN_NAME = 'NextJsRequireCacheHotReloader'

// This plugin flushes require.cache after emitting the files. Providing 'hot reloading' of server files.
export class NextJsRequireCacheHotReloader implements WebpackPluginInstance {
prevAssets: any = null
hasServerComponents: boolean
previousOutputPathsWebpack5: Set<string> = new Set()
currentOutputPathsWebpack5: Set<string> = new Set()

constructor(opts: { hasServerComponents: boolean }) {
this.hasServerComponents = opts.hasServerComponents
}

apply(compiler: Compiler) {
compiler.hooks.assetEmitted.tap(
PLUGIN_NAME,
(_file, { targetPath, content }) => {
(file, { targetPath, content }) => {
this.currentOutputPathsWebpack5.add(targetPath)
deleteCache(targetPath)
clearModuleContext(targetPath, content.toString('utf-8'))

if (
this.hasServerComponents &&
/^(app|pages)\//.test(file) &&
/\.js$/.test(targetPath)
) {
// Also clear the potential __sc_client__ cache.
// @TODO: Investigate why the client ssr bundle isn't emitted as an asset here.
const clientComponentsSSRTarget = targetPath.replace(
/\.js$/,
NEXT_CLIENT_SSR_ENTRY_SUFFIX + '.js'
)
if (deleteCache(clientComponentsSSRTarget)) {
this.currentOutputPathsWebpack5.add(clientComponentsSSRTarget)
clearModuleContext(
clientComponentsSSRTarget,
content.toString('utf-8')
)
}
}
}
)

Expand Down
2 changes: 0 additions & 2 deletions packages/next/server/dev/hot-reloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ export default class HotReloader {
private distDir: string
private webpackHotMiddleware?: WebpackHotMiddleware
private config: NextConfigComplete
private runtime?: 'nodejs' | 'edge'
private hasServerComponents: boolean
private hasReactRoot: boolean
public clientStats: webpack5.Stats | null
Expand Down Expand Up @@ -209,7 +208,6 @@ export default class HotReloader {
this.serverPrevDocumentHash = null

this.config = config
this.runtime = config.experimental.runtime
this.hasReactRoot = !!process.env.__NEXT_REACT_ROOT
this.hasServerComponents =
this.hasReactRoot && !!config.experimental.serverComponents
Expand Down