Spis treści
1. Co się zepsuło
To nie był dramatyczny rewrite. To była zmiana bundlingu. Zmieniło się nazewnictwo chunków, zmienił się graf chunków, a kod, który wcześniej nie trafiał do tła, został zaimportowany przez service workera.
Ten kod dotykał document. Na stronie, w popupie albo w content scripcie to normalne. W MV3 service workerze nie. Dokumentacja Chrome o service workerach rozszerzeń dobrze ustawia model mentalny: background context to event-driven worker code, a nie strona z DOM. Zacznij od przewodnika Chrome po extension service workers, jeśli ta granica nie jest jeszcze oczywista.
Linia, która psuje workera
const title = document.titleObjaw końcowy był nudny i groźny: paczka rozszerzenia była akceptowalna, ale service worker nie startował poprawnie w produkcji. W Chrome extension page worker był widoczny jako nieaktywny.
2. Dlaczego build i lint tego nie złapały
Bundler może udowodnić, że JavaScript jest składniowo poprawny. Nie udowodni, że każdy zaimportowany moduł jest bezpieczny w każdym kontekście rozszerzenia. Linter może złapać oczywiste użycie globala, jeśli masz osobne środowiska dla service workerów, content scriptów, extension pages i kodu aplikacji. Większość projektów rozszerzeń nie idzie tak daleko.
Kluczowe rozróżnienie: paczka była build-valid, ale runtime-invalid. Manifest istniał. Plik service workera istniał. Zip dało się wysłać. Brakowało tylko przeglądarki wykonującej ten sam krok, który zrobi po dostarczeniu paczki przez Chrome Web Store.
Dodatkowa ochrona statyczna: zablokuj DOM globale w plikach workera
Browser-level smoke test nadal jest ostatnią siatką bezpieczeństwa, ale linting może złapać oczywistą pomyłkę wcześniej. Jeśli Twoja konfiguracja TypeScript już udostępnia chrome przez @types/chrome, zostaw Chrome API dostępne i jawnie zbanuj DOM-only globale w entrypointach service workera przez regułę ESLint no-restricted-globals albo kompatybilną regułę Oxlint.
export default [
{
files: ["src/background/**/*.{js,ts}", "src/**/*service-worker*.{js,ts}"],
rules: {
"no-restricted-globals": [
"error",
{ name: "document", message: "MV3 service workers do not have a DOM." },
{ name: "window", message: "Use self/globalThis in workers, not window." },
{ name: "localStorage", message: "Use chrome.storage in extension workers." },
],
},
},
]Zasada, której używamy teraz
Nie testuj tylko źródeł. Testuj finalny artefakt, który trafia do Chrome Web Store.
3. Smoke test, który powinien istnieć
Ten smoke test jest celowo mały. Nie loguje się do produktu. Nie potrzebuje sandboxa. Nie potrzebuje ciastek. Odpowiada tylko na jedno pytanie: czy Chromium potrafi załadować finalny build rozszerzenia i wykonać MV3 service workera?
Dokumentacja Chrome pokazuje ten sam browser-level kierunek w Puppeteer: załaduj unpacked extension i czekaj na target service_worker. W samplu używamy Playwrighta, ale granica jest ta sama. Zobacz przewodnik Chrome po testowaniu rozszerzeń.
Minimalny kształt testu Playwright
const context = await chromium.launchPersistentContext(userDataDir, {
headless: false,
args: [
'--disable-extensions-except=' + extensionDir,
'--load-extension=' + extensionDir,
],
})
const serviceWorker = await context.waitForEvent('serviceworker', {
predicate: (worker) => worker.url().startsWith('chrome-extension://'),
})
const response = await extensionPage.evaluate(() => {
return chrome.runtime.sendMessage({ type: 'service-worker-smoke' })
})
expect(response.ok).toBe(true)Pełny działający przykład opublikowaliśmy jako Toumash/mv3-service-worker-smoke. Najważniejszy fragment to spec Playwright, który otwiera stronę rozszerzenia i wysyła ping do workera.
4. Minimalny workflow GitHub Actions
Trzymaj ten test osobno od pełnego E2E. Wartość polega na tym, że jest wystarczająco tani, żeby odpalać go na pull requestach dotykających kodu rozszerzenia, bundlingu, konfiguracji Vite, konfiguracji CRXJS albo pakowania releasu.
name: Service Worker Smoke Test
on:
pull_request:
push:
branches:
- main
jobs:
service-worker-smoke:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run build
- run: npx playwright install --with-deps chromium
- run: xvfb-run --auto-servernum npm run test:service-workerTest powinien oblać build, jeśli top-level runtime error blokuje rejestrację listenerów w workerze. W naszym repo demonstracyjnym odkomentowanie const title = document.title sprawia, że build przechodzi, a smoke test pada.
5. Checklista release
- 1.Zbuduj dokładnie ten output produkcyjny, który trafia do release zipa.
- 2.Załaduj ten output przez
--load-extension, nie pliki źródłowe. - 3.Poczekaj na prawdziwy
chrome-extension://service worker. - 4.Wyślij ping do handlera zarejestrowanego przez właściwy kod workera.
- 5.Nie uzależniaj smoke testu od API produktu, sesji użytkownika ani danych klienta.
- 6.Ustaw go jako wymagany check dla PR-ów zmieniających build albo release rozszerzenia.
To nie udowodni, że całe rozszerzenie działa. Udowodni, że background worker nie jest martwy od startu. Dla rozszerzeń MV3 to zasługuje na osobny check.
Powiązane artykuły
Jak budować rozszerzenia Chrome z React, Vite i CRXJS
Szerszy przewodnik po architekturze rozszerzeń MV3
CI/CD dla rozszerzeń przeglądarki
Jak utwardziliśmy CRXJS cross-platformowym CI
Jak szybciej dostarczać aktualizacje rozszerzeń Chrome
Lekcje z release pipeline po akceptacji Chrome Web Store
Repo MV3 Service Worker Smoke Test
Skopiuj sample Playwright do swojego rozszerzenia
Potrzebujesz utwardzić release pipeline rozszerzenia Chrome?
Budujemy i utrzymujemy produkcyjne rozszerzenia przeglądarkowe, w tym checki CI dla uprawnień, service workerów, pakowania i release do Chrome Web Store.
