@@ -104,4 +104,128 @@ export class ErrorBoundary extends Component<Props, State> {
104
104
105
105
private handleAutoRetry = ( ) => {
106
106
this . resetTimeoutId = window . setTimeout ( ( ) => {
107
- console . log ( '[ErrorBoundary] Auto-retrying after error...' ) ; \n this . handleRetry ( ) ; \n } , 5000 ) ; \n } ; \n\n private renderDefaultFallback ( ) { \n const { error, errorInfo } = this . state ; \n const isModuleFederationError = error ?. message ?. includes ( 'Loading' ) || \n error ?. message ?. includes ( 'remote' ) || \n error ?. name === 'ChunkLoadError' ; \n\n return ( \n < div style = { { \n padding : '20px' , \n margin : '20px' , \n border : '2px solid #ff6b6b' , \n borderRadius : '8px' , \n backgroundColor : '#ffe0e0' , \n color : '#d63031' \n } } > \n < h2 style = { { margin : '0 0 16px 0' , fontSize : '18px' } } > \n { isModuleFederationError ? \n '🔌 Remote Module Loading Error' : \n '⚠️ Something went wrong' \n } \n </ h2 > \n \n < p style = { { margin : '0 0 16px 0' , fontSize : '14px' } } > \n { isModuleFederationError ? ( \n < > This usually happens when a remote module is unavailable or the URL is incorrect.</ > \n ) : ( \n < > An unexpected error occurred while rendering this component.</ > \n ) } \n </ p > \n \n < div style = { { marginBottom : '16px' } } > \n < button \n onClick = { this . handleRetry } \n style = { { \n padding : '8px 16px' , \n marginRight : '8px' , \n backgroundColor : '#0984e3' , \n color : 'white' , \n border : 'none' , \n borderRadius : '4px' , \n cursor : 'pointer' \n } } \n > \n 🔄 Retry\n </ button > \n \n { isModuleFederationError && ( \n < button \n onClick = { this . handleAutoRetry } \n style = { { \n padding : '8px 16px' , \n backgroundColor : '#fdcb6e' , \n color : '#2d3436' , \n border : 'none' , \n borderRadius : '4px' , \n cursor : 'pointer' \n } } \n > \n ⏰ Auto-retry in 5s\n </ button > \n ) } \n </ div > \n \n { process . env . NODE_ENV === 'development' && ( \n < details style = { { fontSize : '12px' , marginTop : '16px' } } > \n < summary style = { { cursor : 'pointer' , fontWeight : 'bold' } } > \n 🐛 Debug Information\n </ summary > \n < pre style = { { \n marginTop : '8px' , \n padding : '8px' , \n backgroundColor : '#f8f9fa' , \n border : '1px solid #dee2e6' , \n borderRadius : '4px' , \n overflow : 'auto' , \n fontSize : '11px' \n } } > \n < strong > Error:</ strong > { error ?. toString ( ) } \n { errorInfo ?. componentStack && ( \n < > \n { '\n\n' } < strong > Component Stack:</ strong > { errorInfo . componentStack } \n </ > \n ) } \n </ pre > \n </ details > \n ) } \n </ div > \n ) ; \n } \n\n render ( ) { \n if ( this . state . hasError ) { \n // Render custom fallback UI or default\n return this.props.fallback || this.renderDefaultFallback();\n }\n\n return this.props.children;\n }\n }\n\n/**\n * Hook version of Error Boundary for functional components\n * Note: This is a wrapper that uses the class-based ErrorBoundary\n */\nexport function withErrorBoundary<P extends object>(\n Component: React.ComponentType<P>,\n errorBoundaryProps?: Omit<Props, 'children'>\n) {\n const WrappedComponent = (props: P) => (\n <ErrorBoundary {...errorBoundaryProps}>\n <Component {...props} />\n </ErrorBoundary>\n );\n \n WrappedComponent.displayName = `withErrorBoundary(${Component.displayName || Component.name})`;\n \n return WrappedComponent;\n}\n\nexport default ErrorBoundary;
107
+ console . log ( '[ErrorBoundary] Auto-retrying after error...' ) ;
108
+ this . handleRetry ( ) ;
109
+ } , 5000 ) ;
110
+ } ;
111
+
112
+ private renderDefaultFallback ( ) {
113
+ const { error, errorInfo } = this . state ;
114
+ const isModuleFederationError = error ?. message ?. includes ( 'Loading' ) ||
115
+ error ?. message ?. includes ( 'remote' ) ||
116
+ error ?. name === 'ChunkLoadError' ;
117
+
118
+ return (
119
+ < div style = { {
120
+ padding : '20px' ,
121
+ margin : '20px' ,
122
+ border : '2px solid #ff6b6b' ,
123
+ borderRadius : '8px' ,
124
+ backgroundColor : '#ffe0e0' ,
125
+ color : '#d63031'
126
+ } } >
127
+ < h2 style = { { margin : '0 0 16px 0' , fontSize : '18px' } } >
128
+ { isModuleFederationError ?
129
+ '🔌 Remote Module Loading Error' :
130
+ '⚠️ Something went wrong'
131
+ }
132
+ </ h2 >
133
+
134
+ < p style = { { margin : '0 0 16px 0' , fontSize : '14px' } } >
135
+ { isModuleFederationError ? (
136
+ < > This usually happens when a remote module is unavailable or the URL is incorrect.</ >
137
+ ) : (
138
+ < > An unexpected error occurred while rendering this component.</ >
139
+ ) }
140
+ </ p >
141
+
142
+ < div style = { { marginBottom : '16px' } } >
143
+ < button
144
+ onClick = { this . handleRetry }
145
+ style = { {
146
+ padding : '8px 16px' ,
147
+ marginRight : '8px' ,
148
+ backgroundColor : '#0984e3' ,
149
+ color : 'white' ,
150
+ border : 'none' ,
151
+ borderRadius : '4px' ,
152
+ cursor : 'pointer'
153
+ } }
154
+ >
155
+ 🔄 Retry
156
+ </ button >
157
+
158
+ { isModuleFederationError && (
159
+ < button
160
+ onClick = { this . handleAutoRetry }
161
+ style = { {
162
+ padding : '8px 16px' ,
163
+ backgroundColor : '#fdcb6e' ,
164
+ color : '#2d3436' ,
165
+ border : 'none' ,
166
+ borderRadius : '4px' ,
167
+ cursor : 'pointer'
168
+ } }
169
+ >
170
+ ⏰ Auto-retry in 5s
171
+ </ button >
172
+ ) }
173
+ </ div >
174
+
175
+ { process . env . NODE_ENV === 'development' && (
176
+ < details style = { { fontSize : '12px' , marginTop : '16px' } } >
177
+ < summary style = { { cursor : 'pointer' , fontWeight : 'bold' } } >
178
+ 🐛 Debug Information
179
+ </ summary >
180
+ < pre style = { {
181
+ marginTop : '8px' ,
182
+ padding : '8px' ,
183
+ backgroundColor : '#f8f9fa' ,
184
+ border : '1px solid #dee2e6' ,
185
+ borderRadius : '4px' ,
186
+ overflow : 'auto' ,
187
+ fontSize : '11px'
188
+ } } >
189
+ < strong > Error:</ strong > { error ?. toString ( ) }
190
+ { errorInfo ?. componentStack && (
191
+ < >
192
+ { '\n\n' } < strong > Component Stack:</ strong > { errorInfo . componentStack }
193
+ </ >
194
+ ) }
195
+ </ pre >
196
+ </ details >
197
+ ) }
198
+ </ div >
199
+ ) ;
200
+ }
201
+
202
+ render ( ) {
203
+ if ( this . state . hasError ) {
204
+ // Render custom fallback UI or default
205
+ return this . props . fallback || this . renderDefaultFallback ( ) ;
206
+ }
207
+
208
+ return this . props . children ;
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Hook version of Error Boundary for functional components
214
+ * Note: This is a wrapper that uses the class-based ErrorBoundary
215
+ */
216
+ export function withErrorBoundary < P extends object > (
217
+ Component : React . ComponentType < P > ,
218
+ errorBoundaryProps ?: Omit < Props , 'children' >
219
+ ) {
220
+ const WrappedComponent = ( props : P ) => (
221
+ < ErrorBoundary { ...errorBoundaryProps } >
222
+ < Component { ...props } />
223
+ </ ErrorBoundary >
224
+ ) ;
225
+
226
+ WrappedComponent . displayName = `withErrorBoundary(${ Component . displayName || Component . name } )` ;
227
+
228
+ return WrappedComponent ;
229
+ }
230
+
231
+ export default ErrorBoundary ;
0 commit comments