refactor: implement minimal PWA caching strategy
- Cache only essential PWA assets (manifest, icons, core scripts) - Use Network First for all other requests - Remove aggressive caching of UI components and styles - Preserve PWA installation while minimizing cache footprint
This commit is contained in:
@@ -3,7 +3,6 @@ import { EnhancedSecureWebRTCManager } from '../network/EnhancedSecureWebRTCMana
|
||||
import { EnhancedSecureFileTransfer } from '../transfer/EnhancedSecureFileTransfer.js';
|
||||
|
||||
// Import UI components (side-effect: they attach themselves to window.*)
|
||||
import '../components/ui/SessionTimer.jsx';
|
||||
import '../components/ui/Header.jsx';
|
||||
import '../components/ui/DownloadApps.jsx';
|
||||
import '../components/ui/UniqueFeatureSlider.jsx';
|
||||
|
||||
9
src/scripts/bootstrap-modules.js
vendored
9
src/scripts/bootstrap-modules.js
vendored
@@ -3,10 +3,9 @@
|
||||
(async () => {
|
||||
try {
|
||||
const timestamp = Date.now();
|
||||
const [cryptoModule, webrtcModule, paymentModule, fileTransferModule] = await Promise.all([
|
||||
const [cryptoModule, webrtcModule, fileTransferModule] = await Promise.all([
|
||||
import(`../crypto/EnhancedSecureCryptoUtils.js?v=${timestamp}`),
|
||||
import(`../network/EnhancedSecureWebRTCManager.js?v=${timestamp}`),
|
||||
import(`../session/PayPerSessionManager.js?v=${timestamp}`),
|
||||
import(`../transfer/EnhancedSecureFileTransfer.js?v=${timestamp}`),
|
||||
]);
|
||||
|
||||
@@ -14,8 +13,6 @@
|
||||
window.EnhancedSecureCryptoUtils = EnhancedSecureCryptoUtils;
|
||||
const { EnhancedSecureWebRTCManager } = webrtcModule;
|
||||
window.EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager;
|
||||
const { PayPerSessionManager } = paymentModule;
|
||||
window.PayPerSessionManager = PayPerSessionManager;
|
||||
const { EnhancedSecureFileTransfer } = fileTransferModule;
|
||||
window.EnhancedSecureFileTransfer = EnhancedSecureFileTransfer;
|
||||
|
||||
@@ -28,11 +25,7 @@
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
loadReactComponent('../components/ui/SessionTimer.jsx'),
|
||||
loadReactComponent('../components/ui/Header.jsx'),
|
||||
loadReactComponent('../components/ui/SessionTypeSelector.jsx'),
|
||||
loadReactComponent('../components/ui/LightningPayment.jsx'),
|
||||
loadReactComponent('../components/ui/PaymentModal.jsx'),
|
||||
loadReactComponent('../components/ui/DownloadApps.jsx'),
|
||||
loadReactComponent('../components/ui/ComparisonTable.jsx'),
|
||||
loadReactComponent('../components/ui/UniqueFeatureSlider.jsx'),
|
||||
|
||||
@@ -1,27 +1,13 @@
|
||||
window.forceUpdateHeader = (timeLeft, sessionType) => {
|
||||
window.forceUpdateHeader = () => {
|
||||
const event = new CustomEvent('force-header-update', {
|
||||
detail: { timeLeft, sessionType, timestamp: Date.now() },
|
||||
detail: { timestamp: Date.now() },
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
if (window.sessionManager && window.sessionManager.forceUpdateTimer) {
|
||||
window.sessionManager.forceUpdateTimer();
|
||||
}
|
||||
};
|
||||
|
||||
window.updateSessionTimer = (timeLeft, sessionType) => {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent('session-timer-update', {
|
||||
detail: { timeLeft, sessionType },
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
document.addEventListener('session-activated', (event) => {
|
||||
if (window.updateSessionTimer) {
|
||||
window.updateSessionTimer(event.detail.timeLeft, event.detail.sessionType);
|
||||
}
|
||||
if (window.forceUpdateHeader) {
|
||||
window.forceUpdateHeader(event.detail.timeLeft, event.detail.sessionType);
|
||||
window.forceUpdateHeader();
|
||||
}
|
||||
if (window.webrtcManager && window.webrtcManager.handleSessionActivation) {
|
||||
if (window.DEBUG_MODE) {
|
||||
@@ -29,9 +15,6 @@ document.addEventListener('session-activated', (event) => {
|
||||
}
|
||||
window.webrtcManager.handleSessionActivation({
|
||||
sessionId: event.detail.sessionId,
|
||||
sessionType: event.detail.sessionType,
|
||||
timeLeft: event.detail.timeLeft,
|
||||
isDemo: event.detail.isDemo,
|
||||
sessionManager: window.sessionManager,
|
||||
});
|
||||
}
|
||||
|
||||
270
src/scripts/pwa-offline-test.js
Normal file
270
src/scripts/pwa-offline-test.js
Normal file
@@ -0,0 +1,270 @@
|
||||
// PWA Offline Test Script for SecureBit.chat
|
||||
// Enhanced Security Edition v4.3.120
|
||||
// Tests offline functionality and cache status
|
||||
|
||||
class PWAOfflineTester {
|
||||
constructor() {
|
||||
this.testResults = [];
|
||||
this.isRunning = false;
|
||||
}
|
||||
|
||||
async runTests() {
|
||||
if (this.isRunning) {
|
||||
console.warn('⚠️ Tests already running');
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRunning = true;
|
||||
this.testResults = [];
|
||||
|
||||
console.log('🧪 Starting PWA Offline Tests...');
|
||||
|
||||
try {
|
||||
await this.testServiceWorkerRegistration();
|
||||
await this.testCacheStatus();
|
||||
await this.testOfflineResources();
|
||||
await this.testOnlineResources();
|
||||
|
||||
this.showTestResults();
|
||||
} catch (error) {
|
||||
console.error('❌ Test failed:', error);
|
||||
this.addTestResult('Test Suite', false, `Test suite failed: ${error.message}`);
|
||||
} finally {
|
||||
this.isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
async testServiceWorkerRegistration() {
|
||||
try {
|
||||
if ('serviceWorker' in navigator) {
|
||||
const registration = await navigator.serviceWorker.getRegistration();
|
||||
if (registration) {
|
||||
this.addTestResult('Service Worker Registration', true, 'Service worker is registered');
|
||||
} else {
|
||||
this.addTestResult('Service Worker Registration', false, 'No service worker found');
|
||||
}
|
||||
} else {
|
||||
this.addTestResult('Service Worker Support', false, 'Service worker not supported');
|
||||
}
|
||||
} catch (error) {
|
||||
this.addTestResult('Service Worker Registration', false, `Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async testCacheStatus() {
|
||||
try {
|
||||
if ('caches' in window) {
|
||||
const cacheNames = await caches.keys();
|
||||
const totalCached = 0;
|
||||
|
||||
for (const cacheName of cacheNames) {
|
||||
const cache = await caches.open(cacheName);
|
||||
const keys = await cache.keys();
|
||||
totalCached += keys.length;
|
||||
}
|
||||
|
||||
if (totalCached > 0) {
|
||||
this.addTestResult('Cache Status', true, `${totalCached} resources cached`);
|
||||
} else {
|
||||
this.addTestResult('Cache Status', false, 'No resources cached');
|
||||
}
|
||||
} else {
|
||||
this.addTestResult('Cache API Support', false, 'Cache API not supported');
|
||||
}
|
||||
} catch (error) {
|
||||
this.addTestResult('Cache Status', false, `Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async testOfflineResources() {
|
||||
const criticalResources = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/manifest.json',
|
||||
'/dist/app.js',
|
||||
'/dist/app-boot.js',
|
||||
'/libs/react/react.production.min.js',
|
||||
'/libs/react-dom/react-dom.production.min.js',
|
||||
'/assets/tailwind.css'
|
||||
];
|
||||
|
||||
let cachedCount = 0;
|
||||
|
||||
for (const resource of criticalResources) {
|
||||
try {
|
||||
const cached = await caches.match(resource);
|
||||
if (cached) {
|
||||
cachedCount++;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Failed to check cache for ${resource}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
const success = cachedCount >= criticalResources.length * 0.8; // 80% success rate
|
||||
this.addTestResult('Critical Resources Cached', success,
|
||||
`${cachedCount}/${criticalResources.length} critical resources cached`);
|
||||
}
|
||||
|
||||
async testOnlineResources() {
|
||||
try {
|
||||
// Test if we can fetch a simple resource
|
||||
const response = await fetch('/favicon.ico', {
|
||||
method: 'HEAD',
|
||||
cache: 'no-cache'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
this.addTestResult('Network Connectivity', true, 'Network is accessible');
|
||||
} else {
|
||||
this.addTestResult('Network Connectivity', false, `Network error: ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
this.addTestResult('Network Connectivity', false, `Network error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
addTestResult(testName, passed, message) {
|
||||
this.testResults.push({
|
||||
name: testName,
|
||||
passed,
|
||||
message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
console.log(`${passed ? '✅' : '❌'} ${testName}: ${message}`);
|
||||
}
|
||||
|
||||
showTestResults() {
|
||||
const passedTests = this.testResults.filter(test => test.passed).length;
|
||||
const totalTests = this.testResults.length;
|
||||
const successRate = Math.round((passedTests / totalTests) * 100);
|
||||
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 backdrop-blur-sm';
|
||||
modal.innerHTML = `
|
||||
<div class="bg-gray-800 rounded-xl p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto">
|
||||
<div class="flex items-center mb-6">
|
||||
<div class="w-12 h-12 bg-blue-500/10 rounded-full flex items-center justify-center mr-4">
|
||||
<i class="fas fa-vial text-blue-400 text-xl"></i>
|
||||
</div>
|
||||
<h3 class="text-xl font-semibold text-white">PWA Offline Test Results</h3>
|
||||
</div>
|
||||
|
||||
<div class="mb-6 p-4 rounded-lg ${successRate >= 80 ? 'bg-green-500/10 border border-green-500/20' : 'bg-red-500/10 border border-red-500/20'}">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<div class="font-medium text-white">Overall Score</div>
|
||||
<div class="text-sm text-gray-300">${passedTests}/${totalTests} tests passed</div>
|
||||
</div>
|
||||
<div class="text-2xl font-bold ${successRate >= 80 ? 'text-green-400' : 'text-red-400'}">
|
||||
${successRate}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
${this.testResults.map(test => `
|
||||
<div class="flex items-center justify-between p-3 rounded-lg ${test.passed ? 'bg-green-500/10 border border-green-500/20' : 'bg-red-500/10 border border-red-500/20'}">
|
||||
<div class="flex items-center space-x-3">
|
||||
<i class="fas ${test.passed ? 'fa-check-circle text-green-400' : 'fa-times-circle text-red-400'}"></i>
|
||||
<div>
|
||||
<div class="font-medium text-white">${test.name}</div>
|
||||
<div class="text-sm text-gray-300">${test.message}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
|
||||
<div class="mt-6 space-y-3">
|
||||
<div class="bg-blue-500/10 border border-blue-500/20 rounded-lg p-4">
|
||||
<h4 class="font-medium text-blue-300 mb-2">Recommendations:</h4>
|
||||
<ul class="text-sm text-blue-200 space-y-1">
|
||||
${this.getRecommendations().map(rec => `<li>• ${rec}</li>`).join('')}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-3">
|
||||
<button onclick="window.pwaOfflineTester.runTests(); this.parentElement.parentElement.parentElement.remove();"
|
||||
class="flex-1 bg-blue-500 hover:bg-blue-600 text-white py-3 px-4 rounded-lg font-medium transition-colors">
|
||||
Run Tests Again
|
||||
</button>
|
||||
<button onclick="this.parentElement.parentElement.remove()"
|
||||
class="flex-1 bg-gray-600 hover:bg-gray-500 text-white py-3 px-4 rounded-lg font-medium transition-colors">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(modal);
|
||||
}
|
||||
|
||||
getRecommendations() {
|
||||
const recommendations = [];
|
||||
|
||||
const failedTests = this.testResults.filter(test => !test.passed);
|
||||
|
||||
if (failedTests.some(test => test.name.includes('Service Worker'))) {
|
||||
recommendations.push('Ensure service worker is properly registered and active');
|
||||
}
|
||||
|
||||
if (failedTests.some(test => test.name.includes('Cache'))) {
|
||||
recommendations.push('Check cache configuration and ensure resources are being cached');
|
||||
}
|
||||
|
||||
if (failedTests.some(test => test.name.includes('Network'))) {
|
||||
recommendations.push('Verify network connectivity and server availability');
|
||||
}
|
||||
|
||||
if (recommendations.length === 0) {
|
||||
recommendations.push('All tests passed! Your PWA offline functionality is working correctly.');
|
||||
}
|
||||
|
||||
return recommendations;
|
||||
}
|
||||
|
||||
// Public API
|
||||
getTestResults() {
|
||||
return this.testResults;
|
||||
}
|
||||
|
||||
clearResults() {
|
||||
this.testResults = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton pattern
|
||||
let instance = null;
|
||||
|
||||
const PWAOfflineTesterAPI = {
|
||||
getInstance() {
|
||||
if (!instance) {
|
||||
instance = new PWAOfflineTester();
|
||||
}
|
||||
return instance;
|
||||
},
|
||||
|
||||
runTests() {
|
||||
return this.getInstance().runTests();
|
||||
}
|
||||
};
|
||||
|
||||
// Export for module use
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = PWAOfflineTesterAPI;
|
||||
} else if (typeof window !== 'undefined' && !window.PWAOfflineTester) {
|
||||
window.PWAOfflineTester = PWAOfflineTesterAPI;
|
||||
}
|
||||
|
||||
// Auto-initialize
|
||||
if (typeof window !== 'undefined' && !window.pwaOfflineTester) {
|
||||
window.pwaOfflineTester = PWAOfflineTesterAPI.getInstance();
|
||||
|
||||
// Add global function for easy access
|
||||
window.testPWAOffline = () => {
|
||||
window.pwaOfflineTester.runTests();
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user