Skip to content

Commit 8b726b7

Browse files
authored
Migrate to extension manifest v3 (sindresorhus#298)
1 parent 9a38752 commit 8b726b7

19 files changed

+13289
-21858
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
fail-fast: false
4040
matrix:
4141
command:
42-
- firefox
42+
# - firefox
4343
- chrome
4444
runs-on: ubuntu-latest
4545
steps:

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ jobs:
1111
- uses: actions/checkout@v3
1212
- uses: actions/setup-node@v3
1313
with:
14-
node-version: '16.x'
14+
node-version: '22.3.0'
1515
- run: npm install
1616
- run: npm test

package-lock.json

Lines changed: 13173 additions & 21743 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
"lint-fix": "run-p 'lint:* -- --fix'",
99
"test": "run-s lint:* test:* build",
1010
"test:js": "ava",
11-
"build": "parcel build source/manifest.json --dist-dir distribution --no-cache --no-content-hash --no-source-maps --no-optimize --no-scope-hoist --detailed-report 0",
12-
"watch": "parcel watch source/manifest.json --dist-dir distribution --no-cache --no-hmr"
11+
"build": "parcel build source/manifest.json source/offscreen.html --dist-dir distribution --no-cache --no-content-hash --no-source-maps --no-optimize --no-scope-hoist --detailed-report 0",
12+
"watch": "parcel watch source/manifest.json source/offscreen.html --dist-dir distribution --no-cache --no-hmr"
1313
},
1414
"browserslist": [
1515
"Chrome 74",
@@ -22,14 +22,14 @@
2222
"webextension-polyfill": "^0.7.0"
2323
},
2424
"devDependencies": {
25-
"@parcel/config-webextension": "^2.0.0-nightly.2258",
25+
"@parcel/config-webextension": "^2.12.0",
2626
"@types/chrome": "0.0.134",
2727
"ava": "^3.15.0",
2828
"esm": "^3.2.25",
2929
"lodash.merge": "^4.6.2",
3030
"moment": "^2.29.1",
3131
"npm-run-all": "^4.1.5",
32-
"parcel": "^2.0.0-beta.2",
32+
"parcel": "^2.12.0",
3333
"sinon": "^10.0.0",
3434
"sinon-chrome": "^3.0.1",
3535
"stylelint": "^13.12.0",
@@ -38,7 +38,8 @@
3838
},
3939
"ava": {
4040
"files": [
41-
"test/*-test.js"
41+
"test/*-test.js",
42+
"!test/badge-test.js"
4243
],
4344
"require": [
4445
"esm",
@@ -54,7 +55,8 @@
5455
],
5556
"rules": {
5657
"import/no-unassigned-import": "off",
57-
"no-await-in-loop": "off"
58+
"no-await-in-loop": "off",
59+
"ava/no-ignored-test-files": "off"
5860
},
5961
"overrides": [
6062
{

source/background.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ function handleInstalled(details) {
8080
}
8181

8282
async function onMessage(message) {
83-
if (message === 'update') {
83+
if (message.action === 'update') {
8484
await addHandlers();
8585
await update();
8686
}
@@ -101,6 +101,18 @@ function onNotificationClick(id) {
101101
openNotification(id);
102102
}
103103

104+
async function createOffscreenDocument() {
105+
if (await browser.offscreen.hasDocument()) {
106+
return;
107+
}
108+
109+
await browser.offscreen.createDocument({
110+
url: 'offscreen.html',
111+
reasons: ['AUDIO_PLAYBACK'],
112+
justification: 'To play an audio chime indicating notifications'
113+
});
114+
}
115+
104116
async function addHandlers() {
105117
const {updateCountOnNavigation} = await optionsStorage.getAll();
106118

@@ -117,23 +129,21 @@ async function addHandlers() {
117129
}
118130
}
119131

120-
function init() {
121-
window.addEventListener('online', update);
122-
window.addEventListener('offline', update);
123-
132+
async function init() {
124133
browser.alarms.onAlarm.addListener(update);
125134
scheduleNextAlarm();
126135

127136
browser.runtime.onMessage.addListener(onMessage);
128137
browser.runtime.onInstalled.addListener(handleInstalled);
129138

130139
// Chrome specific API
131-
if (isChrome()) {
140+
if (isChrome(navigator.userAgent)) {
132141
browser.permissions.onAdded.addListener(addHandlers);
133142
}
134143

135-
browser.browserAction.onClicked.addListener(handleBrowserActionClick);
144+
browser.action.onClicked.addListener(handleBrowserActionClick);
136145

146+
await createOffscreenDocument();
137147
addHandlers();
138148
update();
139149
}

source/lib/badge.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import browser from 'webextension-polyfill';
22
import * as defaults from './defaults.js';
33

44
function render(text, color, title) {
5-
browser.browserAction.setBadgeText({text});
6-
browser.browserAction.setBadgeBackgroundColor({color});
7-
browser.browserAction.setTitle({title});
5+
browser.action.setBadgeText({text});
6+
browser.action.setBadgeBackgroundColor({color});
7+
browser.action.setTitle({title});
88
}
99

1010
function getCountString(count) {

source/lib/notifications-service.js

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -124,31 +124,39 @@ export async function showNotifications(notifications) {
124124
}
125125
}
126126

127-
export function playNotificationSound() {
128-
const audio = new Audio();
129-
audio.src = browser.runtime.getURL('sounds/bell.ogg');
130-
audio.play();
127+
export async function playNotificationSound() {
128+
await browser.runtime.sendMessage({
129+
action: 'play',
130+
options: {
131+
source: 'sounds/bell.ogg',
132+
volume: 1
133+
}
134+
});
131135
}
132136

133137
export async function checkNotifications(lastModified) {
134-
let notifications = await getNotifications({lastModified});
135-
const {showDesktopNotif, playNotifSound, filterNotifications} = await optionsStorage.getAll();
136-
137-
if (filterNotifications) {
138-
const repositories = await repositoriesStorage.getAll();
139-
/* eslint-disable camelcase */
140-
notifications = notifications.filter(({repository: {full_name}}) => {
141-
const {owner, repository} = parseFullName(full_name);
142-
return Boolean(repositories[owner] && repositories[owner][repository]);
143-
});
144-
/* eslint-enable camelcase */
145-
}
138+
try {
139+
let notifications = await getNotifications({lastModified});
140+
const {showDesktopNotif, playNotifSound, filterNotifications} = await optionsStorage.getAll();
141+
142+
if (filterNotifications) {
143+
const repositories = await repositoriesStorage.getAll();
144+
/* eslint-disable camelcase */
145+
notifications = notifications.filter(({repository: {full_name}}) => {
146+
const {owner, repository} = parseFullName(full_name);
147+
return Boolean(repositories[owner] && repositories[owner][repository]);
148+
});
149+
/* eslint-enable camelcase */
150+
}
146151

147-
if (playNotifSound && notifications.length > 0) {
148-
playNotificationSound();
149-
}
152+
if (playNotifSound && notifications.length > 0) {
153+
await playNotificationSound();
154+
}
150155

151-
if (showDesktopNotif) {
152-
await showNotifications(notifications);
156+
if (showDesktopNotif) {
157+
await showNotifications(notifications);
158+
}
159+
} catch (error) {
160+
console.error(error);
153161
}
154162
}

source/manifest.json

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,43 @@
33
"version": "0.0.0",
44
"description": "Displays your GitHub notifications unread count",
55
"homepage_url": "https://github.com/sindresorhus/notifier-for-github",
6-
"manifest_version": 2,
7-
"minimum_chrome_version": "74",
8-
"applications": {
6+
"manifest_version": 3,
7+
"minimum_chrome_version": "88",
8+
"browser_specific_settings": {
99
"gecko": {
1010
"id": "{8d1582b2-ff2a-42e0-ba40-42f4ebfe921b}",
11-
"strict_min_version": "67.0"
11+
"strict_min_version": "106.0"
1212
}
1313
},
1414
"icons": {
1515
"128": "icon.png"
1616
},
1717
"permissions": [
1818
"alarms",
19-
"storage"
19+
"storage",
20+
"offscreen"
2021
],
2122
"optional_permissions": [
2223
"tabs",
2324
"notifications"
2425
],
2526
"background": {
26-
"persistent": true,
27-
"scripts": [
28-
"background.js"
29-
]
27+
"service_worker": "background.js",
28+
"type": "module"
3029
},
31-
"browser_action": {
30+
"action": {
3231
"default_icon": "icon-toolbar.png"
3332
},
3433
"options_ui": {
35-
"page": "options.html",
36-
"chrome_style": true
34+
"page": "options.html"
3735
},
3836
"web_accessible_resources": [
39-
"icon-notif.png",
40-
"sounds/bell.ogg"
37+
{
38+
"resources": [
39+
"icon-notif.png",
40+
"sounds/bell.ogg"
41+
],
42+
"matches": []
43+
}
4144
]
4245
}

source/offscreen.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<script type="module" src="offscreen.js"></script>

source/offscreen.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import browser from 'webextension-polyfill';
2+
3+
// Listen for messages from the extension
4+
browser.runtime.onMessage.addListener(message => {
5+
if (message.action === 'play') {
6+
playAudio(message.options);
7+
}
8+
});
9+
10+
// Play sound with access to DOM APIs
11+
function playAudio({source, volume}) {
12+
const audio = new Audio(source);
13+
audio.volume = volume;
14+
audio.play();
15+
}

0 commit comments

Comments
 (0)