porting to vitepress
5
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
/node_modules
|
||||
pnpm-lock.yaml
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
node_modules
|
||||
172
docs/.vitepress/config.mjs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
import { defineConfig } from 'vitepress'
|
||||
|
||||
export default defineConfig({
|
||||
lang: 'en-US',
|
||||
title: 'Debrid Services Comparison',
|
||||
description: 'Community-maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools.',
|
||||
ignoreDeadLinks: true,
|
||||
cleanUrls: true,
|
||||
lastUpdated: true,
|
||||
|
||||
markdown: {
|
||||
lineNumbers: true
|
||||
},
|
||||
|
||||
head: [
|
||||
['link', { rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' }],
|
||||
['link', { rel: 'shortcut icon', href: '/favicon.ico' }],
|
||||
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/images/apple-touch-icon.png' }],
|
||||
['meta', { name: 'theme-color', content: '#ffffff', media: '(prefers-color-scheme: light)' }],
|
||||
['meta', { name: 'theme-color', content: '#0b0b0c', media: '(prefers-color-scheme: dark)' }],
|
||||
['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1.0, viewport-fit=cover' }],
|
||||
['meta', { name: 'author', content: 'Fynks' }],
|
||||
['meta', { name: 'robots', content: 'index, follow, max-image-preview:large, max-snippet:-1' }],
|
||||
['meta', { property: 'og:title', content: 'Debrid Services Comparison' }],
|
||||
['meta', { property: 'og:description', content: 'Community-maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools.' }],
|
||||
['meta', { property: 'og:type', content: 'website' }],
|
||||
['meta', { property: 'og:image', content: '/images/og.png' }],
|
||||
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
|
||||
['meta', { name: 'twitter:title', content: 'Debrid Services Comparison' }],
|
||||
['meta', { name: 'twitter:description', content: 'Community-maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools.' }],
|
||||
['meta', { name: 'twitter:image', content: '/images/og.png' }]
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
logo: {
|
||||
light: 'favicon.svg',
|
||||
dark: 'favicon.svg',
|
||||
alt: 'Debrid Services Comparison Logo'
|
||||
},
|
||||
|
||||
search: {
|
||||
provider: 'local',
|
||||
options: {
|
||||
detailedView: true
|
||||
}
|
||||
},
|
||||
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'Pricing', link: '/pricing' },
|
||||
{ text: 'Hosts', link: '/hosts' },
|
||||
{ text: 'Adult Hosts', link: '/Adult-hosts' },
|
||||
{ text: 'Policies', link: '/policies' },
|
||||
{ text: 'Tools', link: '/tools' },
|
||||
{
|
||||
text: 'More',
|
||||
items: [
|
||||
{ text: 'Interactive Comparison', link: 'https://debridcompare.pages.dev' },
|
||||
{ text: 'GitHub', link: 'https://github.com/fynks/debrid-services-comparison' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
sidebar: {
|
||||
'/': [
|
||||
{
|
||||
text: 'Getting Started',
|
||||
items: [
|
||||
{ text: 'What are Debrid Services?', link: '/#what-are-debrid-services' },
|
||||
{ text: 'Support This Project', link: '/#support-this-project' },
|
||||
{ text: 'Interactive Comparison', link: 'https://debridcompare.pages.dev' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Service Comparison',
|
||||
items: [
|
||||
{ text: 'Pricing Comparison', link: '/pricing' },
|
||||
{ text: 'Available Hosts', link: '/hosts' },
|
||||
{ text: 'Adult Hosts', link: '/Adult-hosts' },
|
||||
{ text: 'Policies & Legal', link: '/policies' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Tools & Resources',
|
||||
items: [
|
||||
{ text: 'Tools & Community', link: '/tools' },
|
||||
{ text: 'Speed Testing', link: '/tools#speed-test' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: 'Community',
|
||||
collapsed: true,
|
||||
items: [
|
||||
{ text: 'Contributing', link: 'https://github.com/fynks/debrid-services-comparison/blob/main/CONTRIBUTING.md' },
|
||||
{ text: 'Report Issues', link: 'https://github.com/fynks/debrid-services-comparison/issues' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/pricing': [
|
||||
{
|
||||
text: 'Pricing Information',
|
||||
items: [
|
||||
{ text: 'Overview', link: '/pricing' },
|
||||
{ text: 'Detailed Pricing Analysis', link: '/pricing#detailed-pricing-and-value-analysis' },
|
||||
{ text: 'Official Pricing Pages', link: '/pricing#up-to-date-pricing' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/hosts': [
|
||||
{
|
||||
text: 'File Hosting Services',
|
||||
items: [
|
||||
{ text: 'Complete Host List', link: '/hosts' },
|
||||
{ text: 'Interactive Comparison', link: 'https://debridcompare.pages.dev' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/Adult-hosts': [
|
||||
{
|
||||
text: 'Adult Content Hosts',
|
||||
items: [
|
||||
{ text: 'Supported Hosts', link: '/Adult-hosts' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/policies': [
|
||||
{
|
||||
text: 'Service Policies',
|
||||
items: [
|
||||
{ text: 'Policies & Legal', link: '/policies' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
'/tools': [
|
||||
{
|
||||
text: 'Tools & Community',
|
||||
items: [
|
||||
{ text: 'Recommended Tools', link: '/tools#recommended-tools' },
|
||||
{ text: 'Communities', link: '/tools#communities' },
|
||||
{ text: 'Speed Testing', link: '/tools#speed-test' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
footer: {
|
||||
message: 'Made with ❤️ by Fynks',
|
||||
copyright: 'Copyright © 2025 Debrid Services Comparison'
|
||||
},
|
||||
|
||||
outline: {
|
||||
level: [2, 3],
|
||||
label: 'On this page'
|
||||
},
|
||||
|
||||
lastUpdated: {
|
||||
text: 'Updated at',
|
||||
formatOptions: {
|
||||
dateStyle: 'short',
|
||||
timeStyle: 'medium'
|
||||
}
|
||||
},
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/fynks/debrid-services-comparison' }
|
||||
]
|
||||
}
|
||||
})
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
---
|
||||
layout: home
|
||||
title: Adult Hosts
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Detailed adult hoster support comparison for leading debrid/multi-hoster services."
|
||||
---
|
||||
|
||||
### Adult Hosts
|
||||
|
||||
6
docs/hosts.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
layout: home
|
||||
title: Hosts
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Comprehensive hoster support comparison for leading debrid/multi-hoster services including file and torrent hosters."
|
||||
---
|
||||
117
docs/index.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
---
|
||||
layout: home
|
||||
title: Best Debrid Compare
|
||||
description: "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc."
|
||||
head:
|
||||
- - meta
|
||||
- name: robots
|
||||
content: "index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
|
||||
- - meta
|
||||
- property: og:type
|
||||
content: "website"
|
||||
- - meta
|
||||
- property: og:url
|
||||
content: "https://debridcompare.pages.dev"
|
||||
- - meta
|
||||
- property: og:image
|
||||
content: "https://debridcompare.pages.dev/images/og.png"
|
||||
- - meta
|
||||
- property: og:title
|
||||
content: "Debrid Compare"
|
||||
- - meta
|
||||
- property: og:description
|
||||
content: "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc."
|
||||
- - meta
|
||||
- property: og:image:secure_url
|
||||
content: "https://debridcompare.pages.dev/images/og.png"
|
||||
- - meta
|
||||
- property: og:image:alt
|
||||
content: "Debrid Compare"
|
||||
- - meta
|
||||
- property: og:image:width
|
||||
content: "1200"
|
||||
- - meta
|
||||
- property: og:image:height
|
||||
content: "630"
|
||||
- - meta
|
||||
- property: og:image:type
|
||||
content: "image/png"
|
||||
- - meta
|
||||
- property: og:site_name
|
||||
content: "Debrid Compare"
|
||||
- - meta
|
||||
- property: og:locale
|
||||
content: "en_US"
|
||||
- - meta
|
||||
- property: og:updated_time
|
||||
content: "2025-09-19T00:00:00Z"
|
||||
- - link
|
||||
- rel: canonical
|
||||
href: "https://debridcompare.pages.dev"
|
||||
- - link
|
||||
- rel: alternate
|
||||
hreflang: "en"
|
||||
href: "https://debridcompare.pages.dev"
|
||||
hero:
|
||||
name: "Debrid Compare"
|
||||
tagline: "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc."
|
||||
image:
|
||||
src: /images/logo_dark.svg
|
||||
alt: Debrid Compare Logo
|
||||
actions:
|
||||
- theme: brand
|
||||
text: 🚀 Supported Hosts
|
||||
link: /hosts
|
||||
size: large
|
||||
- theme: alt
|
||||
text: 📚 Pricing
|
||||
link: /pricing
|
||||
- theme: alt
|
||||
text: ⭐ GitHub
|
||||
link: https://github.com/fynks/debrid-services-comparison
|
||||
target: _blank
|
||||
features:
|
||||
- icon: ⚡
|
||||
title: Performance & Gaming
|
||||
details: "Supercharge your device with performance optimization, gaming enhancements, CPU/GPU tuning, and intelligent automation."
|
||||
link: /android-root-apps/#performance-tweaks-and-optimizations
|
||||
|
||||
- icon: 🌐
|
||||
title: Network & Connectivity Control
|
||||
details: "Master network management with firewall tools, DNS control, Wi-Fi optimization, and advanced connectivity features."
|
||||
link: /android-root-apps/#network-and-connectivity
|
||||
|
||||
- icon: 🛠️
|
||||
title: Root Management & Hiding
|
||||
details: "Manage root access, hide root from banking apps, ensure integrity checks pass, and maintain system security."
|
||||
link: /android-root-apps/#root-management
|
||||
|
||||
---
|
||||
|
||||
<div class="support">
|
||||
|
||||
### Support This Project
|
||||
|
||||
> ✨ This guide is **free, open-source, and community-run**. If it helped: starring, reporting corrections, or using a referral link helps sustain maintenance (at no extra cost to you).
|
||||
|
||||
| Service | Referral | Direct Signup |
|
||||
| :------ | :------- | :------------ |
|
||||
| AllDebrid | [Referral](https://alldebrid.com/?uid=3wvya&lang=en) | [Signup](https://alldebrid.com/register/) |
|
||||
| Real-Debrid | [Referral](https://real-debrid.com/?id=10990901) | [Signup](https://real-debrid.com/) |
|
||||
| TorBox | – | [Signup](https://torbox.app/login) |
|
||||
| Premiumize | – | [Signup](https://www.premiumize.me/register) |
|
||||
| LinkSnappy | [Referral](https://linksnappy.com/?ref=774668) | [Signup](https://linksnappy.com/home#Register) |
|
||||
| Debrid-Link | [Referral](https://debrid-link.com/id/7B3BO) | [Signup](https://debrid-link.com/webapp/register) |
|
||||
| Mega-Debrid | – | [Signup](https://www.mega-debrid.eu/index.php?page=freeregister) |
|
||||
| Deepbrid | [Referral](https://www.deepbrid.com/aff/go/upward1971) | [Signup](https://www.deepbrid.com/signup) |
|
||||
| Offcloud | [Referral](https://offcloud.com/?=c44b1fa5) | [Signup](https://offcloud.com/register) |
|
||||
| High-Way | – | [Signup](https://high-way.me/login/login) |
|
||||
|
||||
> [!NOTE]
|
||||
> No financial ties to services. Referrals offset hosting & data validation costs only.
|
||||
|
||||
<div align="right">
|
||||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
6
docs/policies.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
layout: home
|
||||
title: Policies
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Refund, privacy, and usage policies for leading debrid/multi-hoster services."
|
||||
---
|
||||
62
docs/pricing.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
layout: home
|
||||
title: Pricing
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Comprehensive pricing comparison of leading debrid/multi-hoster services including plans, costs, and value analysis."
|
||||
---
|
||||
|
||||
<div class="pricing">
|
||||
|
||||
## Pricing Comparison
|
||||
|
||||
### Detailed Pricing and Value Analysis
|
||||
|
||||
| **Plan Duration** | **AllDebrid** | **Premiumize** | **Real-Debrid** | **TorBox** | **Debrid-Link** | **LinkSnappy** | **Mega-Debrid** | **Deepbrid** | **High-Way** | **Offcloud** |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| **Free / Trial** | 7-day trial¹ | ❌ | ❌ | Free tier² | ❌ | ❌ | ❌ | Limited hosts only | Limited Hosts⁶ | ❌ |
|
||||
| **7 Days** | ❌ | ❌ | ❌ | ❌ | ❌ | $4.99 | ❌ | ❌ | ❌ | ❌ |
|
||||
| **15 Days** | €2.99 (one-time)⁴ | ❌ | €3.00 | ❌ | €3.00 | ❌ | ❌ | €4.50 | ❌ | ❌ |
|
||||
| **30 Days** | €2.99 (recurring)³<br>€3.99 (one-time)⁴ | $11.99 | €4.00 | From $3.00/month⁵ | €4.00 | $12.99 | €4.00 | €4.99 | From €5.99 | $9.99 |
|
||||
| **90 Days** | €8.99 (one-time)⁴ | $29.99 | €9.00 | ❌ | €9.00 | $29.99 | €9.00 | €12.99 | From €15.99 | $29.97 |
|
||||
| **180 Days** | €15.99 (one-time)⁴ | ❌ | €16.00 | ❌ | €16.00 | $54.99 | €16.00 | €19.99 | From €29.99 | ❌ |
|
||||
| **300 Days** | €24.99 (one-time)⁴ | ❌ | ❌ | ❌ | €25.00 | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| **365 Days / 1 Year** | ❌ | $79.99 | ❌ | ❌ | ❌ | ❌ | ❌ | €32.99 | ❌ | $69.99 |
|
||||
|
||||
> [!NOTE] Pricing Notes
|
||||
> - **¹ AllDebrid Free Trial**: 7-day trial requires phone verification.
|
||||
> - **² TorBox Free Tier**: Limited speed and features; no torrenting.
|
||||
> - **³ AllDebrid Recurring**: Auto-renews monthly at €2.99
|
||||
> - **⁴ AllDebrid / Debrid-Link One-Time**: Non-recurring payment. Often better value than recurring.
|
||||
> - **⁵ TorBox Tiers**: Multiple plans starting at $3.00/month. Higher tiers unlock more features.
|
||||
> - **⁶ High-Way**: Limited Hoster, FreeMB through activity in the forum
|
||||
|
||||
### Up-to-date Pricing
|
||||
|
||||
> [!IMPORTANT]
|
||||
> *Always verify prices on official sites as they change frequently.*
|
||||
|
||||
<details><summary>👉 Click to expand</summary>
|
||||
|
||||
| **Service** | **Official Pricing Page** |
|
||||
| :---------- | :------------------------------------------------------------------------- |
|
||||
| AllDebrid | [alldebrid.com/offer](https://alldebrid.com/offer/) |
|
||||
| Real-Debrid | [real-debrid.com/premium](https://real-debrid.com/premium) |
|
||||
| TorBox | [torbox.app/pricing](https://torbox.app/pricing) |
|
||||
| Premiumize | [premiumize.me/premium](https://www.premiumize.me/premium) |
|
||||
| LinkSnappy | [linksnappy.com/myaccount/extend](https://linksnappy.com/myaccount/extend) |
|
||||
| Debrid-Link | [debrid-link.com/premium](https://debrid-link.com/premium) |
|
||||
| Mega-Debrid | [mega-debrid.eu/offres](https://www.mega-debrid.eu/index.php?page=offres) |
|
||||
| Deepbrid | [deepbrid.com/signup](https://www.deepbrid.com/signup) |
|
||||
| High-Way | [high-way.me/pages/tariffs](https://high-way.me/pages/tariffs) |
|
||||
| Offcloud | [https://offcloud.com/#pricing](https://offcloud.com/#pricing) |
|
||||
|
||||
</details><br>
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
<div align="right">
|
||||
|
||||
[(↑ Back to Top)](#table-of-contents)
|
||||
|
||||
</div></div>
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 410 B After Width: | Height: | Size: 410 B |
|
Before Width: | Height: | Size: 924 B After Width: | Height: | Size: 924 B |
|
Before Width: | Height: | Size: 321 KiB After Width: | Height: | Size: 321 KiB |
6
docs/tools.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
layout: home
|
||||
title: Tools
|
||||
titleTemplate: Debrid Compare
|
||||
description: "Tools and integrations for leading debrid/multi-hoster services including browser extensions, download managers, and media center plugins."
|
||||
---
|
||||
40
package.json
|
|
@ -1,24 +1,30 @@
|
|||
{
|
||||
"name": "@fynks/debrid-service-comparison",
|
||||
"version": "2.0.1",
|
||||
"description": "A concise comparison of pricing and supported hosts for popular debrid services including AllDebrid, Real-Debrid, LinkSnappy, Premiumize, Debrid-Link, TorBox, and Mega-Debrid.",
|
||||
"main": "index.js",
|
||||
"homepage": "",
|
||||
"name": "debrid-services-comparison",
|
||||
"version": "1.1.0",
|
||||
"description": "Community‑maintained, up-to-date comparison of leading debrid / multi-hoster services for pricing, host coverage, policies & tools etc.",
|
||||
"private": true,
|
||||
"homepage": "https://awesome-android-root.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
||||
"url": "https://github.com/fynks/debrid-services-comparison.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/fynks/debrid-services-comparison/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"minify:css": "cleancss -o dist/css/styles-min.css dist/css/styles.css",
|
||||
"minify:js": "terser dist/js/app.js -o dist/js/app-min.js --compress --mangle",
|
||||
"optimize-json": "chmod +x scripts/json-optimizer.sh && scripts/json-optimizer.sh dist/json/file-hosts.json dist/json/file-hosts-optimized.json && scripts/json-optimizer.sh dist/json/adult-hosts.json dist/json/adult-hosts-optimized.json",
|
||||
"build": "npm run minify:css && npm run minify:js && npm run optimize-json && workbox generateSW workbox-config.js",
|
||||
"postbuild": "node scripts/replace-assets.js"
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "scripts/build-docs.sh && vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
},
|
||||
"author": "fynks",
|
||||
"dependencies": {
|
||||
"clean-css-cli": "^5.6.3",
|
||||
"terser": "^5.44.0",
|
||||
"workbox-cli": "^7.3.0"
|
||||
}
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.6.4",
|
||||
"terser": "^5.44.0"
|
||||
},
|
||||
"keywords": [
|
||||
],
|
||||
"author": {
|
||||
"name": "debrid-services-comparison",
|
||||
"url": "https://debridcompare.pages.dev"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
147
scripts/build-docs.sh
Executable file
|
|
@ -0,0 +1,147 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Exit on any error and treat unset variables as errors
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
readonly GREEN='\033[0;32m'
|
||||
readonly NC='\033[0m' # No Color
|
||||
readonly RED='\033[0;31m'
|
||||
readonly BLUE='\033[0;34m'
|
||||
readonly YELLOW='\033[1;33m'
|
||||
|
||||
# Script info
|
||||
readonly SCRIPT_NAME="$(basename "$0")"
|
||||
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Error handling function with line number
|
||||
handle_error() {
|
||||
local line_number="${2:-unknown}"
|
||||
echo -e "${RED}Error on line ${line_number}: $1${NC}" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Trap errors and show line number
|
||||
trap 'handle_error "Script failed" ${LINENO}' ERR
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}⚠ $1${NC}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}✗ $1${NC}" >&2
|
||||
}
|
||||
|
||||
echo -e "${GREEN}Starting build-docs process...${NC}"
|
||||
|
||||
# 1. Check required files and directories
|
||||
[ ! -d "docs" ] && handle_error "'docs' directory not found."
|
||||
[ ! -f "README.md" ] && handle_error "'README.md' not found."
|
||||
|
||||
# 2. Function to extract div content with specific class from README.md
|
||||
extract_div_content() {
|
||||
local class_name="$1"
|
||||
local start_line end_line
|
||||
|
||||
# Find the start line of the div with the specified class
|
||||
start_line=$(grep -n "<div[^>]*class=\"${class_name}\"" README.md | head -1 | cut -d: -f1)
|
||||
|
||||
if [ -z "$start_line" ]; then
|
||||
log_warn "No div with class '${class_name}' found in README.md"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find the corresponding closing </div></div> after the start line
|
||||
end_line=$(tail -n +$((start_line + 1)) README.md | grep -n "</div></div>" | head -1 | cut -d: -f1)
|
||||
|
||||
if [ -z "$end_line" ]; then
|
||||
log_warn "No closing </div></div> found for class '${class_name}'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Calculate the actual end line number
|
||||
end_line=$((start_line + end_line))
|
||||
|
||||
# Extract the content between start and end lines
|
||||
sed -n "${start_line},${end_line}p" README.md
|
||||
}
|
||||
|
||||
# 3. Function to copy div content to docs file
|
||||
copy_div_to_docs() {
|
||||
local class_name="$1"
|
||||
local target_file="$2"
|
||||
local content
|
||||
|
||||
content=$(extract_div_content "$class_name")
|
||||
|
||||
if [ $? -eq 0 ] && [ -n "$content" ]; then
|
||||
if [ -f "$target_file" ]; then
|
||||
# Append to existing file with separator
|
||||
{
|
||||
cat "$target_file"
|
||||
echo ""
|
||||
echo "$content"
|
||||
} > "${target_file}.tmp" && mv "${target_file}.tmp" "$target_file" || handle_error "Failed appending content to $target_file"
|
||||
log_info "Appended '$class_name' div content to $target_file"
|
||||
else
|
||||
# Create new file with content
|
||||
echo "$content" > "$target_file" || handle_error "Failed creating $target_file"
|
||||
log_info "Created $target_file with '$class_name' div content"
|
||||
fi
|
||||
|
||||
# Adjust relative links for docs directory structure
|
||||
adjust_links_for_docs "$target_file"
|
||||
else
|
||||
log_warn "Failed to extract content for class '$class_name'"
|
||||
fi
|
||||
}
|
||||
|
||||
# 4. Function to adjust links for docs directory structure
|
||||
adjust_links_for_docs() {
|
||||
local file="$1"
|
||||
|
||||
# Adjust relative links (skip absolute URLs)
|
||||
sed -i '/http[s]*:\/\/\//! s|\.\/docs/|\.\/|g' "$file" || handle_error "Failed adjusting links in $file"
|
||||
|
||||
# Adjust image paths
|
||||
sed -i 's|docs/public/images/|public/images/|g' "$file" || handle_error "Failed adjusting image paths in $file"
|
||||
sed -i 's|\./dist/|public/images/|g' "$file" || handle_error "Failed adjusting dist image paths in $file"
|
||||
|
||||
log_info "Adjusted links and image paths in $file"
|
||||
}
|
||||
|
||||
# 5. Copy div sections to respective docs files
|
||||
copy_div_to_docs "support" "docs/index.md"
|
||||
copy_div_to_docs "pricing" "docs/pricing.md"
|
||||
copy_div_to_docs "hosts" "docs/hosts.md"
|
||||
copy_div_to_docs "policies" "docs/policies.md"
|
||||
copy_div_to_docs "tools" "docs/tools.md"
|
||||
|
||||
# 6. Append speedtest content to the bottom of tools.md
|
||||
speedtest_content=$(extract_div_content "speedtest")
|
||||
if [ $? -eq 0 ] && [ -n "$speedtest_content" ]; then
|
||||
{
|
||||
cat "docs/tools.md"
|
||||
echo ""
|
||||
echo "---"
|
||||
echo ""
|
||||
echo "$speedtest_content"
|
||||
} > "docs/tools.md.tmp" && mv "docs/tools.md.tmp" "docs/tools.md" || handle_error "Failed appending speedtest content to docs/tools.md"
|
||||
log_info "Appended speedtest content to bottom of docs/tools.md"
|
||||
adjust_links_for_docs "docs/tools.md"
|
||||
else
|
||||
log_warn "Failed to extract speedtest content"
|
||||
fi
|
||||
|
||||
# 7. Remove standalone speedtest.md file if it exists
|
||||
if [ -f "docs/speedtest.md" ]; then
|
||||
rm "docs/speedtest.md" || handle_error "Failed removing docs/speedtest.md"
|
||||
log_info "Removed standalone docs/speedtest.md file"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Documentation build process completed successfully.${NC}"
|
||||
|
|
@ -1,191 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# JSON Optimizer Script - Converts host data to indexed format
|
||||
# Usage: ./scripts/json-optimizer.sh file-hosts.json
|
||||
# ./scripts/json-optimizer.sh adult-hosts.json
|
||||
# ./scripts/json-optimizer.sh pricing.json
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Default values
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEFAULT_INPUT_DIR="."
|
||||
DEFAULT_OUTPUT_DIR="."
|
||||
|
||||
# Check if at least one argument is provided
|
||||
if [ $# -eq 0 ]; then
|
||||
print_error "No input file specified"
|
||||
echo "Usage: $0 <input-file.json> [output-file.json]"
|
||||
echo "Examples:"
|
||||
echo " $0 file-hosts.json"
|
||||
echo " $0 ./json/adult-hosts.json"
|
||||
echo " $0 pricing.json pricing-optimized.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get input file
|
||||
INPUT_FILE="$1"
|
||||
|
||||
# Generate output filename if not provided
|
||||
if [ $# -eq 2 ]; then
|
||||
OUTPUT_FILE="$2"
|
||||
else
|
||||
# Extract filename without path and extension
|
||||
FILENAME=$(basename "$INPUT_FILE")
|
||||
NAME="${FILENAME%.*}"
|
||||
EXT="${FILENAME##*.}"
|
||||
OUTPUT_FILE="${NAME}-optimized.${EXT}"
|
||||
fi
|
||||
|
||||
# Check if input file exists
|
||||
if [ ! -f "$INPUT_FILE" ]; then
|
||||
print_error "Input file '$INPUT_FILE' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create output directory if it doesn't exist
|
||||
OUTPUT_DIR=$(dirname "$OUTPUT_FILE")
|
||||
if [ ! -d "$OUTPUT_DIR" ] && [ "$OUTPUT_DIR" != "." ]; then
|
||||
print_status "Creating output directory: $OUTPUT_DIR"
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
fi
|
||||
|
||||
print_status "Processing: $INPUT_FILE"
|
||||
print_status "Output will be saved to: $OUTPUT_FILE"
|
||||
|
||||
# Python script to handle the conversion
|
||||
python3 -c "
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
from collections import defaultdict
|
||||
|
||||
def convert_to_indexed_format(input_file, output_file):
|
||||
try:
|
||||
# Read the input JSON
|
||||
print('Reading input file...')
|
||||
with open(input_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
host_count = len(data)
|
||||
print(f'Loaded {host_count:,} hosts')
|
||||
|
||||
# Handle empty data
|
||||
if not data:
|
||||
print('Warning: Input file is empty')
|
||||
output_data = {'services': [], 'supported': {}}
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(output_data, f, separators=(',', ':'))
|
||||
return True
|
||||
|
||||
# Extract all services (keys from entries)
|
||||
all_services = set()
|
||||
for host_data in data.values():
|
||||
all_services.update(host_data.keys())
|
||||
|
||||
services = sorted(list(all_services))
|
||||
service_count = len(services)
|
||||
print(f'Found {service_count} services: {\", \".join(services[:5])}{\"...\" if service_count > 5 else \"\"}')
|
||||
|
||||
# Create service to index mapping
|
||||
service_to_index = {service: idx for idx, service in enumerate(services)}
|
||||
|
||||
# Convert data to indexed format
|
||||
print('Converting data to indexed format...')
|
||||
supported = {}
|
||||
total_support_instances = 0
|
||||
|
||||
for host, host_data in data.items():
|
||||
# Get indices of services with 'yes' values (case insensitive)
|
||||
supported_indices = [
|
||||
service_to_index[service]
|
||||
for service, value in host_data.items()
|
||||
if str(value).lower() == 'yes'
|
||||
]
|
||||
supported[host] = sorted(supported_indices)
|
||||
total_support_instances += len(supported_indices)
|
||||
|
||||
# Create output structure
|
||||
output_data = {
|
||||
'services': services,
|
||||
'supported': supported
|
||||
}
|
||||
|
||||
# Write optimized JSON (compact format)
|
||||
print('Writing optimized JSON...')
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(output_data, f, separators=(',', ':'))
|
||||
|
||||
# Get file sizes for comparison
|
||||
original_size = os.path.getsize(input_file)
|
||||
new_size = os.path.getsize(output_file)
|
||||
reduction = ((original_size - new_size) / original_size) * 100 if original_size > 0 else 0
|
||||
|
||||
print('✅ Conversion successful!')
|
||||
print(f'📁 Original size: {original_size:,} bytes')
|
||||
print(f'📁 New size: {new_size:,} bytes')
|
||||
print(f'📉 Size reduction: {reduction:.1f}%')
|
||||
print(f'💾 Output saved to: {output_file}')
|
||||
|
||||
# Show statistics
|
||||
avg_support_per_host = total_support_instances / host_count if host_count > 0 else 0
|
||||
|
||||
print('📈 Statistics:')
|
||||
print(f' - Hosts: {host_count:,}')
|
||||
print(f' - Services: {service_count:,}')
|
||||
print(f' - Total support instances: {total_support_instances:,}')
|
||||
print(f' - Average support per host: {avg_support_per_host:.1f}')
|
||||
|
||||
return True
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
print(f'❌ JSON parsing error: {str(e)}')
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f'❌ Error during conversion: {str(e)}')
|
||||
return False
|
||||
|
||||
# Run the conversion
|
||||
success = convert_to_indexed_format('$INPUT_FILE', '$OUTPUT_FILE')
|
||||
|
||||
if not success:
|
||||
sys.exit(1)
|
||||
" || {
|
||||
print_error "Python conversion failed. Please ensure Python 3 is installed."
|
||||
exit 1
|
||||
}
|
||||
|
||||
print_success "Conversion completed successfully!"
|
||||
|
||||
# Optional: Show file size comparison in bash as well
|
||||
if command -v stat >/dev/null 2>&1; then
|
||||
ORIGINAL_SIZE=$(stat -f%z "$INPUT_FILE" 2>/dev/null || stat -c%s "$INPUT_FILE" 2>/dev/null)
|
||||
NEW_SIZE=$(stat -f%z "$OUTPUT_FILE" 2>/dev/null || stat -c%s "$OUTPUT_FILE" 2>/dev/null)
|
||||
|
||||
if [ $? -eq 0 ] && [ $ORIGINAL_SIZE -gt 0 ]; then
|
||||
REDUCTION_PERCENTAGE=$(( (ORIGINAL_SIZE - NEW_SIZE) * 100 / ORIGINAL_SIZE ))
|
||||
print_status "Final size reduction: ${REDUCTION_PERCENTAGE}%"
|
||||
fi
|
||||
fi
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Improved script with better error handling and focused head tag processing
|
||||
function replaceAssets() {
|
||||
const file = path.resolve(__dirname, '..', 'dist', 'index.html');
|
||||
|
||||
// Check if dist/index.html exists
|
||||
if (!fs.existsSync(file)) {
|
||||
console.error('Error: dist/index.html not found');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
let html = fs.readFileSync(file, 'utf8');
|
||||
console.log('Original HTML loaded successfully');
|
||||
|
||||
// Extract the head section
|
||||
const headMatch = html.match(/(<head[^>]*>)([\s\S]*?)(<\/head>)/i);
|
||||
if (!headMatch) {
|
||||
console.error('Error: Could not find <head> tag in HTML');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const [fullHeadTag, headStart, headContent, headEnd] = headMatch;
|
||||
console.log('Head section found, processing assets...');
|
||||
|
||||
let updatedHeadContent = headContent;
|
||||
let cssReplaced = 0;
|
||||
let jsReplaced = 0;
|
||||
|
||||
// Compute simple query hash for cache-busting if files exist
|
||||
const cssMinPath = path.resolve(__dirname, '..', 'dist', 'css', 'styles-min.css');
|
||||
const jsMinPath = path.resolve(__dirname, '..', 'dist', 'js', 'app-min.js');
|
||||
const safeHash = (p) => {
|
||||
try {
|
||||
const buf = fs.readFileSync(p);
|
||||
let hash = 0;
|
||||
for (let i = 0; i < buf.length; i += Math.ceil(buf.length / 128) || 1) {
|
||||
hash = (hash * 31 + buf[i]) >>> 0;
|
||||
}
|
||||
return hash.toString(36);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
const cssHash = safeHash(cssMinPath);
|
||||
const jsHash = safeHash(jsMinPath);
|
||||
const cssTarget = cssHash ? `href="./css/styles-min.css?v=${cssHash}"` : 'href="./css/styles-min.css"';
|
||||
const jsTarget = jsHash ? `src="js/app-min.js?v=${jsHash}"` : 'src="js/app-min.js"';
|
||||
|
||||
// Replace CSS links in head - more flexible patterns
|
||||
const cssPatterns = [
|
||||
/href=["']\.\/css\/styles\.css["']/g,
|
||||
/href=["']css\/styles\.css["']/g,
|
||||
/href=["'][^"']*\/styles\.css["']/g
|
||||
];
|
||||
|
||||
cssPatterns.forEach(pattern => {
|
||||
const matches = updatedHeadContent.match(pattern);
|
||||
if (matches) {
|
||||
updatedHeadContent = updatedHeadContent.replace(pattern, cssTarget);
|
||||
cssReplaced += matches.length;
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure existing preload to styles-min.css carries the same version hash
|
||||
if (cssHash) {
|
||||
const preloadMinCssPattern = /href=["']\/?css\/styles-min\.css["']/g;
|
||||
if (preloadMinCssPattern.test(updatedHeadContent)) {
|
||||
updatedHeadContent = updatedHeadContent.replace(preloadMinCssPattern, `href="/css/styles-min.css?v=${cssHash}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace JS script src in head - more flexible patterns
|
||||
const jsPatterns = [
|
||||
/src=["']\.\/js\/app\.js["']/g,
|
||||
/src=["']js\/app\.js["']/g,
|
||||
/src=["'][^"']*\/app\.js["']/g
|
||||
];
|
||||
|
||||
jsPatterns.forEach(pattern => {
|
||||
const matches = updatedHeadContent.match(pattern);
|
||||
if (matches) {
|
||||
updatedHeadContent = updatedHeadContent.replace(pattern, jsTarget);
|
||||
jsReplaced += matches.length;
|
||||
}
|
||||
});
|
||||
|
||||
// Also check for script tags at the end of body (common pattern)
|
||||
const bodyMatch = html.match(/(<body[^>]*>)([\s\S]*?)(<\/body>)/i);
|
||||
if (bodyMatch) {
|
||||
const [fullBodyTag, bodyStart, bodyContent, bodyEnd] = bodyMatch;
|
||||
let updatedBodyContent = bodyContent;
|
||||
|
||||
jsPatterns.forEach(pattern => {
|
||||
const matches = updatedBodyContent.match(pattern);
|
||||
if (matches) {
|
||||
updatedBodyContent = updatedBodyContent.replace(pattern, jsTarget);
|
||||
jsReplaced += matches.length;
|
||||
}
|
||||
});
|
||||
|
||||
// Reconstruct the body if changes were made
|
||||
if (updatedBodyContent !== bodyContent) {
|
||||
html = html.replace(fullBodyTag, bodyStart + updatedBodyContent + bodyEnd);
|
||||
}
|
||||
}
|
||||
|
||||
// Reconstruct the HTML with updated head
|
||||
const updatedHeadTag = headStart + updatedHeadContent + headEnd;
|
||||
html = html.replace(fullHeadTag, updatedHeadTag);
|
||||
|
||||
// Log results
|
||||
console.log(`CSS replacements made: ${cssReplaced}`);
|
||||
console.log(`JS replacements made: ${jsReplaced}`);
|
||||
|
||||
if (cssReplaced === 0 && jsReplaced === 0) {
|
||||
console.warn('Warning: No asset links were found to replace');
|
||||
console.log('Checking for existing patterns in head section:');
|
||||
|
||||
// Debug: show what's actually in the head
|
||||
const linkTags = headContent.match(/<link[^>]*>/gi) || [];
|
||||
const scriptTags = headContent.match(/<script[^>]*>/gi) || [];
|
||||
|
||||
console.log('Found link tags:', linkTags);
|
||||
console.log('Found script tags:', scriptTags);
|
||||
} else {
|
||||
console.log('Asset links replaced successfully');
|
||||
}
|
||||
|
||||
// Write the updated HTML back
|
||||
fs.writeFileSync(file, html, 'utf8');
|
||||
console.log('Updated dist/index.html saved');
|
||||
|
||||
// Verify the minified files exist
|
||||
const cssFile = path.resolve(__dirname, '..', 'dist', 'css', 'styles-min.css');
|
||||
const jsFile = path.resolve(__dirname, '..', 'dist', 'js', 'app-min.js');
|
||||
|
||||
if (!fs.existsSync(cssFile)) {
|
||||
console.warn('Warning: styles-min.css not found - CSS minification may have failed');
|
||||
} else {
|
||||
console.log('✓ styles-min.css exists');
|
||||
}
|
||||
|
||||
if (!fs.existsSync(jsFile)) {
|
||||
console.warn('Warning: app-min.js not found - JS minification may have failed');
|
||||
} else {
|
||||
console.log('✓ app-min.js exists');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error processing HTML file:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
replaceAssets();
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
module.exports = {
|
||||
// Base directory - still needed for SW generation
|
||||
globDirectory: "dist/",
|
||||
// Explicitly disable precaching for lean SW install
|
||||
globPatterns: [],
|
||||
|
||||
// Enhanced runtime caching strategies
|
||||
runtimeCaching: [
|
||||
// 1. Navigation routes (for SPAs) - Network first with offline fallback
|
||||
{
|
||||
urlPattern: ({ request }) => request.mode === 'navigate',
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'navigation-cache',
|
||||
networkTimeoutSeconds: 3, // Fallback to cache after 3s
|
||||
expiration: {
|
||||
maxEntries: 50,
|
||||
maxAgeSeconds: 24 * 60 * 60 // 24 hours
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200] // Cache successful responses
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 2. HTML pages - Network first for fresh content
|
||||
{
|
||||
urlPattern: /\.html$/i,
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'html-cache',
|
||||
networkTimeoutSeconds: 2,
|
||||
expiration: {
|
||||
maxEntries: 50,
|
||||
maxAgeSeconds: 12 * 60 * 60 // 12 hours
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 3. JS/CSS - StaleWhileRevalidate with versioning awareness
|
||||
{
|
||||
urlPattern: /\.(?:js|css)$/i,
|
||||
handler: 'StaleWhileRevalidate',
|
||||
options: {
|
||||
cacheName: 'static-resources',
|
||||
expiration: {
|
||||
maxEntries: 60,
|
||||
maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
|
||||
purgeOnQuotaError: true // Auto-cleanup when storage is full
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 4. Images - CacheFirst for performance
|
||||
{
|
||||
urlPattern: /\.(?:png|jpg|jpeg|gif|webp|svg|ico)$/i,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'image-cache',
|
||||
expiration: {
|
||||
maxEntries: 200, // More space for images
|
||||
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
|
||||
purgeOnQuotaError: true
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200]
|
||||
},
|
||||
plugins: [
|
||||
{
|
||||
handlerDidError: async () => {
|
||||
// Return fallback image on error (use an existing icon)
|
||||
return caches.match('/favicon.svg');
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// 5. JSON responses (local and API) - NetworkFirst with timeout
|
||||
{
|
||||
urlPattern: ({url}) => /\.json$/i.test(url.pathname) || /\/api\//i.test(url.pathname) || /^https:\/\/api\./i.test(url.href),
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheName: 'api-cache',
|
||||
networkTimeoutSeconds: 5,
|
||||
expiration: {
|
||||
maxEntries: 100,
|
||||
maxAgeSeconds: 5 * 60 // 5 minutes for fresh API data
|
||||
},
|
||||
cacheableResponse: { statuses: [0, 200] },
|
||||
matchOptions: {
|
||||
ignoreSearch: false // Consider query params
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 8. Google Fonts - CacheFirst
|
||||
{
|
||||
urlPattern: /^https:\/\/fonts\.(?:googleapis|gstatic)\.com/,
|
||||
handler: 'CacheFirst',
|
||||
options: {
|
||||
cacheName: 'google-fonts',
|
||||
expiration: {
|
||||
maxEntries: 30,
|
||||
maxAgeSeconds: 365 * 24 * 60 * 60 // 1 year
|
||||
},
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
// Service worker output
|
||||
swDest: "dist/sw.js",
|
||||
|
||||
// Disable sourcemaps in production
|
||||
sourcemap: false,
|
||||
|
||||
// Immediate activation
|
||||
skipWaiting: true,
|
||||
clientsClaim: true,
|
||||
|
||||
// Additional improvements
|
||||
cleanupOutdatedCaches: true, // Remove old caches automatically
|
||||
navigateFallback: null, // No fallback since no precaching
|
||||
|
||||
// Ignore specific query parameters
|
||||
ignoreURLParametersMatching: [
|
||||
/^utm_/, // Marketing params
|
||||
/^fbclid$/ // Facebook click ID
|
||||
],
|
||||
|
||||
// Maximum file size to cache (15MB)
|
||||
maximumFileSizeToCacheInBytes: 15 * 1024 * 1024,
|
||||
|
||||
// Mode for generated SW
|
||||
mode: 'production'
|
||||
};
|
||||