🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 4 Min Lesezeit
0

5 Manifest V3 Gotchas That Cost Me Way More Time Than They Should Have

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

I've lost more hours to Chrome extension development than I'd like to admit. Not because extensions are hard, exactly — it's that Manifest V3 changes a bunch of assumptions that feel completely reasonable until they quietly break your extension in production, usually a week after you shipped it and stopped thinking about it.



Here are the five that got me the worst, and how I'd fix them if I were starting over.






1. Your service worker is not a background page



Coming from Manifest V2, it's tempting to treat your service worker like the old persistent background page — just a script that runs and keeps its state in memory. It isn't. Chrome kills idle service workers aggressively (sometimes in under a minute), and when a new event comes in, it spins up a fresh instance. Any global variable you were relying on is gone.




CODE
// ❌ This "works" in dev and then silently breaks in production
let userSettings = null;

chrome.runtime.onInstalled.addListener(() => {
userSettings = { theme: "dark" }; // gone the moment the SW sleeps
});






The fix is boring but non-negotiable: anything that needs to survive between events goes into chrome.storage, not a variable.




CODE
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.local.set({ userSettings: { theme: "dark" } });
});









2. Listeners registered "later" just... don't fire



This one is sneakier. If you register an event listener inside a promise, a callback, or after an await, it may never fire — because by the time that code runs, Chrome has already decided nothing is listening and moved on.




CODE
// ❌ Registered too late — event may already have fired and been missed
chrome.storage.local.get(["enabled"], ({ enabled }) => {
chrome.action.onClicked.addListener(handleClick);
});






Listeners need to be registered synchronously, at the top level of your script, every time it runs:




CODE
// ✅
chrome.action.onClicked.addListener(handleClick);

async function handleClick(tab) {
const { enabled } = await chrome.storage.local.get(["enabled"]);
// ...
}









3. CSP will quietly reject your inline scripts



If you're copy-pasting popup HTML from an old tutorial or an old extension of your own, there's a decent chance it has an inline <script> tag or an onclick="..." attribute somewhere. Manifest V3's content security policy doesn't allow either — no inline scripts, no eval, no string-based setTimeout.




CODE
<!-- ❌ Silently fails, no script runs, no obvious error in the UI -->
<button onclick="doThing()">Click me</button>






Move everything into an external file and attach listeners in JS instead. It's more files, but it's also just... better practice anyway.






4. Forgetting return true breaks async message passing



Message passing between your popup, content script, and service worker is one of those things that works fine in your first test and then mysteriously stops responding a few days later. The usual culprit: you're responding asynchronously but didn't tell Chrome to keep the channel open.




CODE
// ❌ sendResponse never actually reaches the caller
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
chrome.storage.local.get(["count"], (data) => {
sendResponse(data); // too late, channel already closed
});
});









CODE
// ✅ the `return true` is the whole fix
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
chrome.storage.local.get(["count"], (data) => {
sendResponse(data);
});
return true; // keeps the message channel open for async response
});









5. Broad permissions get your extension flagged (and users don't trust it either)



"host_permissions": ["<all_urls>"] is the fastest way to get extra scrutiny in Chrome Web Store review, and it's also the fastest way to make a user uninstall your extension before trying it. Most of the time you don't actually need standing access to every site — you need access when the user clicks your icon.




CODE
//  "why does this extension want access to everything?"
"host_permissions": ["<all_urls>"]









CODE
//  only activates in the current tab, on demand
"permissions": ["activeTab", "storage"]






If you genuinely need broader access, optional_permissions lets you request it contextually instead of up front, which reviewers (and users) tend to appreciate a lot more.






None of these are individually hard once you know about them — the problem is that MV3's docs are scattered across a dozen pages, and most tutorials still show MV2 patterns without saying so. After hitting variations of all five of these across a handful of extensions, I got tired of re-solving the same problems every time I started a new one, so I built ManifestGo — you describe the extension you want, and it generates the full project already handling service worker lifecycle, CSP-compliant scripts, and minimal-permission scoping correctly from the start. Still actively building on it, but it's saved me from re-learning these gotchas the hard way for the third time.



If you've hit other MV3 landmines I didn't cover here, I'd genuinely like to hear about them in the comments — collecting the ones that don't show up in the official docs.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten 5 Manifest V3 Gotchas That Cost Me Way More Time Than They Should Have

Thematisch verwandte Begriffe: Manifest, Gotchas, That, Cost · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...