Skip to content

Commit

Permalink
[core] Patch hmr endpoint
Browse files Browse the repository at this point in the history
Next.js uses a Websocket endpoint with a url that is not configurable. This commit patches this url on the fly using a Websocket proxy hack.

closes #7
  • Loading branch information
HaNdTriX committed Jan 13, 2023
1 parent d5e3382 commit 8ffc7e2
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 37 deletions.
23 changes: 1 addition & 22 deletions example/main/preload.js
@@ -1,4 +1,4 @@
const { ipcRenderer, contextBridge, webFrame } = require("electron");
const { ipcRenderer, contextBridge } = require("electron");

contextBridge.exposeInMainWorld("electron", {
message: {
Expand All @@ -7,24 +7,3 @@ contextBridge.exposeInMainWorld("electron", {
off: (handler) => ipcRenderer.off("message", handler),
},
});

// Next.js Websocket DevServer is not listining on our custom scheme.
// This is why we need to monkey patch the global WebSocket constructor
// to use the correct DevServer url
// More info: https://github.com/HaNdTriX/next-electron-server/issues/7
if (process.env.NEXT_ELECTON_SERVER_DEV === "true") {
webFrame.executeJavaScript(`Object.defineProperty(globalThis, 'WebSocket', {
value: new Proxy(WebSocket, {
construct: (Target, [url, protocols]) => {
if (url.endsWith('/_next/webpack-hmr')) {
// Fix the Next.js hmr client url
return new Target("ws://localhost:${
process.env.NEXT_ELECTON_SERVER_PORT || 3000
}/_next/webpack-hmr", protocols)
} else {
return new Target(url, protocols)
}
}
})
});`);
}
61 changes: 46 additions & 15 deletions index.js
Expand Up @@ -15,11 +15,6 @@ module.exports = async function serveNextAt(uri, options = {}) {
partition,
} = options;

// Expose the server port and dev flag as en environment variable
// This allows us to dynamically expose the port to the preload script
process.env.NEXT_ELECTON_SERVER_PORT = port;
process.env.NEXT_ELECTON_SERVER_DEV = dev;

// Validate
if (!scheme) {
const error = new Error(
Expand Down Expand Up @@ -70,17 +65,53 @@ module.exports = async function serveNextAt(uri, options = {}) {
"next-electron-server",
`- Serving files via ${scheme}://${host} from http://localhost:${port}`
);
protocol.registerStreamProtocol(scheme, ({ url, ...request }, next) => {

protocol.registerStreamProtocol(scheme, (request, next) => {
const patchedRequest = {
...request,
url: request.url
.replace(`${scheme}://${host}`, `http://localhost:${port}`)
.replace(/\/$/, ""),
};

// Patch Next.js webpack.js to fix the hmr client url
if (
patchedRequest.url.includes(`:${port}/_next/static/chunks/webpack.js`)
) {
console.log(
"\x1b[33m%s\x1b[0m",
"next-electon-server",
"- Patching _next/static/chunks/webpack.js"
);
return cloneAndRetryRequest(patchedRequest, (response) => {
const { PassThrough } = require("stream");
const stream = new PassThrough();

// Patch the webpack.js file to fix the hmr client url:
// We do this, by adding a Websocket proxy that fixes the url
// to the top of the response body
stream.push(`
Object.defineProperty(globalThis, 'WebSocket', {
value: new Proxy(WebSocket, {
construct: (Target, [url, protocols]) => {
if (url.endsWith('/_next/webpack-hmr')) {
// Fix the Next.js hmr client url
return new Target("ws://localhost:${port}/_next/webpack-hmr", protocols)
} else {
return new Target(url, protocols)
}
}
})
});
`);

response.pipe(stream);
next(stream);
});
}

// Proxy request
cloneAndRetryRequest(
{
...request,
url: url
.replace(`${scheme}://${host}`, `http://localhost:${port}`)
.replace(/\/$/, ""),
},
next
);
return cloneAndRetryRequest(patchedRequest, next);
});
} else {
// PRODUCTION: Serve Next.js files using a static handler
Expand Down

0 comments on commit 8ffc7e2

Please sign in to comment.