Skip to content

Commit a456e56

Browse files
committed
feat: Add Next.js/React offline error handling and improve package configuration
- Add comprehensive error boundary for React/Next.js applications in offline mode - Enhance .npmignore with additional Claude-related exclusions - Update README.md to mention Next.js/React error handling feature - Clean up package.json files array to remove non-existent IMPLEMENTATION.md
1 parent a223b49 commit a456e56

5 files changed

Lines changed: 140 additions & 4 deletions

File tree

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"Bash(timeout:*)",
88
"Bash(npm install)",
99
"Bash(npm install:*)",
10-
"Bash(grep:*)"
10+
"Bash(grep:*)",
11+
"Bash(npm pack:*)"
1112
],
1213
"additionalDirectories": [
1314
"D:\\d\\1A-Personal\\D-Learnings\\1-Projects"

.npmignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Development files
22
.claude/
3+
.claude
34
.git/
45
.gitignore
56
.env
@@ -8,6 +9,10 @@
89
# Development documentation
910
CLAUDE.local.md
1011
CLAUDE.md
12+
CLAUDE.*
13+
IMPLEMENTATION.md
14+
claude-*
15+
Claude-*
1116

1217
# Test outputs and temporary files
1318
test-output/
@@ -58,4 +63,4 @@ build/
5863

5964
# Temporary folders
6065
tmp/
61-
temp/
66+
temp/

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ A powerful, universal website mirroring tool that intelligently detects and pres
2929
- Optional tracking script removal (analytics, GTM, Facebook Pixel)
3030
- Professional project structure ready for development
3131
- Offline-ready websites with localized resources
32+
- **Next.js/React error handling** for graceful offline operation
3233

3334
## 🚀 Quick Start
3435

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@
8282
"files": [
8383
"src/",
8484
"README.md",
85-
"LICENSE",
86-
"IMPLEMENTATION.md"
85+
"LICENSE"
8786
],
8887
"preferGlobal": true,
8988
"os": [

src/core/framework-writer.js

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,133 @@ export class FrameworkWriter {
99
this.assetMappings = new Map(); // absolute URL (and alternates) -> local ./assets/... path
1010
}
1111

12+
/**
13+
* Adds error handling for Next.js/React applications in offline mode
14+
* @param {Object} $ - Cheerio DOM instance
15+
*/
16+
addOfflineErrorHandling($) {
17+
// Detect if this is a Next.js application
18+
const isNextJs = this.cloner.analysis?.primaryFramework?.key === 'nextjs' ||
19+
$('#__next').length > 0 ||
20+
$('script[src*="_next"]').length > 0;
21+
22+
const isReact = this.cloner.analysis?.primaryFramework?.key === 'react' ||
23+
$('#root').length > 0 ||
24+
$('script[src*="react"]').length > 0;
25+
26+
if (isNextJs || isReact) {
27+
// Add error boundary script for React/Next.js applications
28+
const errorBoundaryScript = `
29+
<script>
30+
(function() {
31+
// Global error handler for React/Next.js offline mode
32+
window.addEventListener('error', function(event) {
33+
console.warn('Mirror Web CLI: Handling offline error:', event.error?.message || event.message);
34+
35+
// Hide the default Next.js error overlay
36+
const errorOverlay = document.querySelector('[data-nextjs-dialog-overlay]');
37+
if (errorOverlay) {
38+
errorOverlay.style.display = 'none';
39+
}
40+
41+
// Check if the app root is empty and show a fallback
42+
const appRoot = document.querySelector('#__next, #root, [data-reactroot]');
43+
if (appRoot && (!appRoot.innerHTML || appRoot.innerHTML.trim() === '')) {
44+
appRoot.innerHTML = \`
45+
<div style="
46+
min-height: 100vh;
47+
display: flex;
48+
align-items: center;
49+
justify-content: center;
50+
flex-direction: column;
51+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
52+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
53+
color: white;
54+
text-align: center;
55+
padding: 2rem;
56+
">
57+
<div style="
58+
background: rgba(255,255,255,0.1);
59+
backdrop-filter: blur(10px);
60+
border-radius: 20px;
61+
padding: 3rem;
62+
max-width: 600px;
63+
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
64+
">
65+
<h1 style="margin: 0 0 1rem 0; font-size: 2.5rem; font-weight: 300;">
66+
🪞 Offline Mirror
67+
</h1>
68+
<p style="margin: 0 0 1.5rem 0; font-size: 1.2rem; opacity: 0.9;">
69+
This is an offline mirror of <strong>${this.cloner.url}</strong>
70+
</p>
71+
<p style="margin: 0; font-size: 1rem; opacity: 0.7;">
72+
Some interactive features may not work in offline mode.<br>
73+
This static mirror preserves the visual content and structure.
74+
</p>
75+
<div style="margin-top: 2rem; font-size: 0.9rem; opacity: 0.6;">
76+
Generated by Mirror Web CLI v1.0
77+
</div>
78+
</div>
79+
</div>
80+
\`;
81+
}
82+
83+
return true; // Prevent default error handling
84+
});
85+
86+
// Handle unhandled promise rejections
87+
window.addEventListener('unhandledrejection', function(event) {
88+
console.warn('Mirror Web CLI: Handling offline promise rejection:', event.reason);
89+
event.preventDefault(); // Prevent default handling
90+
});
91+
92+
// Override fetch for offline mode
93+
if (typeof window.fetch !== 'undefined') {
94+
const originalFetch = window.fetch;
95+
window.fetch = function(...args) {
96+
return originalFetch(...args).catch(error => {
97+
console.warn('Mirror Web CLI: Network request failed in offline mode:', args[0]);
98+
// Return a fake response to prevent crashes
99+
return new Response('Offline mode - network request blocked', {
100+
status: 200,
101+
statusText: 'OK',
102+
headers: { 'Content-Type': 'text/plain' }
103+
});
104+
});
105+
};
106+
}
107+
})();
108+
</script>`;
109+
110+
// Add the error handling script to the head
111+
$('head').append(errorBoundaryScript);
112+
113+
// Add a noscript fallback
114+
const noscriptFallback = `
115+
<noscript>
116+
<div style="
117+
min-height: 100vh;
118+
display: flex;
119+
align-items: center;
120+
justify-content: center;
121+
flex-direction: column;
122+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
123+
background: #f8fafc;
124+
color: #334155;
125+
text-align: center;
126+
padding: 2rem;
127+
">
128+
<h1>🪞 Offline Mirror</h1>
129+
<p>This is an offline mirror of <strong>${this.cloner.url}</strong></p>
130+
<p>JavaScript is required to view this React/Next.js application.</p>
131+
<p>Please enable JavaScript in your browser settings.</p>
132+
</div>
133+
</noscript>`;
134+
135+
$('body').prepend(noscriptFallback);
136+
}
137+
}
138+
12139
async generateOfflineProject() {
13140
await fs.ensureDir(this.cloner.options.outputDir);
14141

@@ -150,6 +277,9 @@ export class FrameworkWriter {
150277
$('head').append(
151278
`<meta name="mirrored-date" content="${new Date().toISOString()}">`,
152279
);
280+
281+
// Add Next.js/React error handling for offline mode
282+
this.addOfflineErrorHandling($);
153283

154284
// Stylesheets
155285
$('link[rel="stylesheet"], link[rel="preload"][as="style"]').each(

0 commit comments

Comments
 (0)