Chapter 03 Manifest File Explained
Chapter 3: Manifest File Explained
- Deeply understand the various configuration items in manifest.json
- Master permission declarations and security configuration
- Understand the differences between Manifest V2 and V3
Knowledge Summary
Manifest File Overview
The Manifest file is the configuration file for Chrome Extensions, defining the extension’s metadata, permissions, resources, and behavior. It is a required file for every extension and is located in the extension’s root directory.
Manifest Version Evolution
Manifest V3 Core Configuration
Basic Information Fields
{
"manifest_version": 3,
"name": "My Extension",
"version": "1.0.0",
"version_name": "v1.0.0",
"description": "This is a powerful Chrome extension",
"short_name": "MyExt",
"author": "Developer Name",
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
}
}
Configuration Explanation:
manifest_version: Required, version number (recommended to use 3)name: Required, extension nameversion: Required, version numberdescription: Extension description (maximum 132 characters)short_name: Short name (maximum 12 characters)author: Author informationversion_name: User-friendly version identifiericons: Mapping of icon sizes and paths
Action Configuration (formerly Browser Action)
Action Configuration Examples
Simple Popup:
{
"action": {
"default_popup": "popup.html",
"default_title": "Click to open extension"
}
}
Multiple Icon Sizes:
{
"action": {
"default_icon": {
"16": "icons/icon-16.png",
"24": "icons/icon-24.png",
"32": "icons/icon-32.png"
},
"default_title": "My Extension"
}
}
Icon Only (No Popup):
{
"action": {
"default_icon": "icon.png",
"default_title": "Click to trigger background event"
}
}
Permission System Explained
Permission Types and Declarations
Permission Categories
Basic Permissions:
activeTab- Access the current active tabtabs- Access all tab informationstorage- Use storage APIcontextMenus- Add context menu itemsnotifications- Display notificationsalarms- TimersclipboardRead- Read clipboardclipboardWrite- Write to clipboard
Advanced Permissions:
bookmarks- Access bookmarkshistory- Access browsing historydownloads- Manage downloadsmanagement- Manage other extensionscookies- Access cookieswebRequest- Intercept network requestswebRequestBlocking- Block network requestsproxy- Control proxy settingsdebugger- Use debugger API
Host Permissions:
<all_urls>- Access all websites*://*.google.com/*- Specific domainhttps://*/- All HTTPS websitesfile:///*- Local files
Permission Configuration Example:
{
"permissions": ["storage", "tabs"],
"optional_permissions": ["bookmarks", "downloads"],
"host_permissions": ["https://*.example.com/*"]
}
Permission Best Practices
1. Principle of Least Privilege - Only request necessary permissions
{
"permissions": ["storage", "activeTab"],
"optional_permissions": ["downloads", "bookmarks"]
}
2. Dynamic Permission Requests - Request optional permissions at runtime
// Request optional permissions
chrome.permissions.request({
permissions: ['bookmarks'],
origins: ['https://www.example.com/']
}, (granted) => {
if (granted) {
// Permission granted
console.log('Permission granted');
} else {
// User denied
console.log('Permission denied');
}
});
3. Permission Checks - Check permissions before use
// Check permissions
chrome.permissions.contains({
permissions: ['bookmarks'],
origins: ['https://www.example.com/']
}, (result) => {
if (result) {
// Has permission
performAction();
} else {
// Request permission
requestPermission();
}
});
Content Security Policy (CSP)
CSP Configuration Examples
Default CSP (Strictest):
{
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}
Allow WASM:
{
"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
}
}
Sandbox Page CSP:
{
"content_security_policy": {
"sandbox": "sandbox allow-scripts allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"
}
}
CSP Violation Event Handling:
// Listen for CSP violation events
document.addEventListener('securitypolicyviolation', (e) => {
console.error('CSP violation:', {
blockedURI: e.blockedURI,
violatedDirective: e.violatedDirective,
originalPolicy: e.originalPolicy,
sourceFile: e.sourceFile,
lineNumber: e.lineNumber
});
// Report violation to background
chrome.runtime.sendMessage({
type: 'csp_violation',
details: {
uri: e.blockedURI,
directive: e.violatedDirective
}
});
});
Background Scripts Configuration
Service Worker (Manifest V3)
Manifest V3 Uses Service Worker:
{
"background": {
"service_worker": "background.js",
"type": "module"
}
}
Service Worker Example Code:
// background.js - Service Worker
// Extension installation event
chrome.runtime.onInstalled.addListener((details) => {
console.log('Extension installed:', details);
// Execute different operations based on installation reason
switch(details.reason) {
case 'install':
console.log('First installation');
// Set default values
chrome.storage.local.set({
installed: true,
version: chrome.runtime.getManifest().version
});
break;
case 'update':
console.log('Extension update');
// Execute migration logic
migrateData(details.previousVersion);
break;
case 'chrome_update':
console.log('Chrome update');
break;
}
});
// Listen for messages from content scripts
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('Message received:', request, 'from:', sender);
// Async handling
(async () => {
try {
const result = await handleMessage(request, sender);
sendResponse({success: true, data: result});
} catch (error) {
sendResponse({success: false, error: error.message});
}
})();
return true; // Keep message channel open
});
// Listen for tab updates
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
console.log('Tab loaded:', tab.url);
}
});
// Scheduled tasks
chrome.alarms.create('periodicTask', {
periodInMinutes: 30 // Execute every 30 minutes
});
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'periodicTask') {
performPeriodicTask();
}
});
// Service Worker lifecycle
self.addEventListener('activate', (event) => {
console.log('Service Worker activated');
});
// Handle fetch events (only needed in specific scenarios)
self.addEventListener('fetch', (event) => {
// Can intercept and modify network requests
console.log('Fetch event:', event.request.url);
});
async function handleMessage(request, sender) {
// Message handling logic
switch(request.type) {
case 'GET_DATA':
return await getData(request.key);
case 'SAVE_DATA':
return await saveData(request.key, request.value);
default:
throw new Error('Unknown message type');
}
}
async function performPeriodicTask() {
// Periodically executed task
console.log('Executing periodic task');
}
Content Scripts Configuration
Content Script Injection Configuration
Static Declaration Method:
{
"content_scripts": [
{
"matches": ["*://*.example.com/*"],
"js": ["content.js"],
"css": ["content.css"],
"run_at": "document_end",
"all_frames": false,
"match_about_blank": false,
"world": "ISOLATED"
}
]
}
Injection Timing Options:
document_start- When DOM construction begins (earliest)document_end- When DOM construction completes (default)document_idle- When page is idle or after DOM completes
Execution Environment Options (V3):
ISOLATED- Isolated environment (default, has its own global scope)MAIN- Main world (shares global scope with page)
Dynamic Injection Example:
// Dynamically inject content script
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
chrome.scripting.executeScript({
target: {tabId: tabs[0].id},
files: ['content.js']
});
// Or inject CSS
chrome.scripting.insertCSS({
target: {tabId: tabs[0].id},
files: ['content.css']
});
// Or inject function
chrome.scripting.executeScript({
target: {tabId: tabs[0].id},
func: injectedFunction,
args: ['arg1', 'arg2']
});
});
function injectedFunction(arg1, arg2) {
console.log('Injected function executed:', arg1, arg2);
// This function will execute in the page context
}
Advanced Matching Patterns:
Include Specific Paths:
["*://example.com/path/*"]
Exclude Specific Pages:
{
"matches": ["*://example.com/*"],
"exclude_matches": ["*://example.com/admin/*"]
}
Using Glob Patterns:
{
"matches": ["*://example.com/*"],
"include_globs": ["*://example.com/user/*"],
"exclude_globs": ["*://example.com/*/private/*"]
}
Manifest V2 vs V3 Differences
Major Differences Comparison
| Feature | Manifest V2 | Manifest V3 | Notes |
|---|---|---|---|
| Background Script | background: { scripts: ['bg.js'], persistent: false } | background: { service_worker: 'sw.js' } | V3 uses Service Worker instead of background page |
| Host Permissions | permissions: ['<all_urls>'] | host_permissions: ['<all_urls>'] | V3 separates host permissions into a separate field |
| Action API | browser_action or page_action | action (unified) | V3 unifies to action API |
| Web Request API | Full blocking webRequest | declarativeNetRequest (declarative) | V3 restricts blocking network requests |
| Content Security Policy | Can use unsafe-eval | Prohibits unsafe-eval (except WASM) | V3 strengthens security restrictions |
| Remote Code | Can load remote code | Prohibits remote code execution | V3 requires all code packaged in extension |
Manifest V2 to V3 Migration Guide
1. Update manifest_version
// V2
"manifest_version": 2
// V3
"manifest_version": 3
2. Migrate Background Script
// V2 - background.js
chrome.browserAction.onClicked.addListener(() => {
// Handle click
});
// V3 - service-worker.js
chrome.action.onClicked.addListener(() => {
// Handle click
});
3. Update Permission Declarations
// V2
{
"permissions": [
"tabs",
"https://example.com/*"
]
}
// V3
{
"permissions": ["tabs"],
"host_permissions": ["https://example.com/*"]
}
4. Replace Web Request API
// V2 - Using webRequest
chrome.webRequest.onBeforeRequest.addListener(
(details) => {
return {cancel: true};
},
{urls: ["*://example.com/*"]},
["blocking"]
);
// V3 - Using declarativeNetRequest
chrome.declarativeNetRequest.updateDynamicRules({
addRules: [{
id: 1,
priority: 1,
action: {type: "block"},
condition: {urlFilter: "example.com"}
}]
});
5. Handle Service Worker Lifecycle
// V3 - Service Worker will automatically sleep
// Use chrome.storage instead of global variables
let data; // ❌ Avoid using
// ✅ Use storage
chrome.storage.local.set({data: value});
chrome.storage.local.get(['data'], (result) => {
// Use data
});
Complete Manifest Example
Production Project Configuration
Complete Manifest V3 Configuration Example:
{
"manifest_version": 3,
"name": "Advanced Chrome Extension",
"version": "2.0.0",
"description": "Feature-complete Chrome extension example",
"author": "Your Name",
"icons": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png",
"48": "icons/icon-48.png",
"128": "icons/icon-128.png"
},
"action": {
"default_popup": "popup/popup.html",
"default_icon": {
"16": "icons/icon-16.png",
"32": "icons/icon-32.png"
},
"default_title": "Click to view options"
},
"background": {
"service_worker": "background/service-worker.js",
"type": "module"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content/content.js"],
"css": ["content/content.css"],
"run_at": "document_idle",
"all_frames": false
}
],
"permissions": [
"storage",
"tabs",
"notifications",
"alarms",
"contextMenus"
],
"optional_permissions": [
"bookmarks",
"history",
"downloads"
],
"host_permissions": [
"https://*/*",
"http://localhost/*"
],
"options_page": "options/options.html",
"web_accessible_resources": [
{
"resources": ["images/*.png", "styles/*.css"],
"matches": ["<all_urls>"]
}
],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
},
"commands": {
"_execute_action": {
"suggested_key": {
"default": "Ctrl+Shift+Y",
"mac": "Command+Shift+Y"
},
"description": "Open extension popup"
},
"toggle-feature": {
"suggested_key": {
"default": "Ctrl+Shift+U"
},
"description": "Toggle feature switch"
}
},
"minimum_chrome_version": "88",
"default_locale": "en"
}
Configuration Validation Script:
// Validate Manifest configuration
async function validateManifest() {
const manifest = chrome.runtime.getManifest();
console.log('Manifest validation:');
console.log('- Version:', manifest.version);
console.log('- Permissions:', manifest.permissions);
console.log('- Host permissions:', manifest.host_permissions);
// Check required fields
const required = ['manifest_version', 'name', 'version'];
const missing = required.filter(field => !manifest[field]);
if (missing.length > 0) {
console.error('Missing required fields:', missing);
return false;
}
// Check version format
const versionPattern = /^\d+\.\d+\.\d+$/;
if (!versionPattern.test(manifest.version)) {
console.error('Invalid version format:', manifest.version);
return false;
}
console.log('✅ Manifest validation passed');
return true;
}
validateManifest();
- Version Compatibility: Ensure target Chrome version supports the APIs used
- Permission Requests: Follow the principle of least privilege, avoid excessive requests
- Security Policy: Strictly adhere to CSP rules to ensure extension security
- Migration Plan: V2 extensions need to migrate to V3 as soon as possible
Chapter Summary
This chapter provided in-depth coverage of Chrome Extension Manifest file configuration:
- Basic Configuration: Mastered required fields and basic information setup
- Permission System: Understood permission types and request strategies
- Background Scripts: Learned Service Worker configuration methods
- Content Scripts: Understood content script injection configuration
- Version Differences: Compared major differences between V2 and V3
- Migration Guide: Mastered migration methods from V2 to V3
The next chapter will cover detailed development of Content Scripts.