Fix: Blazor Server loading screen now works correctly
Problem: - Loading screen was getting stuck and not hiding properly - Conflicting logic between pwa.js and inline scripts - Blazor Server lifecycle not properly integrated with loading screen Solution (Meziantou-inspired approach for Blazor Server): 1. **blazor-integration.js** - Now manages loading screen lifecycle: - Shows loading screen only on first load (sessionStorage check) - Hides screen when Blazor.start() promise resolves (SignalR connected) - Added reconnection UI for Blazor Server disconnections - Proper error handling if Blazor fails to start 2. **_Layout.cshtml** - Simplified loading screen management: - Removed inline script that was conflicting - Moved blazor-integration.js before pwa.js (load order critical) - Loading screen now controlled by Blazor lifecycle 3. **pwa.js** - Removed conflicting logic: - Removed hideLoadingScreen() method - Removed 5-second fallback timeout - PWA initialization no longer interferes with Blazor loading Key Differences from WebAssembly Approach: - WASM: Downloads .NET runtime + shows download progress - Server: Establishes SignalR connection + shows spinner - Loading screen hides when SignalR connection is ready 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
dd494603f5
commit
db2443c7ac
@ -40,7 +40,7 @@
|
|||||||
@await RenderSectionAsync("Head", required: false)
|
@await RenderSectionAsync("Head", required: false)
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- PWA Loading Screen - Only on first load -->
|
<!-- PWA Loading Screen - Managed by blazor-integration.js -->
|
||||||
<div id="pwa-loading-screen" class="pwa-loading-screen" style="display: none;">
|
<div id="pwa-loading-screen" class="pwa-loading-screen" style="display: none;">
|
||||||
<div class="pwa-loading-content">
|
<div class="pwa-loading-content">
|
||||||
<div class="pwa-loading-logo">
|
<div class="pwa-loading-logo">
|
||||||
@ -56,21 +56,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
// Show loading screen only on initial app load, not on navigation
|
|
||||||
(function() {
|
|
||||||
const isFirstLoad = !sessionStorage.getItem('appLoaded');
|
|
||||||
|
|
||||||
if (isFirstLoad) {
|
|
||||||
const loadingScreen = document.getElementById('pwa-loading-screen');
|
|
||||||
if (loadingScreen) {
|
|
||||||
loadingScreen.style.display = 'flex';
|
|
||||||
}
|
|
||||||
sessionStorage.setItem('appLoaded', 'true');
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<nav class="navbar navbar-expand-sm navbar-light bg-white">
|
<nav class="navbar navbar-expand-sm navbar-light bg-white">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
@ -170,10 +155,11 @@
|
|||||||
<script src="/lib/bootstrap/js/bootstrap.bundle.min.js"></script>
|
<script src="/lib/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/_framework/blazor.server.js" autostart="false"></script>
|
<script src="/_framework/blazor.server.js" autostart="false"></script>
|
||||||
<script src="/_content/Radzen.Blazor/Radzen.Blazor.js"></script>
|
<script src="/_content/Radzen.Blazor/Radzen.Blazor.js"></script>
|
||||||
|
<!-- Blazor integration MUST load before PWA to control loading screen -->
|
||||||
|
<script src="/js/blazor-integration.js"></script>
|
||||||
<script src="/js/pwa.js"></script>
|
<script src="/js/pwa.js"></script>
|
||||||
<script src="/js/notifications.js"></script>
|
<script src="/js/notifications.js"></script>
|
||||||
<script src="/js/modern-mobile.js"></script>
|
<script src="/js/modern-mobile.js"></script>
|
||||||
<script src="/js/blazor-integration.js"></script>
|
|
||||||
@await RenderSectionAsync("Scripts", required: false)
|
@await RenderSectionAsync("Scripts", required: false)
|
||||||
<!-- Mobile Bottom Navigation -->
|
<!-- Mobile Bottom Navigation -->
|
||||||
<nav class="mobile-bottom-nav">
|
<nav class="mobile-bottom-nav">
|
||||||
|
|||||||
@ -1,15 +1,109 @@
|
|||||||
// Blazor Server Integration Script
|
// Blazor Server Integration Script
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', async function() {
|
||||||
|
console.log('Blazor: DOM Content Loaded');
|
||||||
|
|
||||||
|
// Show loading screen initially (only on first load)
|
||||||
|
const isFirstLoad = !sessionStorage.getItem('blazorLoaded');
|
||||||
|
const loadingScreen = document.getElementById('pwa-loading-screen');
|
||||||
|
|
||||||
|
if (isFirstLoad && loadingScreen) {
|
||||||
|
loadingScreen.style.display = 'flex';
|
||||||
|
console.log('Blazor: Showing loading screen for first load');
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we're on a page that should use Blazor
|
// Check if we're on a page that should use Blazor
|
||||||
const blazorContainers = document.querySelectorAll('[data-blazor-component]');
|
const blazorContainers = document.querySelectorAll('[data-blazor-component]');
|
||||||
|
|
||||||
if (blazorContainers.length > 0 || window.location.pathname.includes('/Admin/Products/Blazor')) {
|
if (blazorContainers.length > 0 || window.location.pathname.includes('/Admin/Products/Blazor') || window.location.pathname.includes('/blazor')) {
|
||||||
// Start Blazor
|
try {
|
||||||
Blazor.start();
|
console.log('Blazor: Starting Blazor Server...');
|
||||||
|
|
||||||
|
// Start Blazor Server with reconnection UI
|
||||||
|
await Blazor.start({
|
||||||
|
reconnectionOptions: {
|
||||||
|
maxRetries: 8,
|
||||||
|
retryIntervalMilliseconds: 2000
|
||||||
|
},
|
||||||
|
reconnectionHandler: {
|
||||||
|
onConnectionDown: () => {
|
||||||
|
console.log('Blazor: Connection lost, attempting to reconnect...');
|
||||||
|
showReconnectingUI();
|
||||||
|
},
|
||||||
|
onConnectionUp: () => {
|
||||||
|
console.log('Blazor: Reconnected successfully');
|
||||||
|
hideReconnectingUI();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('Blazor: Started successfully');
|
||||||
|
|
||||||
|
// Mark as loaded and hide loading screen
|
||||||
|
sessionStorage.setItem('blazorLoaded', 'true');
|
||||||
|
hideLoadingScreen();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Blazor: Failed to start:', error);
|
||||||
|
hideLoadingScreen();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not a Blazor page, hide loading screen immediately
|
||||||
|
hideLoadingScreen();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Loading screen management
|
||||||
|
function hideLoadingScreen() {
|
||||||
|
const loadingScreen = document.getElementById('pwa-loading-screen');
|
||||||
|
if (loadingScreen && loadingScreen.style.display !== 'none') {
|
||||||
|
console.log('Blazor: Hiding loading screen');
|
||||||
|
loadingScreen.classList.add('fade-out');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
loadingScreen.style.display = 'none';
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconnection UI for Blazor Server
|
||||||
|
function showReconnectingUI() {
|
||||||
|
let reconnectUI = document.getElementById('blazor-reconnect-ui');
|
||||||
|
|
||||||
|
if (!reconnectUI) {
|
||||||
|
reconnectUI = document.createElement('div');
|
||||||
|
reconnectUI.id = 'blazor-reconnect-ui';
|
||||||
|
reconnectUI.className = 'alert alert-warning';
|
||||||
|
reconnectUI.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 9999;
|
||||||
|
min-width: 300px;
|
||||||
|
text-align: center;
|
||||||
|
`;
|
||||||
|
reconnectUI.innerHTML = `
|
||||||
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
||||||
|
<strong>Connection lost</strong><br>
|
||||||
|
<small>Attempting to reconnect...</small>
|
||||||
|
`;
|
||||||
|
document.body.appendChild(reconnectUI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideReconnectingUI() {
|
||||||
|
const reconnectUI = document.getElementById('blazor-reconnect-ui');
|
||||||
|
if (reconnectUI) {
|
||||||
|
reconnectUI.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to navigate to Blazor components from MVC
|
// Helper function to navigate to Blazor components from MVC
|
||||||
window.navigateToBlazor = function(componentPath) {
|
window.navigateToBlazor = function(componentPath) {
|
||||||
window.location.href = '/blazor#' + componentPath;
|
window.location.href = '/blazor#' + componentPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Export functions for use by other scripts
|
||||||
|
window.hideBlazorLoadingScreen = hideLoadingScreen;
|
||||||
|
window.showBlazorReconnectingUI = showReconnectingUI;
|
||||||
|
window.hideBlazorReconnectingUI = hideReconnectingUI;
|
||||||
@ -39,22 +39,9 @@ class PWAManager {
|
|||||||
// Setup push notifications
|
// Setup push notifications
|
||||||
this.setupPushNotifications();
|
this.setupPushNotifications();
|
||||||
|
|
||||||
// Hide loading screen after initialization
|
// Loading screen is now managed by blazor-integration.js
|
||||||
this.hideLoadingScreen();
|
// Don't interfere with Blazor Server's loading lifecycle
|
||||||
}
|
console.log('PWA: Initialization complete (loading screen managed by Blazor)');
|
||||||
|
|
||||||
hideLoadingScreen() {
|
|
||||||
const loadingScreen = document.getElementById('pwa-loading-screen');
|
|
||||||
if (loadingScreen && loadingScreen.style.display !== 'none') {
|
|
||||||
// Add fade-out class
|
|
||||||
loadingScreen.classList.add('fade-out');
|
|
||||||
|
|
||||||
// Hide after animation completes (don't remove from DOM to avoid layout issues)
|
|
||||||
setTimeout(() => {
|
|
||||||
loadingScreen.style.display = 'none';
|
|
||||||
console.log('PWA: Loading screen hidden');
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupInstallPrompt() {
|
setupInstallPrompt() {
|
||||||
@ -701,15 +688,5 @@ window.addEventListener('load', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fallback: Ensure loading screen is hidden after maximum timeout
|
// Loading screen fallback timeout removed - now managed by blazor-integration.js
|
||||||
// This guarantees the loading screen won't stay visible indefinitely
|
// Blazor Server controls loading screen lifecycle based on SignalR connection state
|
||||||
setTimeout(() => {
|
|
||||||
const loadingScreen = document.getElementById('pwa-loading-screen');
|
|
||||||
if (loadingScreen && loadingScreen.style.display !== 'none') {
|
|
||||||
console.log('PWA: Hiding loading screen via fallback timeout');
|
|
||||||
loadingScreen.classList.add('fade-out');
|
|
||||||
setTimeout(() => {
|
|
||||||
loadingScreen.style.display = 'none';
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
}, 5000); // 5 second maximum
|
|
||||||
Loading…
Reference in New Issue
Block a user