perf: add Memory Saver with tab suspension and exclusion list#165
perf: add Memory Saver with tab suspension and exclusion list#165Ayush-Vish wants to merge 20 commits intop2plabsxyz:mainfrom
Conversation
peersky://settings/performance to free up the inactive tabsThere was a problem hiding this comment.
Pull request overview
Implements a new “Memory Saver” performance feature in PeerSky settings and tab UI to suspend inactive tabs and visually indicate sleeping tabs, with an exclusions list to keep selected sites active.
Changes:
- Added new settings keys (
memorySaverEnabled,memorySaverExclusions) and broadcast updates to renderer windows. - Implemented tab suspension/wake-up logic in the tab bar, including navigation-history capture/restore and hover-card memory usage updates.
- Added a new “Performance” section in Settings UI with toggle + exclusions management, plus sleeping-tab styling.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/settings-manager.js | Adds defaults/validation and emits memory-saver-changed on updates. |
| src/pages/tab-bar.js | Implements suspend/wake logic, idle checking, exclusions matching, and hover-card async memory lookup. |
| src/pages/settings.html | Adds Performance section UI and navigation entry. |
| src/pages/static/js/settings.js | Wires up Memory Saver toggle + exclusions list UI behavior. |
| src/pages/theme/index.css | Adds sleeping-tab visual treatment (favicon ring/title dimming) and hides the old emoji indicator. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| // Save history | ||
| try { | ||
| const { ipcRenderer } = require("electron"); | ||
| const webContentsId = webview.getWebContentsId(); | ||
| tab.savedNavigation = ipcRenderer.sendSync('get-tab-navigation', webContentsId); | ||
| } catch (e) { | ||
| console.warn("Failed to save nav history for sleeping tab", e); | ||
| } | ||
|
|
||
| // Destroy webview | ||
| webview.remove(); | ||
| this.webviews.delete(tabId); | ||
|
|
||
| // Unregister extension cleanly | ||
| try { | ||
| const { ipcRenderer } = require("electron"); | ||
| ipcRenderer.invoke('extensions-unregister-webview', webview.getWebContentsId()).catch(() => {}); | ||
| } catch (e) {} |
There was a problem hiding this comment.
suspendTab() removes the webview from the DOM before invoking extensions-unregister-webview using webview.getWebContentsId(). Depending on Electron/webview lifecycle timing, this can throw or return an invalid ID, leaving the extension system registered for a destroyed view. Capture webContentsId once before removing the webview and reuse it for both navigation save + unregister.
| // Save history | |
| try { | |
| const { ipcRenderer } = require("electron"); | |
| const webContentsId = webview.getWebContentsId(); | |
| tab.savedNavigation = ipcRenderer.sendSync('get-tab-navigation', webContentsId); | |
| } catch (e) { | |
| console.warn("Failed to save nav history for sleeping tab", e); | |
| } | |
| // Destroy webview | |
| webview.remove(); | |
| this.webviews.delete(tabId); | |
| // Unregister extension cleanly | |
| try { | |
| const { ipcRenderer } = require("electron"); | |
| ipcRenderer.invoke('extensions-unregister-webview', webview.getWebContentsId()).catch(() => {}); | |
| } catch (e) {} | |
| // Capture webContentsId once while the webview is still alive | |
| let webContentsId = null; | |
| try { | |
| webContentsId = webview.getWebContentsId(); | |
| } catch (e) { | |
| console.warn("Failed to get webContentsId for sleeping tab", e); | |
| } | |
| // Save history | |
| if (webContentsId != null) { | |
| try { | |
| const { ipcRenderer } = require("electron"); | |
| tab.savedNavigation = ipcRenderer.sendSync('get-tab-navigation', webContentsId); | |
| } catch (e) { | |
| console.warn("Failed to save nav history for sleeping tab", e); | |
| } | |
| } | |
| // Destroy webview | |
| webview.remove(); | |
| this.webviews.delete(tabId); | |
| // Unregister extension cleanly | |
| if (webContentsId != null) { | |
| try { | |
| const { ipcRenderer } = require("electron"); | |
| ipcRenderer | |
| .invoke('extensions-unregister-webview', webContentsId) | |
| .catch(err => { | |
| console.warn("Failed to unregister webview extensions for sleeping tab", err); | |
| }); | |
| } catch (e) { | |
| console.warn("Error while requesting webview extension unregister for sleeping tab", e); | |
| } | |
| } |
There was a problem hiding this comment.
Is this comment addressed?
…related UI elements
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
akhileshthite
left a comment
There was a problem hiding this comment.
Good start!
I have comments related benchmark details, navigation concerns, and UI suggestions.
|
I just realized that we don't have @Ayush-Vish It would be good to include memory saver there. |
akhileshthite
left a comment
There was a problem hiding this comment.
Mostly related to Doc, UI, and a missing unaddressed comment.
| --- | ||
|
|
||
| ## 6. Memory Saver | ||
|
|
There was a problem hiding this comment.
Display SS, save as ./docs/images/peersky-memory-saver.png. Keep width width="800".
There was a problem hiding this comment.
We need visuals of 10 cropped open tabs. Before and After benchmark graph. As I mentioned in the linked comment, we can also compare Chrome's memory saver performance with ours in a graph.
(#165)
|
|
||
| // Save history | ||
| try { | ||
| const { ipcRenderer } = require("electron"); | ||
| const webContentsId = webview.getWebContentsId(); | ||
| tab.savedNavigation = ipcRenderer.sendSync('get-tab-navigation', webContentsId); | ||
| } catch (e) { | ||
| console.warn("Failed to save nav history for sleeping tab", e); | ||
| } | ||
|
|
||
| // Destroy webview | ||
| webview.remove(); | ||
| this.webviews.delete(tabId); | ||
|
|
||
| // Unregister extension cleanly | ||
| try { | ||
| const { ipcRenderer } = require("electron"); | ||
| ipcRenderer.invoke('extensions-unregister-webview', webview.getWebContentsId()).catch(() => {}); | ||
| } catch (e) {} |
There was a problem hiding this comment.
Is this comment addressed?
akhileshthite
left a comment
There was a problem hiding this comment.
Amazing!
We're almost there :D
…improve UI visibility
Related Issue (if any)
Closes: #164

Describe the add-ons or changes you've made
Type of change
How Has This Been Tested?
Checklist:
Screenshots (Only for Front End and UI/UX Designers)