# Browser Extensions für Automation & Productivity **Meta-Description:** Browser Extensions entwickeln für Automation. Manifest V3, Content Scripts, Background Workers und Cross-Browser Kompatibilität. **Keywords:** Browser Extension, Chrome Extension, Manifest V3, Content Script, Automation, Web Extension API --- ## Einführung Browser Extensions erweitern die Browser-Funktionalität direkt. Mit **Manifest V3** und der WebExtensions API können Sie Workflows automatisieren, Daten extrahieren und Produktivität steigern. --- ## Extension Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ BROWSER EXTENSION ARCHITECTURE │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Components: │ │ ├── Manifest (manifest.json) │ │ │ └── Extension Metadata & Permissions │ │ │ │ │ ├── Service Worker (Background) │ │ │ └── Event Handling, API Calls, State │ │ │ │ │ ├── Content Scripts │ │ │ └── DOM Manipulation auf Web Pages │ │ │ │ │ ├── Popup (UI) │ │ │ └── Toolbar Button Interface │ │ │ │ │ └── Options Page │ │ └── Extension Settings │ │ │ │ Communication: │ │ Content Script ←→ Service Worker ←→ Popup │ │ (chrome.runtime.sendMessage / onMessage) │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Manifest V3 Setup ```json // manifest.json { "manifest_version": 3, "name": "Automation Helper", "version": "1.0.0", "description": "Automate repetitive browser tasks", "permissions": [ "activeTab", "storage", "alarms", "contextMenus" ], "host_permissions": [ "https://*.example.com/*" ], "background": { "service_worker": "background.js", "type": "module" }, "content_scripts": [ { "matches": ["https://*.example.com/*"], "js": ["content.js"], "css": ["content.css"], "run_at": "document_idle" } ], "action": { "default_popup": "popup.html", "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }, "options_page": "options.html", "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } } ``` --- ## Service Worker (Background) ```typescript // background.ts chrome.runtime.onInstalled.addListener(() => { console.log('Extension installed'); // Context Menu erstellen chrome.contextMenus.create({ id: 'extract-data', title: 'Daten extrahieren', contexts: ['selection'] }); // Default Settings chrome.storage.sync.set({ autoExtract: true, extractInterval: 5 }); }); // Context Menu Handler chrome.contextMenus.onClicked.addListener((info, tab) => { if (info.menuItemId === 'extract-data' && info.selectionText) { processSelectedText(info.selectionText); } }); // Message Handler chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === 'EXTRACT_PAGE') { handleExtraction(message.data) .then(result => sendResponse({ success: true, data: result })) .catch(error => sendResponse({ success: false, error: error.message })); return true; // Async Response } if (message.type === 'GET_SETTINGS') { chrome.storage.sync.get(['autoExtract', 'extractInterval'], (settings) => { sendResponse(settings); }); return true; } }); // Alarm für wiederkehrende Tasks chrome.alarms.create('sync-data', { periodInMinutes: 5 }); chrome.alarms.onAlarm.addListener((alarm) => { if (alarm.name === 'sync-data') { syncDataToServer(); } }); async function handleExtraction(data: any) { // API Call oder Datenverarbeitung const response = await fetch('https://api.example.com/extract', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return response.json(); } async function syncDataToServer() { const { extractedData } = await chrome.storage.local.get('extractedData'); if (extractedData && extractedData.length > 0) { await fetch('https://api.example.com/sync', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(extractedData) }); // Clear nach Sync await chrome.storage.local.set({ extractedData: [] }); } } ``` --- ## Content Script ```typescript // content.ts // DOM Ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } function init() { console.log('Content script loaded on', window.location.href); // UI Element einfügen injectUI(); // Page Observer für dynamische Inhalte observePageChanges(); // Auto-Extract wenn aktiviert chrome.storage.sync.get('autoExtract', ({ autoExtract }) => { if (autoExtract) { extractPageData(); } }); } function injectUI() { const container = document.createElement('div'); container.id = 'extension-helper'; container.innerHTML = ` `; document.body.appendChild(container); document.getElementById('ext-extract-btn')?.addEventListener('click', () => { extractPageData(); }); } async function extractPageData() { const data = { url: window.location.href, title: document.title, timestamp: new Date().toISOString(), content: extractContent() }; // An Background Script senden const response = await chrome.runtime.sendMessage({ type: 'EXTRACT_PAGE', data }); if (response.success) { showNotification('Daten erfolgreich extrahiert!'); } else { showNotification('Fehler: ' + response.error, 'error'); } } function extractContent() { // Beispiel: Produkt-Daten extrahieren const products: any[] = []; document.querySelectorAll('.product-item').forEach((el) => { products.push({ name: el.querySelector('.product-name')?.textContent?.trim(), price: el.querySelector('.price')?.textContent?.trim(), image: el.querySelector('img')?.getAttribute('src') }); }); return products; } function observePageChanges() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes.length > 0) { // Neue Elemente verarbeiten handleNewElements(mutation.addedNodes); } }); }); observer.observe(document.body, { childList: true, subtree: true }); } function handleNewElements(nodes: NodeList) { nodes.forEach((node) => { if (node instanceof HTMLElement) { // Highlight neue Produkte const products = node.querySelectorAll('.product-item'); products.forEach((product) => { product.classList.add('ext-highlighted'); }); } }); } function showNotification(message: string, type: 'success' | 'error' = 'success') { const notification = document.createElement('div'); notification.className = `ext-notification ext-${type}`; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => notification.remove(), 3000); } ``` --- ## Popup UI ```html ``` ```typescript // popup.ts document.addEventListener('DOMContentLoaded', async () => { // Stats laden await updateStats(); // Event Listeners document.getElementById('extract-btn')?.addEventListener('click', extractCurrent); document.getElementById('batch-extract-btn')?.addEventListener('click', batchExtract); }); async function updateStats() { const { extractedCount = 0, syncedCount = 0 } = await chrome.storage.local.get([ 'extractedCount', 'syncedCount' ]); document.getElementById('extracted-count')!.textContent = extractedCount.toString(); document.getElementById('synced-count')!.textContent = syncedCount.toString(); } async function extractCurrent() { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab.id) return; // Message an Content Script const response = await chrome.tabs.sendMessage(tab.id, { type: 'EXTRACT' }); if (response.success) { setStatus('success', 'Extrahiert!'); await updateStats(); } else { setStatus('error', 'Fehler'); } } async function batchExtract() { const tabs = await chrome.tabs.query({ url: 'https://*.example.com/*' }); setStatus('loading', `Extrahiere ${tabs.length} Tabs...`); for (const tab of tabs) { if (tab.id) { await chrome.tabs.sendMessage(tab.id, { type: 'EXTRACT' }); } } setStatus('success', `${tabs.length} Seiten extrahiert`); await updateStats(); } function setStatus(type: 'success' | 'error' | 'loading', text: string) { const indicator = document.getElementById('status-indicator')!; const statusText = document.getElementById('status-text')!; indicator.className = `indicator ${type}`; statusText.textContent = text; } ``` --- ## Storage API ```typescript // Sync Storage (zwischen Geräten synchronisiert, 100KB Limit) await chrome.storage.sync.set({ settings: { autoExtract: true, theme: 'dark' } }); const { settings } = await chrome.storage.sync.get('settings'); // Local Storage (nur lokal, 5MB Limit) await chrome.storage.local.set({ extractedData: largeDataArray }); // Storage Change Listener chrome.storage.onChanged.addListener((changes, areaName) => { for (const [key, { oldValue, newValue }] of Object.entries(changes)) { console.log(`${areaName}.${key} changed from`, oldValue, 'to', newValue); } }); ``` --- ## Cross-Browser Kompatibilität ```typescript // Browser Detection const isChrome = typeof chrome !== 'undefined' && chrome.runtime; const isFirefox = typeof browser !== 'undefined'; // Unified API const browserAPI = isFirefox ? browser : chrome; // Polyfill für Firefox Promise-based API function promisify(chromeMethod: (...args: any[]) => void): (...args: any[]) => Promise { return (...args) => new Promise((resolve, reject) => { chromeMethod(...args, (result: T) => { if (chrome.runtime.lastError) { reject(chrome.runtime.lastError); } else { resolve(result); } }); }); } // webextension-polyfill verwenden import browser from 'webextension-polyfill'; // Unified API für alle Browser const tabs = await browser.tabs.query({ active: true }); ``` --- ## Fazit Browser Extensions bieten: 1. **Tiefe Integration**: Direkter DOM-Zugriff 2. **Automation**: Wiederkehrende Tasks automatisieren 3. **Produktivität**: Workflows optimieren 4. **Cross-Platform**: Chrome, Firefox, Edge Mächtige Tools für Power-User und Entwickler. --- ## Bildprompts 1. "Browser with extension icon showing automation, productivity concept" 2. "Extension popup interacting with webpage, data extraction" 3. "Multiple browser windows synchronized, cross-browser extension" --- ## Quellen - [Chrome Extension Documentation](https://developer.chrome.com/docs/extensions/) - [Manifest V3 Migration](https://developer.chrome.com/docs/extensions/mv3/intro/) - [Firefox WebExtensions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions) - [webextension-polyfill](https://github.com/nicknisi/webextension-polyfill)