Bug
The Vite plugin's configureServer hook adds a new change listener to server.watcher every time it's called, but never removes it. Vite can call configureServer multiple times (e.g. on config changes, HMR restarts), which causes listeners to accumulate and triggers Node's MaxListenersExceededWarning.
MaxListenersExceededWarning: Possible EventTarget memory leak detected.
11 change listeners added to [FSWatcher].
at watchDidFileChanges (.../node_modules/@icp-sdk/bindgen/dist/esm/plugins/vite.js:22:18)
at configureServer (.../node_modules/@icp-sdk/bindgen/dist/esm/plugins/vite.js:13:9)
Root cause
In plugins/vite.js, watchDidFileChanges unconditionally calls server.watcher.on("change", ...) without guarding against duplicates or cleaning up on server close:
function watchDidFileChanges(server, options) {
const didFilePath = resolve(options.didFile);
server.watcher.add(didFilePath);
server.watcher.on("change", async (changedPath) => {
if (resolve(changedPath) === resolve(didFilePath)) {
await run(options);
}
});
}
Suggested fix
Listen for the server's close event to remove the listener:
configureServer(server) {
if (!options.disableWatch) {
const didFilePath = resolve(options.didFile);
server.watcher.add(didFilePath);
const onChange = async (changedPath) => {
if (resolve(changedPath) === resolve(didFilePath)) {
await run(options);
}
};
server.watcher.on("change", onChange);
// Cleanup when server closes (before restart creates a new one)
server.httpServer?.on("close", () => {
server.watcher.off("change", onChange);
});
}
}
Note: The proposed fix has not been tested yet and may still be incorrect.
Environment
- @icp-sdk/bindgen: 0.2.1
- Vite 6.x
- Node.js 22.x
Bug
The Vite plugin's
configureServerhook adds a newchangelistener toserver.watcherevery time it's called, but never removes it. Vite can callconfigureServermultiple times (e.g. on config changes, HMR restarts), which causes listeners to accumulate and triggers Node'sMaxListenersExceededWarning.Root cause
In
plugins/vite.js,watchDidFileChangesunconditionally callsserver.watcher.on("change", ...)without guarding against duplicates or cleaning up on server close:Suggested fix
Listen for the server's close event to remove the listener:
Note: The proposed fix has not been tested yet and may still be incorrect.
Environment