Eine Chrome/Chromium-Browser-Extension, die komplette Webseiten als ZIP-Archiv (HTML + Assets) oder als einzelne HTML-Datei mit eingebetteten Ressourcen herunterlädt. Alle externen Ressourcen werden erfasst, CORS-Beschränkungen umgangen und Dateien parallel geladen.
- ZIP-Archiv oder Einzeldatei -- Wahl zwischen ZIP (HTML + separate Asset-Dateien, kein Base64-Overhead) oder Single-HTML (alles als Base64 eingebettet, einfach teilbar)
- CORS-freier Download -- Background Service Worker fetcht Ressourcen ohne CORS-Restriktionen, wo Content Scripts blockiert werden
- Paralleles Laden -- Batch-Fetch mit 6 parallelen Workern und 10er-Chunk-Verarbeitung statt sequentiellem Download
- URL-Deduplizierung -- Cache-Map stellt sicher, dass gleiche Ressourcen nur einmal geladen und im ZIP nur einmal gespeichert werden
- Fortschrittsanzeige -- Live-Progressbar mit Stage-Labels (CSS, Bilder, Fonts, ...) und Ressourcen-Counter
- Timeout-Schutz -- 15-Sekunden-Timeout pro Ressource verhindert hängende Downloads
- Vollständige Offline-Kopien -- Alle visuellen Elemente einer Seite werden erfasst
- Deutsche Benutzeroberfläche -- Komplett auf Deutsch lokalisiert
| Ressource | Details |
|---|---|
| CSS-Stylesheets | Externe Stylesheets, Inline-<style>-Tags, rekursive @import-Auflösung (mit Zirkulärschutz, max. Tiefe 10) |
CSS url()-Referenzen |
Fonts, Hintergrundbilder, Cursor-Icons und alle weiteren url()-Verweise innerhalb von CSS |
| Bilder | <img src>, <img srcset> (responsive Bilder mit Breitenangaben), <picture>/<source> Elemente |
| SVG-Dateien | <img src="*.svg">, <object data="*.svg"> (mit Query-Parameter-Handling) |
| Hintergrundbilder | Inline-style-Attribute mit url(), sowie Computed Styles aus CSS-Regeln (nicht nur inline) |
| Favicons | <link rel="icon">, <link rel="shortcut icon">, <link rel="apple-touch-icon"> |
| JavaScript | Externe Scripts -- im ZIP-Modus als separate .js-Dateien, im HTML-Modus inline eingebettet (alle Attribute wie async, defer, type werden beibehalten) |
| Schriftarten | In CSS referenzierte Web-Fonts via @font-face und url() (WOFF, WOFF2, TTF, OTF) |
| Video-Poster | <video poster> Attribute (Vorschaubilder) |
| Preload-Ressourcen | <link rel="preload"> für Fonts, Images und Styles |
- Zur neuesten Release-Version gehen
- ZIP-Datei unter "Assets" herunterladen
- ZIP-Datei entpacken
- Chrome/Chromium öffnen und zu
chrome://extensions/navigieren - Entwicklermodus aktivieren (Toggle oben rechts)
- Entpackte Extension laden klicken
- Entpackten Ordner auswählen
git clone https://github.com/pepperonas/site-loader-extension.git- Chrome/Chromium öffnen und zu
chrome://extensions/navigieren - Entwicklermodus aktivieren (Toggle oben rechts)
- Entpackte Extension laden klicken
- Den geklonten Ordner auswählen
- Webseite öffnen, die heruntergeladen werden soll
- Extension-Icon in der Browser-Toolbar klicken
- Modus wählen: ZIP-Archiv (Standard) oder Einzelne HTML
- Seite herunterladen klicken
- Fortschritt in der Progressbar verfolgen
- Datei wird automatisch im Download-Ordner gespeichert
Erzeugt ein ZIP-Archiv mit folgender Struktur:
website_2025-03-29.zip
├── index.html # Hauptseite mit relativen Asset-Pfaden
└── assets/
├── img/ # Bilder (PNG, JPG, WebP, SVG, ...)
├── js/ # JavaScript-Dateien
├── css/ # (inline im HTML, Fonts/Bilder hier)
├── bg/ # Hintergrundbilder
├── svg/ # SVG-Dateien aus <object>-Tags
└── fonts/ # Web-Fonts (WOFF2, WOFF, TTF)
Vorteile: Keine Base64-Aufblähung (+33%), kleinere Dateien, Ressourcen können einzeln inspiziert werden.
Erzeugt eine einzelne .html-Datei mit allen Ressourcen als Base64 Data-URIs eingebettet.
Vorteile: Eine einzige Datei, einfach per E-Mail oder Messenger teilbar.
| Permission | Verwendung |
|---|---|
activeTab |
Zugriff auf den Inhalt des aktiven Tabs |
scripting |
Dynamische Injection von Content Script und JSZip |
downloads |
Download der generierten Dateien auslösen |
Die Extension benötigt keine <all_urls>-Berechtigung und hat keinen Zugriff auf Tabs, die nicht aktiv angeklickt werden.
┌──────────────┐ chrome.runtime ┌─────────────────────────┐
│ Popup (UI) │ ──── sendMessage ──────> │ Background Service │
│ popup.html │ <─── onMessage ───────── │ Worker (background.js) │
│ popup.js │ │ │
└──────────────┘ │ - CORS-freier fetch() │
^ │ - Batch mit 6 Workern │
│ progress │ - 15s Timeout/Resource │
│ updates │ - Script Injection │
│ └────────┬────────────────┘
│ │
│ chrome.tabs.sendMessage
│ │
│ v
│ ┌────────────────────────┐
└────────────── progress ───────── │ Content Script │
│ (content.js) │
│ │
│ 1. DOM klonen │
│ 2. CSS verarbeiten │
│ 3. Bilder einbetten │
│ 4. SVGs einbetten │
│ 5. Backgrounds │
│ 6. Computed Styles │
│ 7. Favicons │
│ 8. Scripts │
│ 9. Video Poster │
│ 10. Preload │
│ 11. ZIP/HTML erzeugen │
│ 12. Download starten │
└────────────────────────┘
Die Verarbeitung erfolgt in einer festen Reihenfolge, um Abhängigkeiten korrekt aufzulösen:
-
CSS Stylesheets -- Externe
<link>Stylesheets werden geladen und als<style>-Tags eingebettet. Dabei werden rekursiv alle@import-Anweisungen aufgelöst (mit Zirkulärschutz) und sämtlicheurl()-Referenzen (Fonts, Bilder) konvertiert. -
Bilder -- Alle
<img src>werden verarbeitet. Bereits eingebettete Data-URIs (data:...) werden übersprungen. Zusätzlich werdensrcset-Attribute auf<img>und<source>-Elementen mit allen Breitenangaben verarbeitet. -
SVGs --
<object data="*.svg">Elemente werden separat behandelt, da sie ein eigenes Dokument referenzieren. -
Inline Background Images -- Elemente mit
style-Attributen, dieurl()enthalten, werden gescannt und die referenzierten Bilder eingebettet. -
Computed Background Images -- Hintergrundbilder, die über CSS-Klassen (nicht inline) gesetzt werden, werden über
getComputedStyle()auf dem Live-DOM ermittelt und auf den geklonten DOM übertragen. -
Favicons -- Alle
<link rel="icon">,rel="shortcut icon"undrel="apple-touch-icon"werden eingebettet. -
JavaScript -- Externe
<script src>werden geladen. Im ZIP-Modus als separate Dateien, im HTML-Modus als Inline-Scripts (alle Attribute außersrcwerden beibehalten). -
Video Poster --
<video poster>Vorschaubilder werden eingebettet. -
Preload-Ressourcen --
<link rel="preload">für Fonts, Images und Styles werden eingebettet.
Content Scripts unterliegen der Same-Origin-Policy der Webseite. Viele CDN-Ressourcen (Google Fonts, Cloudflare, etc.) blockieren Cross-Origin-Requests ohne passenden Access-Control-Allow-Origin-Header.
Die Extension löst das, indem alle Fetches über den Background Service Worker laufen. Dieser hat keine CORS-Restriktionen und kann beliebige URLs laden. Der Content Script sendet die URL per chrome.runtime.sendMessage, der Service Worker fetcht die Ressource und gibt das Ergebnis (Base64 oder ArrayBuffer) zurück.
- Batch-Fetching: URLs werden in 10er-Gruppen an den Service Worker gesendet, um IPC-Overhead zu reduzieren
- 6 parallele Worker: Der Service Worker verarbeitet 6 Fetches gleichzeitig
- URL-Cache: Bereits geladene Ressourcen werden aus dem Cache bedient (Map mit
responseType:urlals Key) - Asset-Pfad-Deduplizierung:
registerZipAsset()stellt sicher, dass jede URL exakt einen Pfad im ZIP bekommt -- verhindert Inkonsistenzen zwischen HTML-Referenzen und ZIP-Inhalt - Force-Cache: Fetch-Requests nutzen
cache: 'force-cache', um bereits im Browser gecachte Ressourcen zu verwenden
- Non-blocking: Fehlgeschlagene Ressourcen (CORS, 404, Timeout) werden geloggt aber übersprungen -- der Download wird nicht abgebrochen
- 15s Timeout: Jeder einzelne Fetch hat einen AbortController mit 15-Sekunden-Timeout
- Fallback-Injection: Wenn der Content Script noch nicht geladen ist (z.B. Extension gerade installiert), wird er dynamisch injiziert
- JSZip-Fallback: Wenn JSZip nicht verfügbar ist, wird automatisch auf HTML-Modus zurückgefallen
- Zirkulärer @import-Schutz: Bereits besuchte Import-URLs werden übersprungen, maximale Rekursionstiefe von 10
{seitentitel}_{YYYY-MM-DD}.zip (ZIP-Modus)
{seitentitel}_{YYYY-MM-DD}.html (HTML-Modus)
Der Seitentitel wird bereinigt: Sonderzeichen werden durch Unterstriche ersetzt, alles in Kleinbuchstaben. Deutsche Umlaute bleiben erhalten.
site-loader-extension/
├── manifest.json # Extension-Konfiguration (Manifest V3)
├── background.js # Service Worker: CORS-Fetch, Batch-Processing, Message-Relay
├── content.js # Ressourcen-Embedding-Pipeline (1000+ Zeilen)
├── popup.html # UI: Modus-Toggle, Progressbar, Status
├── popup.js # UI-Logik: Event-Handler, Progress-Listener
├── lib/
│ └── jszip.min.js # JSZip v3.10.1 (~97KB)
├── banner.png # README-Banner
├── icon16.png # Extension-Icon 16x16
├── icon48.png # Extension-Icon 48x48
├── icon128.png # Extension-Icon 128x128
├── CLAUDE.md # Claude Code Projektdokumentation
├── CHANGELOG.md # Änderungshistorie
└── README.md # Diese Datei
| Ressource | Grund |
|---|---|
| Video-/Audio-Streams | Würden zu riesigen Dateien führen (oft 100+ MB) |
| Canvas/WebGL-Inhalte | Dynamisch zur Laufzeit gerendert, nicht serialisierbar |
| iFrame-Inhalte | Separate Dokumente mit eigenen Security Contexts |
| WebSocket-/API-Daten | Laufzeitabhängig, können offline nicht reproduziert werden |
- JavaScript-Sicherheit: Externe Scripts werden eingebettet und ausgeführt. Nur vertrauenswürdige Webseiten herunterladen.
- Offline-Funktionalität: API-Aufrufe, WebSockets und dynamisch nachgeladene Inhalte funktionieren in der heruntergeladenen Datei nicht.
- ZIP vs. HTML Größe: ZIP-Modus eliminiert den ~33% Base64-Overhead. Eine 10MB-Seite wird als ZIP ca. 10MB, als HTML ca. 13MB.
- Chrome-Limit: Chrome hat ein Blob-URL-Limit von ca. 500MB. Extrem große Seiten könnten dieses Limit erreichen.
- Geschützte Seiten: Chrome Web Store,
chrome://-Seiten und andere System-URLs können nicht heruntergeladen werden.
| Geänderte Datei | Aktion |
|---|---|
popup.html, popup.js |
Popup schließen und neu öffnen |
content.js |
Extension unter chrome://extensions/ neu laden und Zielwebseite aktualisieren |
background.js, manifest.json |
Extension unter chrome://extensions/ neu laden |
| Kontext | Zugang |
|---|---|
| Popup | Rechtsklick auf Extension-Icon, "Popup prüfen" |
| Service Worker | chrome://extensions/ dann "Service Worker" Link bei der Extension |
| Content Script | F12 auf der Zielwebseite, Console-Tab |
"Fehler beim Laden der Ressource" in der Console:
- Normal für CORS-geschützte Ressourcen, die auch über den Service Worker nicht erreichbar sind (z.B. Auth-geschützte Assets). Die Extension fährt mit den verfügbaren Ressourcen fort.
ZIP ist leer oder sehr klein:
- Prüfe die Service Worker Console auf Fehler. Möglicherweise blockiert die Seite Script-Injection (strikte CSP-Header).
Extension-Icon nicht klickbar:
- Chrome Web Store und System-Seiten (
chrome://,chrome-extension://) blockieren Extensions.
MIT License
Copyright (c) 2025 Martin Pfeffer
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Martin Pfeffer - 2025
Beiträge, Issues und Feature-Requests sind willkommen! Bitte erstelle ein Issue oder einen Pull Request.
- ZIP-Archiv Download (HTML + separate Asset-Dateien)
- Background Service Worker für CORS-freie Fetches
- Paralleles Ressourcen-Laden mit 6-Worker Batch-Processing
- URL-Deduplizierung und Ressourcen-Caching
- Fortschrittsanzeige mit Live-Updates und Stage-Labels
- Neue Ressourcentypen:
srcset,<picture>,@import(rekursiv),<video poster>,<link rel="preload"> - Computed Background Images aus CSS-Regeln (nicht nur inline styles)
- 15s Timeout pro Ressource
- Robustere Fehlerbehandlung mit Fallback-Mechanismen
- ZIP-Asset-Pfad-Deduplizierung via
registerZipAsset() - Komplett überarbeitete UI mit Modus-Toggle
- Initiale Veröffentlichung
- Base64-Einbettung für alle Ressourcen (Single-HTML)
- Deutsche Lokalisierung
- Manifest V3 Implementierung
