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 đượckhô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”.