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 HMR for next-api #5814

Merged
merged 10 commits into from
Aug 29, 2023
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
9 changes: 7 additions & 2 deletions crates/turbopack-cli/js/src/entry/client.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { connect } from "@vercel/turbopack-ecmascript-runtime/dev/client/hmr-client";
import { connectHMR } from "@vercel/turbopack-ecmascript-runtime/dev/client/websocket";
import {
connectHMR,
addMessageListener,
sendMessage,
} from "@vercel/turbopack-ecmascript-runtime/dev/client/websocket";

export function initializeHMR(options: { assetPrefix: string }) {
connect({
assetPrefix: options.assetPrefix,
addMessageListener,
sendMessage,
});
connectHMR({
assetPrefix: options.assetPrefix,
Expand Down
4 changes: 3 additions & 1 deletion crates/turbopack-ecmascript-hmr-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ impl Display for ResourceIdentifier {
}

#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
#[serde(tag = "type")]
pub enum ClientMessage {
#[serde(rename = "turbopack-subscribe")]
Subscribe {
#[serde(flatten)]
resource: ResourceIdentifier,
},
#[serde(rename = "turbopack-unsubscribe")]
Unsubscribe {
#[serde(flatten)]
resource: ResourceIdentifier,
Expand Down
1 change: 1 addition & 0 deletions crates/turbopack-ecmascript-runtime/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"check:dev-runtime-none": "tsc -p src/dev/runtime/none"
},
"exports": {
".": "./src/main.js",
"./*": "./src/*.ts"
},
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,32 @@
/// <reference path="../runtime/base/protocol.d.ts" />
/// <reference path="../runtime/base/extensions.d.ts" />

import { addEventListener, sendMessage } from "./websocket";
import {
addMessageListener as turboSocketAddMessageListener,
sendMessage as turboSocketSendMessage,
} from "./websocket";
type SendMessage = typeof import("./websocket").sendMessage;

export type ClientOptions = {
assetPrefix: string;
addMessageListener: typeof import("./websocket").addMessageListener;
sendMessage: SendMessage;
};

export function connect({ assetPrefix }: ClientOptions) {
addEventListener((event) => {
switch (event.type) {
case "connected":
handleSocketConnected();
export function connect({
// TODO(WEB-1465) Remove this backwards compat fallback once
// vercel/next.js#54586 is merged.
addMessageListener = turboSocketAddMessageListener,
// TODO(WEB-1465) Remove this backwards compat fallback once
// vercel/next.js#54586 is merged.
sendMessage = turboSocketSendMessage,
}: ClientOptions) {
addMessageListener((msg) => {
switch (msg.type) {
case "turbopack-connected":
handleSocketConnected(sendMessage);
break;
case "message":
const msg: ServerMessage = JSON.parse(event.message.data);
handleSocketMessage(msg);
default:
handleSocketMessage(msg.data as ServerMessage);
break;
}
});
Expand All @@ -28,13 +39,13 @@ export function connect({ assetPrefix }: ClientOptions) {
}
globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS = {
push: ([chunkPath, callback]: [ChunkPath, UpdateCallback]) => {
subscribeToChunkUpdate(chunkPath, callback);
subscribeToChunkUpdate(chunkPath, sendMessage, callback);
},
};

if (Array.isArray(queued)) {
for (const [chunkPath, callback] of queued) {
subscribeToChunkUpdate(chunkPath, callback);
subscribeToChunkUpdate(chunkPath, sendMessage, callback);
}
}
}
Expand All @@ -46,7 +57,7 @@ type UpdateCallbackSet = {

const updateCallbackSets: Map<ResourceKey, UpdateCallbackSet> = new Map();

function sendJSON(message: ClientMessage) {
function sendJSON(sendMessage: SendMessage, message: ClientMessage) {
sendMessage(JSON.stringify(message));
}

Expand All @@ -59,23 +70,26 @@ function resourceKey(resource: ResourceIdentifier): ResourceKey {
});
}

function subscribeToUpdates(resource: ResourceIdentifier): () => void {
sendJSON({
type: "subscribe",
function subscribeToUpdates(
sendMessage: SendMessage,
resource: ResourceIdentifier
): () => void {
sendJSON(sendMessage, {
type: "turbopack-subscribe",
...resource,
});

return () => {
sendJSON({
type: "unsubscribe",
sendJSON(sendMessage, {
type: "turbopack-unsubscribe",
...resource,
});
};
}

function handleSocketConnected() {
function handleSocketConnected(sendMessage: SendMessage) {
for (const key of updateCallbackSets.keys()) {
subscribeToUpdates(JSON.parse(key));
subscribeToUpdates(sendMessage, JSON.parse(key));
}
}

Expand Down Expand Up @@ -515,29 +529,39 @@ function handleSocketMessage(msg: ServerMessage) {
}
}

export function subscribeToChunkUpdate(
function subscribeToChunkUpdate(
chunkPath: ChunkPath,
sendMessage: SendMessage,
callback: UpdateCallback
): () => void {
return subscribeToUpdate(
{
path: chunkPath,
},
sendMessage,
callback
);
}

export function subscribeToUpdate(
resource: ResourceIdentifier,
sendMessage: SendMessage,
callback: UpdateCallback
) {
// TODO(WEB-1465) Remove this backwards compat fallback once
// vercel/next.js#54586 is merged.
if (callback === undefined) {
callback = sendMessage;
sendMessage = turboSocketSendMessage;
}

const key = resourceKey(resource);
let callbackSet: UpdateCallbackSet;
const existingCallbackSet = updateCallbackSets.get(key);
if (!existingCallbackSet) {
callbackSet = {
callbacks: new Set([callback]),
unsubscribe: subscribeToUpdates(resource),
unsubscribe: subscribeToUpdates(sendMessage, resource),
};
updateCallbackSets.set(key, callbackSet);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./hmr-client";
export * from "./websocket";
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Adapted from https://github.com/vercel/next.js/blob/canary/packages/next/client/dev/error-overlay/websocket.ts

let source: WebSocket;
const eventCallbacks: ((event: WebsocketEvent) => void)[] = [];
const eventCallbacks: ((msg: WebSocketMessage) => void)[] = [];

// TODO: add timeout again
// let lastActivity = Date.now()
Expand All @@ -17,16 +17,16 @@ function getSocketProtocol(assetPrefix: string): string {
return protocol === "http:" ? "ws" : "wss";
}

type WebsocketEvent =
export type WebSocketMessage =
| {
type: "connected";
type: "turbopack-connected";
}
| {
type: "message";
message: MessageEvent;
type: "turbopack-message";
data: Record<string, any>;
};

export function addEventListener(cb: (event: WebsocketEvent) => void) {
export function addMessageListener(cb: (msg: WebSocketMessage) => void) {
eventCallbacks.push(cb);
}

Expand All @@ -51,10 +51,9 @@ export function connectHMR(options: HMROptions) {
console.log("[HMR] connecting...");

function handleOnline() {
const connected = { type: "turbopack-connected" as const };
eventCallbacks.forEach((cb) => {
cb({
type: "connected",
});
cb(connected);
});

if (options.log) console.log("[HMR] connected");
Expand All @@ -64,11 +63,12 @@ export function connectHMR(options: HMROptions) {
function handleMessage(event: MessageEvent) {
// lastActivity = Date.now()

const message = {
type: "turbopack-message" as const,
data: JSON.parse(event.data),
};
eventCallbacks.forEach((cb) => {
cb({
type: "message",
message: event,
});
cb(message);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ type ResourceIdentifier = {
};

type ClientMessageSubscribe = {
type: "subscribe";
type: "turbopack-subscribe";
} & ResourceIdentifier;

type ClientMessageUnsubscribe = {
type: "unsubscribe";
type: "turbopack-unsubscribe";
} & ResourceIdentifier;

type ClientMessage = ClientMessageSubscribe | ClientMessageUnsubscribe;
Expand Down
1 change: 1 addition & 0 deletions crates/turbopack-ecmascript-runtime/js/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// required for NCC to work