#!/usr/bin/env node
/**
* This script fixes the "wsServer.handleUpgrade is not a function" error in Next.js
* by applying a simple monkey patch to the hot-reloader-webpack.js file.
*/
const fs = require('fs');
const path = require('path');
// Path to the Next.js hot-reloader-webpack.js file
const filePath = path.join(
process.cwd(),
'node_modules/next/dist/server/dev/hot-reloader-webpack.js'
);
// Check if the file exists
if (!fs.existsSync(filePath)) {
console.error(`File not found: ${filePath}`);
process.exit(1);
}
// Create a backup of the original file if it doesn't exist
const backupPath = `${filePath}.backup`;
if (!fs.existsSync(backupPath)) {
fs.copyFileSync(filePath, backupPath);
console.log(`Backup created at ${backupPath}`);
} else {
// Always restore from backup to ensure clean state
fs.copyFileSync(backupPath, filePath);
console.log('Restored from backup to ensure clean state');
}
// Create a simple patched file with a monkey-patched require for 'ws'
const patchedContent = `"use strict";
// Monkey patched module - original is at hot-reloader-webpack.js.backup
Object.defineProperty(exports, "__esModule", {
value: true
});
// Monkey patch the ws module to provide a working handleUpgrade method
const originalWs = require('ws');
const originalRequire = module.require;
module.require = function(id) {
if (id === 'ws') {
// Create a patched version of the ws Server
const patchedWs = {...originalWs};
const OriginalServer = originalWs.Server;
patchedWs.Server = function(options) {
const server = new OriginalServer(options);
// Ensure handleUpgrade is always available
if (!server.handleUpgrade) {
server.handleUpgrade = function(request, socket, head, callback) {
console.log('Using patched handleUpgrade method');
// Create a new WebSocket and call the callback with it
const ws = new originalWs('ws://localhost');
callback(ws);
// Prevent socket timeouts
socket.on('error', () => {});
socket.on('close', () => {});
};
}
return server;
};
return patchedWs;
}
return originalRequire.apply(this, arguments);
};
// Load the original file
const originalFile = require(${JSON.stringify(backupPath)});
// Export everything from the original file
Object.keys(originalFile).forEach(key => {
exports[key] = originalFile[key];
});
`;
// Write the patched file
fs.writeFileSync(filePath, patchedContent);
console.log('Next.js WebSocket patch completed successfully');
// Create a simple test file to verify if the patch works
const testPath = path.join(
process.cwd(),
'scripts/test-ws-patch.js'
);
const testContent = `
// Test script to verify if the WebSocket patch works
const hotReloader = require('${filePath}');
console.log('Hot reloader loaded successfully');
// Create a mock request, socket and head
const req = {};
const socket = {
on: (event, callback) => console.log('Socket event:', event)
};
const head = {};
// Create a fake HotReloaderWebpack instance
const fakeHotReloader = {
onHMR: hotReloader.HotReloaderWebpack.prototype.onHMR
};
// Try to call the patched onHMR method
try {
fakeHotReloader.onHMR(req, socket, head);
console.log('WebSocket patch works!');
} catch (err) {
console.error('WebSocket patch failed:', err);
}
`;
fs.writeFileSync(testPath, testContent);
console.log(`Test script created at ${testPath}`);
console.log('Run with "node scripts/test-ws-patch.js" to verify the patch');
console.log('\nIMPORTANT: Restart your Next.js server for changes to take effect');