using my boilerplate yuh
This commit is contained in:
50
src/background/background.ts
Normal file
50
src/background/background.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { MessageListener } from 'chrome-extension-toolkit';
|
||||
import { BACKGROUND_MESSAGES } from 'src/shared/messages';
|
||||
import { generateRandomId } from 'src/shared/util/random';
|
||||
import onHistoryStateUpdated from './events/onHistoryStateUpdated';
|
||||
import onInstall from './events/onInstall';
|
||||
import onNewChromeSession from './events/onNewChromeSession';
|
||||
import onServiceWorkerAlive from './events/onServiceWorkerAlive';
|
||||
import onUpdate from './events/onUpdate';
|
||||
import { sessionStore } from '../shared/storage/sessionStore';
|
||||
import browserActionHandler from './handler/browserActionHandler';
|
||||
import hotReloadingHandler from './handler/hotReloadingHandler';
|
||||
import tabManagementHandler from './handler/tabManagementHandler';
|
||||
|
||||
onServiceWorkerAlive();
|
||||
|
||||
/**
|
||||
* will be triggered on either install or update
|
||||
* (will also be triggered on a user's sync'd browsers (on other devices)))
|
||||
*/
|
||||
chrome.runtime.onInstalled.addListener(details => {
|
||||
switch (details.reason) {
|
||||
case 'install':
|
||||
onInstall();
|
||||
break;
|
||||
case 'update':
|
||||
onUpdate();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// This event is fired when any tab's url changes.
|
||||
chrome.webNavigation.onHistoryStateUpdated.addListener(onHistoryStateUpdated);
|
||||
|
||||
// initialize the message listener that will listen for messages from the content script
|
||||
const messageListener = new MessageListener<BACKGROUND_MESSAGES>({
|
||||
...browserActionHandler,
|
||||
...hotReloadingHandler,
|
||||
...tabManagementHandler,
|
||||
});
|
||||
|
||||
messageListener.listen();
|
||||
|
||||
sessionStore.getChromeSessionId().then(async chromeSessionId => {
|
||||
if (!chromeSessionId) {
|
||||
await sessionStore.setChromeSessionId(generateRandomId(10));
|
||||
onNewChromeSession();
|
||||
}
|
||||
});
|
||||
11
src/background/events/onHistoryStateUpdated.ts
Normal file
11
src/background/events/onHistoryStateUpdated.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* This event is fired when any tab's url changes.
|
||||
* This is useful for content scripts to know when SPA navigations occur.
|
||||
* @param details
|
||||
*/
|
||||
export default function onHistoryStateUpdated(
|
||||
details: chrome.webNavigation.WebNavigationTransitionCallbackDetails
|
||||
): void {
|
||||
const { tabId, url } = details;
|
||||
// TODO: send a message to tab with tabId to reanalyze the page
|
||||
}
|
||||
26
src/background/events/onInstall.ts
Normal file
26
src/background/events/onInstall.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { SECOND } from 'src/shared/util/time';
|
||||
|
||||
/**
|
||||
* Called when the extension is first installed or synced onto a new machine
|
||||
*/
|
||||
export default async function onInstall() {
|
||||
// set the uninstall url
|
||||
chrome.runtime.setUninstallURL('https://www.google.com');
|
||||
logOnInstallEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* making sure we are not sending duplicate install event for users that have synced browsers
|
||||
* sync storage get's cleared on browser uninstall, so re-installing the browser will trigger the event
|
||||
*/
|
||||
function logOnInstallEvent() {
|
||||
setTimeout(async () => {
|
||||
const manifest = chrome.runtime.getManifest();
|
||||
const INSTALL_KEY = `${manifest.short_name}-installed`;
|
||||
const storage = await chrome.storage.sync.get(INSTALL_KEY);
|
||||
if (!storage[INSTALL_KEY]) {
|
||||
// TODO: send install event
|
||||
await chrome.storage.sync.set({ [INSTALL_KEY]: true });
|
||||
}
|
||||
}, 5 * SECOND);
|
||||
}
|
||||
4
src/background/events/onNewChromeSession.ts
Normal file
4
src/background/events/onNewChromeSession.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* This function is called when the user's browser opens for the first time
|
||||
*/
|
||||
export default function onNewChromeSession() {}
|
||||
9
src/background/events/onServiceWorkerAlive.ts
Normal file
9
src/background/events/onServiceWorkerAlive.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { openDebugTab } from '../util/openDebugTab';
|
||||
|
||||
/**
|
||||
* Called whenever the background service worker comes alive
|
||||
* (usually around 30 seconds to 5 minutes after it was last alive)
|
||||
*/
|
||||
export default function onServiceWorkerAlive() {
|
||||
openDebugTab();
|
||||
}
|
||||
10
src/background/events/onUpdate.ts
Normal file
10
src/background/events/onUpdate.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { hotReloadTab } from 'src/background/util/hotReloadTab';
|
||||
|
||||
/**
|
||||
* Called when the extension is updated (or when the extension is reloaded in development mode)
|
||||
*/
|
||||
export default function onUpdate() {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
hotReloadTab();
|
||||
}
|
||||
}
|
||||
20
src/background/handler/browserActionHandler.ts
Normal file
20
src/background/handler/browserActionHandler.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { MessageHandler } from 'chrome-extension-toolkit';
|
||||
import BrowserActionMessages from 'src/shared/messages/BrowserActionMessages';
|
||||
|
||||
const browserActionHandler: MessageHandler<BrowserActionMessages> = {
|
||||
disableBrowserAction({ sender, sendResponse }) {
|
||||
// by setting the popup to an empty string, clicking the browser action will not open the popup.html.
|
||||
// we can then add an onClickListener to it from the content script
|
||||
chrome.action.setPopup({ tabId: sender.tab?.id, popup: '' }).then(sendResponse);
|
||||
},
|
||||
enableBrowserAction({ sender, sendResponse }) {
|
||||
chrome.action
|
||||
.setPopup({
|
||||
tabId: sender.tab?.id,
|
||||
popup: 'popup.html',
|
||||
})
|
||||
.then(sendResponse);
|
||||
},
|
||||
};
|
||||
|
||||
export default browserActionHandler;
|
||||
21
src/background/handler/hotReloadingHandler.ts
Normal file
21
src/background/handler/hotReloadingHandler.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import HotReloadingMessages from 'src/shared/messages/HotReloadingMessages';
|
||||
import { MessageHandler } from 'chrome-extension-toolkit';
|
||||
import { devStore } from 'src/shared/storage/devStore';
|
||||
|
||||
const hotReloadingHandler: MessageHandler<HotReloadingMessages> = {
|
||||
async reloadExtension({ sendResponse }) {
|
||||
const isExtensionReloading = await devStore.getIsExtensionReloading();
|
||||
if (!isExtensionReloading) return sendResponse();
|
||||
|
||||
const isTabReloading = await devStore.getIsExtensionReloading();
|
||||
if (isTabReloading) {
|
||||
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
const tabToReload = tabs[0];
|
||||
|
||||
await devStore.setReloadTabId(tabToReload?.id);
|
||||
}
|
||||
chrome.runtime.reload();
|
||||
},
|
||||
};
|
||||
|
||||
export default hotReloadingHandler;
|
||||
18
src/background/handler/tabManagementHandler.ts
Normal file
18
src/background/handler/tabManagementHandler.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { MessageHandler } from 'chrome-extension-toolkit';
|
||||
import TabManagementMessages from 'src/shared/messages/TabManagementMessages';
|
||||
|
||||
const tabManagementHandler: MessageHandler<TabManagementMessages> = {
|
||||
getTabId({ sendResponse, sender }) {
|
||||
sendResponse(sender.tab?.id ?? -1);
|
||||
},
|
||||
openNewTab({ data, sendResponse }) {
|
||||
const { url } = data;
|
||||
chrome.tabs.create({ url }).then(sendResponse);
|
||||
},
|
||||
removeTab({ data, sendResponse }) {
|
||||
const { tabId } = data;
|
||||
chrome.tabs.remove(tabId).then(sendResponse);
|
||||
},
|
||||
};
|
||||
|
||||
export default tabManagementHandler;
|
||||
39
src/background/util/hotReloadTab.ts
Normal file
39
src/background/util/hotReloadTab.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { devStore } from 'src/shared/storage/devStore';
|
||||
|
||||
/**
|
||||
* A list of websites that we don't want to reload when the extension reloads (becuase it'd be hella annoying lmao)
|
||||
*/
|
||||
const HOT_RELOADING_WHITELIST = [
|
||||
'youtube.com',
|
||||
'twitch.tv',
|
||||
'github.dev',
|
||||
'figma.com',
|
||||
'netflix.com',
|
||||
'disneyplus.com',
|
||||
'hbomax.com',
|
||||
'spotify.com',
|
||||
'localhost:6006',
|
||||
'docs.google.com',
|
||||
'reddit.com',
|
||||
'gmail.com',
|
||||
'photopea.com',
|
||||
];
|
||||
|
||||
/**
|
||||
* Reloads the tab that was open when the extension was reloaded
|
||||
* @returns a promise that resolves when the tab is reloaded
|
||||
*/
|
||||
export async function hotReloadTab(): Promise<void> {
|
||||
const { getIsTabReloading, getReloadTabId } = devStore;
|
||||
|
||||
const [isTabReloading, reloadTabId] = await Promise.all([getIsTabReloading(), getReloadTabId()]);
|
||||
|
||||
if (!isTabReloading || !reloadTabId) return;
|
||||
|
||||
chrome.tabs.get(reloadTabId, tab => {
|
||||
if (!tab?.id) return;
|
||||
if (!HOT_RELOADING_WHITELIST.find(url => tab.url?.includes(url))) {
|
||||
chrome.tabs.reload(tab.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
24
src/background/util/openDebugTab.ts
Normal file
24
src/background/util/openDebugTab.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { devStore } from 'src/shared/storage/devStore';
|
||||
|
||||
/**
|
||||
* Open the debug tab as the first tab
|
||||
*/
|
||||
export async function openDebugTab() {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const debugTabId = await devStore.getDebugTabId();
|
||||
|
||||
const isAlreadyOpen = await (await chrome.tabs.query({})).some(tab => tab.id === debugTabId);
|
||||
if (isAlreadyOpen) return;
|
||||
|
||||
const wasVisible = await devStore.getWasDebugTabVisible();
|
||||
|
||||
const tab = await chrome.tabs.create({
|
||||
url: chrome.runtime.getURL('debug.html'),
|
||||
active: wasVisible,
|
||||
pinned: true,
|
||||
index: 0,
|
||||
});
|
||||
|
||||
await devStore.setDebugTabId(tab.id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user