Skip to content

Commit 608ce9c

Browse files
feat: move indexedDB to service worker (#696)
* fix: parcel to support bundling background * fix: context menu duplicate error * feat: move indexedDB to service worker * refactor: indexedDB realted featuers to service worker * chore: update package.json build commands * chore: minor function fix in content-script * ci: fix PR review action * fix: logic to init slurs in bg * chore: move runtime to cross browser module * call indexedDB functions directly from popup instead of content-script * add missing fields in indexeddb metadata table * fix: optimize indexedDB functions --------- Co-authored-by: maanasb01 <maanasb01@gmail.com>
1 parent 0741e6b commit 608ce9c

11 files changed

+481
-628
lines changed

.github/workflows/build-extension-manually.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ jobs:
2424
ls
2525
pwd
2626
npm install
27-
npm run build
27+
npm run build:chrome
2828
mv dist/ extension-chrome/
2929
npm run build:firefox
3030
mv dist/ extension-firefox/
3131
3232
- name: "Upload dist folder as artifact"
33-
uses: actions/upload-artifact@v3
33+
uses: actions/upload-artifact@v4
3434
with:
3535
name: extension-artifacts
3636
path: |

.github/workflows/build-pr-review-both-browsers.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
pull_request:
55
branches:
66
- main
7+
- dev
8+
paths:
9+
# Run only if files inside this folder are modified
10+
- "browser-extension/plugin/**"
711

812
permissions:
913
actions: write
@@ -39,13 +43,13 @@ jobs:
3943
ls
4044
pwd
4145
npm install
42-
npm run build
46+
npm run build:chrome
4347
mv dist/ extension-chrome/
4448
npm run build:firefox
4549
mv dist/ extension-firefox/
4650
4751
- name: "Upload dist folder as artifact"
48-
uses: actions/upload-artifact@v3
52+
uses: actions/upload-artifact@v4
4953
with:
5054
name: extension-artifacts
5155
path: |

browser-extension/plugin/package-lock.json

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

browser-extension/plugin/package.json

+22-9
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,33 @@
22
"name": "ogbv-chrome-plugin",
33
"version": "0.0.1",
44
"description": "",
5+
"targets": {
6+
"frontend": {
7+
"context": "browser",
8+
"source": [
9+
"src/options.jsx",
10+
"src/content-script.js"
11+
]
12+
},
13+
"background": {
14+
"context": "service-worker",
15+
"source": "src/background.js"
16+
}
17+
},
518
"scripts": {
619
"prepare": "cd ../.. && husky install \"browser-extension/plugin/.husky\"",
720
"test": "echo \"Error: no test specified\" && exit 1",
821
"test:api": "jest",
9-
"start:options": "parcel src/options.jsx",
10-
"start:contentScript": "parcel src/content-script.js",
11-
"moveBuildArtefactsToDistDir": "cp src/options.html dist && cp manifest.json dist && cp icon* dist && cp src/background.js dist",
12-
"moveBuildArtefactsToFirefoxDistDir": "cp src/options.html dist && cp manifest.firefox.json dist/manifest.json && cp icon* dist && cp src/background.js dist",
13-
"build": "mkdir dist && NODE_ENV=production parcel build src/options.jsx src/content-script.js && npm run moveBuildArtefactsToDistDir",
14-
"build:firefox": "mkdir dist && NODE_ENV=production parcel build src/options.jsx src/content-script.js && npm run moveBuildArtefactsToFirefoxDistDir",
1522
"pre-commit": "npm audit --audit-level=moderate",
1623
"lint": "lint-staged",
17-
"dev:firefox": "mkdir -p dist && concurrently \"npm run start:options\" \"npm run start:contentScript\" \"npm run moveBuildArtefactsToFirefoxDistDir\"",
18-
"dev:chrome": "mkdir -p dist && concurrently \"npm run start:options\" \"npm run start:contentScript\" \"npm run moveBuildArtefactsToDistDir\"",
24+
"start:parcel": "parcel",
25+
"moveBuildArtefactsToDistDir": "cp src/options.html dist && cp manifest.json dist && cp icon* dist",
26+
"moveBuildArtefactsToFirefoxDistDir": "cp src/options.html dist && cp manifest.firefox.json dist/manifest.json && cp icon* dist",
27+
"refactorBuildFiles": "mv dist/background/* dist/ && mv dist/frontend/* dist/ && rmdir dist/background dist/frontend",
28+
"build:chrome": "mkdir dist && NODE_ENV=production parcel build && npm run moveBuildArtefactsToDistDir && npm run refactorBuildFiles",
29+
"build:firefox": "mkdir dist && NODE_ENV=production parcel build && npm run moveBuildArtefactsToFirefoxDistDir && npm run refactorBuildFiles",
30+
"dev:firefox": "mkdir -p dist && concurrently \"npm run start:parcel\" \"npm run moveBuildArtefactsToFirefoxDistDir\"",
31+
"dev:chrome": "mkdir -p dist && concurrently \"npm run start:parcel\" \"npm run moveBuildArtefactsToDistDir\"",
1932
"dev:clean": "rm -rf dist/"
2033
},
2134
"jest": {
@@ -41,7 +54,7 @@
4154
"puppeteer": "21.5.2"
4255
},
4356
"dependencies": {
44-
"axios": "1.6.2",
57+
"axios": "1.7.9",
4558
"concurrently": "8.2.2",
4659
"dexie": "^4.0.11",
4760
"dom-to-image": "2.6.0",

browser-extension/plugin/src/background.js

+171-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,50 @@
1-
// import { userBrowserTabs, userBrowserContextMenus } from './browser-compat';
1+
import Dexie from 'dexie';
2+
import {
3+
initializeSlurs,
4+
getAllSlurs,
5+
convertSlurMetadataFromDBtoJSON,
6+
getSlursBySource,
7+
addSlur,
8+
deleteSlur,
9+
slurExists,
10+
bulkAddSlurs,
11+
fetchPublicSlursMetadata,
12+
bulkDeleteSlurs,
13+
initializeMetadata
14+
} from './slur-store';
15+
import { getPublicSlurs } from './api/public-slurs';
216
console.log('bg script 8');
317

18+
let db;
19+
let isSlurInitialized = false;
20+
// init db schema
21+
function initializeDB() {
22+
if (!db) {
23+
db = new Dexie('SlurWordsDatabase');
24+
db.version(1).stores({
25+
words: '++id, slur_id, word, source, enable_status, batch',
26+
words_metadata:
27+
'++id, slur_id, label, level_of_severity, casual, appropriated, appropriation_context, meaning, language, batch, categories, timestamp'
28+
});
29+
console.log('Database Initialized');
30+
}
31+
return db;
32+
}
33+
34+
(async () => {
35+
try {
36+
const db = initializeDB();
37+
38+
if (!isSlurInitialized) {
39+
await initializeSlurs(db);
40+
await initializeMetadata(db)
41+
isSlurInitialized = true;
42+
}
43+
} catch (error) {
44+
console.error('Error initializing extension:', error);
45+
}
46+
})();
47+
448
const BROWSER_CHROME = 'chrome';
549
const BROWSER_FIREFOX = 'firefox';
650
const BROWSER_UNSUPPORTED = 'unsupported';
@@ -39,16 +83,18 @@ userBrowserTabs.onUpdated.addListener(function (tabId, changeInfo) {
3983
}
4084
});
4185

42-
userBrowserContextMenus.create(
43-
{
44-
id: 'add-slur',
45-
title: 'Add Slur to Uli',
46-
contexts: ['selection']
47-
},
48-
() => {
49-
console.log('context menu created');
50-
}
51-
);
86+
userBrowserContextMenus.removeAll(() => {
87+
userBrowserContextMenus.create(
88+
{
89+
id: 'add-slur',
90+
title: 'Add Slur to Uli',
91+
contexts: ['selection']
92+
},
93+
() => {
94+
console.log('context menu created');
95+
}
96+
);
97+
});
5298

5399
userBrowserContextMenus.onClicked.addListener((info, tab) => {
54100
switch (info.menuItemId) {
@@ -66,3 +112,117 @@ userBrowserContextMenus.onClicked.addListener((info, tab) => {
66112
console('unexpected action');
67113
}
68114
});
115+
116+
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
117+
switch (request.type) {
118+
case 'initializeSlurs':
119+
handleInitSlurs(request, sendResponse, db);
120+
return true;
121+
case 'updateDataMsgToBG':
122+
handleUpdateData(request, sendResponse, db);
123+
return true;
124+
case 'fetchPersonalSlursToBG':
125+
handleFetchPersonalSlurs(request, sendResponse, db);
126+
return true;
127+
case 'syncApprovedCrowdsourcedSlursToBG':
128+
handleSyncApprovedSlurs(request, sendResponse, db);
129+
return true;
130+
default:
131+
return false;
132+
}
133+
});
134+
135+
async function handleInitSlurs(request, sendResponse, db) {
136+
try {
137+
allSlurWords = await getAllSlurs(db);
138+
allMetadata = await convertSlurMetadataFromDBtoJSON(db);
139+
sendResponse({
140+
status: 200,
141+
allSlurWords: allSlurWords,
142+
allMetadata: allMetadata
143+
});
144+
} catch (error) {
145+
console.error('Error initializing slurs in service worker:', error);
146+
sendResponse({ status: 400, message: error.message });
147+
}
148+
}
149+
150+
async function handleUpdateData(request, sendResponse, db) {
151+
try {
152+
const newSlurs = request.data;
153+
console.log('New slurs received:', newSlurs);
154+
155+
// Fetch existing slurs
156+
const existingSlurs = (await getSlursBySource(db, 'personal')).map(
157+
(slur) => slur.word
158+
);
159+
// Add new slurs to the database
160+
for (const slur of newSlurs) {
161+
if (!existingSlurs.includes(slur)) {
162+
await addSlur(db, slur, 'personal');
163+
}
164+
}
165+
// Remove slurs from the database that no longer exist in the new list
166+
for (const slur of existingSlurs) {
167+
if (!newSlurs.includes(slur)) {
168+
await deleteSlur(db, slur, 'personal');
169+
}
170+
}
171+
sendResponse({ status: 200 });
172+
} catch (error) {
173+
console.error('Error during updating slur list:', error);
174+
sendResponse({ status: 400, message: error.message });
175+
}
176+
}
177+
178+
async function handleFetchPersonalSlurs(request, sendResponse, db) {
179+
try {
180+
console.log('Fetching personal slurs');
181+
const personalSlurs = await getSlursBySource(db, 'personal');
182+
const slurArr = personalSlurs.map((slur) => slur.word);
183+
console.log('Sending personal slurs:', slurArr);
184+
sendResponse(slurArr);
185+
} catch (error) {
186+
console.error('Error fetching personal slurs:', error);
187+
sendResponse({ status: 400, message: error.message });
188+
}
189+
}
190+
191+
async function handleSyncApprovedSlurs(request, sendResponse, db) {
192+
const source = 'public_crowdsourced_slurs';
193+
try {
194+
const publicSlurs = await getPublicSlurs();
195+
const publicSlursArray = publicSlurs.map((slur) => slur.label);
196+
// console.log('Public slurs fetched:', publicSlursArray);
197+
198+
const existingSlurs = await getSlursBySource(db, source)
199+
200+
const publicSlurSet = new Set(publicSlurs.map(s=>s.id))
201+
const existingSlurSet = new Set(existingSlurs.map(s=>s.slur_id))
202+
203+
const newSlurs = publicSlurs.filter(s =>
204+
!existingSlurSet.has(s.id)
205+
);
206+
// Identify metadata that needs to be removed (exists in DB but not in fetched data)
207+
const outdatedSlurs = existingSlurs.filter(s =>
208+
!publicSlurSet.has(s.slur_id)
209+
);
210+
211+
if (newSlurs.length > 0) {
212+
await bulkAddSlurs(db, newSlurs, source);
213+
} else {
214+
console.log('No new slurs to add.');
215+
}
216+
217+
if(outdatedSlurs.length > 0){
218+
await bulkDeleteSlurs(db, outdatedSlurs);
219+
}
220+
221+
// Fetch public metadata again
222+
await fetchPublicSlursMetadata(db);
223+
sendResponse({ status: 200 });
224+
} catch (error) {
225+
console.error('Error syncing approved slurs:', error);
226+
sendResponse({ status: 400, message: error.message });
227+
}
228+
}

browser-extension/plugin/src/browser-compat.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,18 @@ if (userAgent.includes('chrome')) {
2424
let userBrowserTabs;
2525
let userBrowserContextMenus;
2626
let userBrowserStorage;
27+
let userBrowserRuntime;
2728

2829
if (userBrowser === BROWSER_FIREFOX) {
2930
userBrowserTabs = browser.tabs;
3031
userBrowserContextMenus = browser.contextMenus;
3132
userBrowserStorage = browser.storage;
33+
userBrowserRuntime = browser.runtime;
3234
} else if (userBrowser === BROWSER_CHROME) {
3335
userBrowserTabs = chrome.tabs;
3436
userBrowserContextMenus = chrome.contextMenus;
3537
userBrowserStorage = chrome.storage;
38+
userBrowserRuntime = chrome.runtime;
3639
} else {
3740
// TODO: Indicate to user that browser is unsupported
3841
}
@@ -44,5 +47,6 @@ export {
4447
userBrowser,
4548
userBrowserTabs,
4649
userBrowserContextMenus,
47-
userBrowserStorage
50+
userBrowserStorage,
51+
userBrowserRuntime
4852
};

0 commit comments

Comments
 (0)