Build Chrome Extensions · Part 12 — Publish, Auto-Update, Cross-Browser & Capstone
Package and upload to the Chrome Web Store, pass review, version and auto-update, port to Firefox and Edge, and build a capstone "Reading Ruler" extension that ties the whole series together. With an interactive ship checklist.
You’ve built the mental model, the architecture, every API, and a modern toolchain {Bạn đã xây mô hình tư duy, kiến trúc, mọi API, và bộ công cụ hiện đại}. The last step is getting your extension into users’ hands and keeping it there {Bước cuối là đưa extension tới tay user và giữ nó ở đó}. Then we’ll assemble everything into a real capstone {Rồi ta ráp mọi thứ thành một capstone thật}.
Tick the ship checklist below and study the capstone map {Đánh dấu checklist phát hành bên dưới và nghiên cứu bản đồ capstone}:
1. Packaging {Đóng gói}
Run the production build (Part 11), then zip the contents of dist/ — not the parent folder {Chạy build production (Phần 11), rồi nén nội dung của dist/ — không phải thư mục cha}:
npm run build
cd dist && zip -r ../my-extension.zip . && cd ..
The zip’s root must contain manifest.json directly {Gốc của zip phải chứa manifest.json trực tiếp}. Double-check the version number is higher than any published version — the store rejects equal or lower versions {Kiểm tra số phiên bản cao hơn mọi phiên bản đã phát hành — store từ chối phiên bản bằng hoặc thấp hơn}.
2. The Chrome Web Store {Chrome Web Store}
- Register a developer account — a one-time $5 fee covers unlimited extensions {Đăng ký tài khoản dev — phí một lần $5 cho không giới hạn extension}.
- Create a new item and upload your zip {Tạo item mới và tải zip lên}.
- Fill the listing: name, description, category, a 128×128 icon, screenshots, and promo tiles {Điền listing: tên, mô tả, danh mục, icon 128×128, ảnh chụp, và ô quảng bá}.
- Add a privacy policy if you touch user data (required for many permissions) {Thêm chính sách bảo mật nếu chạm dữ liệu user (bắt buộc cho nhiều quyền}).
- Justify each permission in the review notes {Giải thích từng quyền trong ghi chú duyệt}.
- Submit for review — it can take from hours to several days {Gửi duyệt — có thể mất từ vài giờ đến vài ngày}.
The biggest rejection causes are unjustified broad permissions and minified-but-unexplained code — both avoidable with the lessons in Part 9 {Nguyên nhân từ chối lớn nhất là quyền rộng không lý do và code minify không giải thích — đều tránh được với bài học Phần 9}.
3. Versioning & auto-update {Đánh phiên bản & tự cập nhật}
Chrome auto-updates installed extensions {Chrome tự cập nhật extension đã cài}. To ship an update, bump version, rebuild, and upload a new zip {Để ship cập nhật, tăng version, build lại, và tải zip mới}:
{ "version": "1.1.0" }
Use the onInstalled reason === "update" branch to run data migrations between versions (Part 7) {Dùng nhánh reason === "update" của onInstalled để chạy di trú dữ liệu giữa các phiên bản (Phần 7)}. Users get the update automatically within hours — no action needed on their side {User nhận cập nhật tự động trong vài giờ — họ không cần làm gì}.
4. Cross-browser {Đa trình duyệt}
- Edge runs Chromium — your same zip works on the Microsoft Edge Add-ons store, often with zero changes {Edge chạy Chromium — cùng zip chạy trên store Edge Add-ons, thường không đổi gì}.
- Firefox supports MV3 but uses the
browser.*namespace (promise-based) and has some API differences {Firefox hỗ trợ MV3 nhưng dùng namespacebrowser.*(dựa promise) và có vài khác biệt API}. Thewebextension-polyfilllets you writebrowser.*everywhere and run on both {webextension-polyfillcho bạn viếtbrowser.*khắp nơi và chạy cả hai}.
import browser from "webextension-polyfill";
const { theme } = await browser.storage.local.get("theme"); // works in Chrome + Firefox
Write to the browser.* promise API from the start and you stay portable {Viết theo API promise browser.* từ đầu thì bạn giữ tính di động}.
5. Capstone — the “Reading Ruler” {Capstone — “Reading Ruler”}
Let’s tie the whole series into one extension: a reading ruler that highlights the line under the cursor, helping focus while reading {Hãy gắn cả series vào một extension: một thước đọc tô sáng dòng dưới con trỏ, giúp tập trung khi đọc}. Each piece maps to a part {Mỗi mảnh ánh xạ tới một phần}:
| Piece {Mảnh} | Does {Làm} | Parts |
|---|---|---|
| Popup | toggle on/off, pick color & height {bật/tắt, chọn màu & chiều cao} | 8, 7 |
| Content script | draws the ruler overlay in a Shadow DOM, follows the mouse {vẽ overlay thước trong Shadow DOM, theo chuột} | 4, 9 |
| Service worker | handles the command + context menu, relays toggles {xử lý command + context menu, chuyển tiếp toggle} | 5, 6, 10 |
| Options page | opacity, presets, shortcut hint {độ mờ, preset, gợi ý phím tắt} | 8 |
chrome.storage + onChanged | single source of truth, live reactivity {nguồn sự thật duy nhất, phản ứng trực tiếp} | 7 |
commands + action badge | Ctrl+Shift+R toggles; badge shows state {Ctrl+Shift+R bật/tắt; badge hiện trạng thái} | 10, 8 |
The flow: the popup writes { enabled: true, color, height } to storage → onChanged fires → the content script in every open tab shows/updates the ruler → the action badge reflects the state {Luồng: popup ghi { enabled: true, color, height } vào storage → onChanged kích hoạt → content script trong mọi tab mở hiện/cập nhật thước → badge action phản ánh trạng thái}. No manual broadcasting, no persistent worker state — exactly the patterns this series taught {Không phát thủ công, không state worker thường trú — đúng các mẫu series này dạy}.
The capstone map in the demo shows all six pieces and which parts each draws on {Bản đồ capstone trong demo hiện cả sáu mảnh và phần nào mỗi cái dựa vào}.
6. Where to go next {Đi đâu tiếp}
declarativeNetRequestfor ad/tracker blocking without reading every request {declarativeNetRequestđể chặn quảng cáo/tracker mà không đọc mọi request}.offscreendocuments for DOM APIs (audio, clipboard) the worker can’t use {Tài liệuoffscreencho API DOM (âm thanh, clipboard) mà worker không dùng được}.chrome.identityfor OAuth flows {chrome.identitycho luồng OAuth}.- Enterprise policies and the
managedstorage area for org deployments {Chính sách doanh nghiệp và khu vực storagemanagedcho triển khai tổ chức}.
Each builds directly on the foundation you now have {Mỗi cái dựng trực tiếp trên nền tảng bạn đã có}.
7. Exercises {Bài tập}
1. You uploaded version 1.0.0, fixed a bug, and re-uploaded 1.0.0. The store rejects it. Why? {Bạn tải phiên bản 1.0.0, sửa bug, và tải lại 1.0.0. Store từ chối. Vì sao?}
Solution {Lời giải}
The version must increase. Bump to 1.0.1 and re-upload {Phiên bản phải tăng. Tăng lên 1.0.1 và tải lại}.
2. Your extension works in Chrome but chrome.storage is undefined in Firefox. Cleanest fix? {Extension chạy trong Chrome nhưng chrome.storage là undefined trong Firefox. Cách sửa sạch nhất?}
Solution {Lời giải}
Use webextension-polyfill and the browser.* promise API so the same code runs in both {Dùng webextension-polyfill và API promise browser.* để cùng code chạy cả hai}.
3. In the capstone, the user toggles the ruler in the popup but already-open tabs don’t update. Which mechanism makes them react without manual messaging? {Trong capstone, user bật thước trong popup nhưng các tab đã mở không cập nhật. Cơ chế nào làm chúng phản ứng mà không cần messaging thủ công?}
Solution {Lời giải}
Each content script listens to chrome.storage.onChanged and re-renders when the setting changes {Mỗi content script lắng nghe chrome.storage.onChanged và render lại khi cài đặt đổi}.
Stretch {Nâng cao}: complete the ship checklist in the demo to 100% — that’s the literal sequence to take any extension live {hoàn thành checklist phát hành trong demo tới 100% — đó là trình tự đúng nghĩa để đưa bất kỳ extension nào lên live}.
Key takeaways {Điểm chính}
- Ship the zipped
dist/withmanifest.jsonat the root and an ever-increasing version {Shipdist/đã nén vớimanifest.jsonở gốc và version luôn tăng}. - Pass review by justifying every permission and keeping the set lean {Vượt duyệt bằng cách giải thích từng quyền và giữ bộ gọn}.
- Chrome auto-updates users; run migrations in the
updatebranch {Chrome tự cập nhật user; chạy di trú ở nhánhupdate}. - Reach Edge for free; use
webextension-polyfillfor Firefox {Tới Edge miễn phí; dùngwebextension-polyfillcho Firefox}. - A real extension is just all the series’ pieces working as one system {Một extension thật chỉ là tất cả mảnh của series hoạt động như một hệ thống}.
Series complete {Hoàn thành series}
That’s the full journey — from “what is an extension” to a published, cross-browser, professionally-tooled product {Đó là toàn bộ hành trình — từ “extension là gì” tới một sản phẩm đã phát hành, đa trình duyệt, có công cụ chuyên nghiệp}. You now have the mental model and the concrete patterns to build almost anything in the browser {Giờ bạn có mô hình tư duy và các mẫu cụ thể để xây gần như mọi thứ trong trình duyệt}. Go ship something {Đi ship gì đó đi}. 🚀