DEV Community

ke jia
ke jia

Posted on

Manifest V3 Gotchas: The 3 Bugs My Extension Template Already Fixed

Building a Chrome extension in 2026 means building against Manifest V3, and MV3 has three traps that catch every first-time extension developer. I built the Chrome Extension template in scaffoldx-cli specifically so those traps are already stepped over before you write a line of code.

Here are the three bugs, and how the template avoids each one.

Bug 1: the service worker doesn't keep state

The biggest mental-model shift in MV3: the background page is gone, replaced by a service worker that Chrome terminates whenever it's idle. Your "background script" can't hold a long-lived object, a timer, or a connection.

The classic bug:

// background.js — looks fine, breaks in production
let pendingSyncs = [];
chrome.runtime.onMessage.addListener((msg) => {
  pendingSyncs.push(msg);   // ← this array is GONE when the worker restarts
  scheduleSync();
});
Enter fullscreen mode Exit fullscreen mode

The worker gets terminated after 30 seconds of idle. pendingSyncs vanishes. The user's action "did nothing" and there's no error to log, because nothing threw — the state just evaporated.

The template's fix: the generated extension stores anything that must survive in chrome.storage.session (or local) and treats the worker as stateless. The pattern is written into the starter code with a comment explaining why, because the next developer will be tempted to "simplify" it back into a global variable.

Bug 2: the host permissions you forgot

MV3 is stricter about host permissions: an extension can only reach the origins it declares in host_permissions, and undeclared origins get silent network failures. The classic bug is a fetch that works in the popup (where the page context has access) and fails in the service worker (where only declared permissions apply).

// Works in popup, 403 in service worker
const res = await fetch('https://api.example.com/data');
// "Cross-origin request blocked" — the worker has no host permission for that origin
Enter fullscreen mode Exit fullscreen mode

The template's fix: the generated manifest.json ships with a host_permissions array that's explicitly commented, and the README section tells you to add every origin you'll fetch from. The failure mode is made visible at design time instead of at runtime, in production, on a user's machine where you can't easily debug it.

Bug 3: the remote code ban

MV3 forbids remote code: no eval, no new Function, no loading scripts from a CDN. A huge number of "quick" extension tutorials violate this and pass review only to get rejected on store submission, or worse, ship a version that Chrome disables the moment a security update lands.

The subtle version of the bug: bundling a library that itself uses dynamic code generation, or a build step that inlines a remote script. The extension loads fine locally and dies in the store.

The template's fix: the starter has no dynamic code paths, and the build (if you add one) is configured to bundle everything locally. The constraint is enforced by the template's structure, not by a rule you have to remember during store review.

Why the template exists at all

These three bugs are all known — they're in Chrome's documentation, in a dozen blog posts, in the extension team's FAQ. The problem isn't knowledge; it's that every new extension project starts from zero, and every new project re-discovers the same three traps, in the same order, with the same debugging cost.

A template that ships with the traps already stepped over converts "learn MV3 by breaking things" into "build the feature on a base that already works." The scaffoldx extension template is small — manifest, popup, content script, service worker, with the three patterns above wired in — and it's the template I reach for whenever someone on the team says "I want to try an extension idea."

npx scaffoldx-cli
# choose: Chrome Extension
Enter fullscreen mode Exit fullscreen mode

The three bugs above are the reason the template exists. Everything else in it is just the boring scaffolding that makes the three interesting parts easy to extend.

npx scaffoldx-cli
Enter fullscreen mode Exit fullscreen mode

More Tools

Tool What it does Command
scaffoldx-cli Production-ready project templates in seconds npx scaffoldx-cli
dotguard Scan .env files for exposed secrets npx @wuchunjie/dotguard
gitpulse Git repo analytics in your terminal npx @wuchunjie/gitpulse
snippetx Terminal code snippet manager npx @wuchunjie/snippetx

If these save you time, consider buying me a coffee. All tools are MIT-licensed, zero-dependency, and run fully offline.

Top comments (0)