jvinhit//lab

Search posts

Type to search across journal entries.

↑ ↓ navigate ↵ open esc close

Build Chrome Extensions · Part 2 — The Manifest, Deep Dive

Every manifest.json key that matters: action, permissions vs host_permissions, content_scripts, background, icons, web_accessible_resources, commands and side_panel — with an interactive manifest builder.

manifest.json là hợp đồng giữa extension và trình duyệt. Làm đúng thì mọi thứ vào khớp; làm sai thì không gì nạp được. Phần này là tài liệu tham chiếu bạn sẽ quay lại liên tục.

Bật tính năng trong builder và xem manifest tự ráp — tham chiếu khi ta đi:


1. Các key định danh

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "description": "Short description shown in the store and management page.",
  "icons": { "16": "icons/16.png", "48": "icons/48.png", "128": "icons/128.png" }
}
  • phải là 3.
  • chuỗi số có dấu chấm; Web Store yêu cầu tăng mỗi lần upload.
  • cung cấp tối thiểu 16, 48, 128.

2. action — nút trên thanh công cụ

"action": {
  "default_popup": "popup.html",
  "default_title": "My Extension",
  "default_icon": { "16": "icons/16.png", "48": "icons/48.png" }
}

Nếu bỏ default_popup, bấm icon sẽ kích hoạt chrome.action.onClicked — hữu ích cho extension kiểu bật/tắt không có UI.


3. permissions vs host_permissions

Sự phân biệt này là điều quan trọng nhất trong manifest.

  • quyền truy cập API chrome.* (khả năng):
"permissions": ["storage", "tabs", "scripting", "contextMenus", "notifications", "alarms"]
  • quyền truy cập dữ liệu của website cụ thể (origin):
"host_permissions": ["https://*.github.com/*", "https://api.example.com/*"]

Phân chia tư duy: permissions nói “tôi muốn dùng tính năng trình duyệt này”; host_permissions nói “tôi muốn đọc/sửa các site này”.

activeTab là bạn của bạn. Thay vì host_permissions rộng, quyền activeTab cấp truy cập tạm thời vào tab hiện tại chỉ khi user bấm icon — đỡ đáng sợ lúc cài và review store nhanh hơn.

Ta dành cả Phần 9 để dùng chúng an toàn.


4. content_scripts — code tự tiêm vào trang

"content_scripts": [
  {
    "matches": ["https://*.github.com/*"],
    "js": ["content.js"],
    "css": ["content.css"],
    "run_at": "document_idle"
  }
]
  • mẫu khớp quyết định trang nào được tiêm script.
  • thời điểm chạy.
  • cũng có exclude_matches, all_frames, và khớp theo glob.

Đầy đủ ở Phần 4.


5. background — service worker

"background": { "service_worker": "background.js", "type": "module" }

Ở MV3 nền là một service worker, không phải trang thường trú. "type": "module" cho phép dùng import. Phần 5 nói về vòng đời theo sự kiện của nó.


6. Bề mặt UI: options_page & side_panel

"options_page": "options.html",
"side_panel": { "default_path": "panel.html" }

options_page là trang cài đặt đầy đủ; side_panel (Chrome 114+) gắn một panel thường trú cạnh trang (cần quyền "sidePanel"). Cả hai ở Phần 8.


7. commands — phím tắt

"commands": {
  "toggle-feature": {
    "suggested_key": { "default": "Ctrl+Shift+Y", "mac": "Command+Shift+Y" },
    "description": "Toggle the feature"
  },
  "_execute_action": { "suggested_key": { "default": "Ctrl+Shift+E" } }
}

_execute_action đặc biệt mở popup bằng bàn phím. Lệnh tùy biến kích hoạt chrome.commands.onCommand trong service worker.


8. web_accessible_resources — phơi file cho trang

Mặc định trang web không nạp được file từ extension của bạn. Để tiêm một ảnh hoặc script vào trang, bạn phải whitelist:

"web_accessible_resources": [
  { "resources": ["inject.js", "logo.png"], "matches": ["https://*/*"] }
]

MV3 yêu cầu giới hạn matches (không phơi cho tất cả một cách mù quáng) — vá một lỗ bảo mật thật từ MV2.


9. Bức tranh đầy đủ

Một manifest thực tế cho extension tương đối mạnh:

{
  "manifest_version": 3,
  "name": "GitHub Helper",
  "version": "1.2.0",
  "description": "Adds shortcuts and metrics to GitHub.",
  "icons": { "16": "icons/16.png", "48": "icons/48.png", "128": "icons/128.png" },
  "action": { "default_popup": "popup.html" },
  "background": { "service_worker": "background.js", "type": "module" },
  "content_scripts": [
    { "matches": ["https://github.com/*"], "js": ["content.js"], "run_at": "document_idle" }
  ],
  "permissions": ["storage", "activeTab", "scripting", "contextMenus"],
  "host_permissions": ["https://api.github.com/*"],
  "options_page": "options.html",
  "commands": { "_execute_action": { "suggested_key": { "default": "Ctrl+Shift+G" } } }
}

10. Bài tập

1. Key nào để truy cập chrome.storage, key nào để đọc trang https://news.ycombinator.com?

Lời giải

permissions cho API; host_permissions cho site.

2. Bạn muốn một phím tắt mở popup. Thêm gì?

Lời giải
"commands": { "_execute_action": { "suggested_key": { "default": "Ctrl+Shift+E" } } }

3. Vì sao nên ưu tiên activeTab hơn "host_permissions": ["<all_urls>"] khi có thể?

Lời giải

activeTab cấp truy cập tạm thời, kích hoạt bằng click, chỉ tab hiện tại — đặc quyền tối thiểu, prompt cài đỡ đáng sợ, review store dễ hơn.

Nâng cao:trong builder, bật content scripts + host permissions + một command, và đọc xem entry nào xuất hiện trong mảng permissions.


Điểm chính

  • Manifest là hợp đồng; chỉ ba key bắt buộc, còn lại khai báo khả năng.
  • permissions = API chrome.*; host_permissions = truy cập site — giữ cả hai tối thiểu.
  • Mỗi bề mặt lớn có một key manifest.
  • web_accessible_resources (kèm matches) cần để phơi file extension cho trang.

Tiếp theo

Phần 3 — Kiến trúc & mô hình component: popup, service worker, content script, options page liên hệ ra sao, mỗi cái làm được và không làm được gì, và bức tranh luồng dữ liệu giúp phần còn lại của series “thông”.