@sigmaott/base-next 1.4.37 → 1.4.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sigmaott/base-next",
3
3
  "type": "module",
4
- "version": "1.4.37",
4
+ "version": "1.4.38",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -1,19 +1,72 @@
1
+ import { setupGlobalComponentResolutionHandler, handleComponentResolutionError, isComponentResolutionError } from '../utils/component-resolution'
2
+
1
3
  export default defineNuxtPlugin((nuxtApp) => {
4
+ // Setup global error handlers
5
+ setupGlobalComponentResolutionHandler()
6
+
2
7
  nuxtApp.hook('app:created', async (app) => {
3
- await new Promise<void>((resolve) => {
8
+ await new Promise<void>((resolve, reject) => {
4
9
  if (window.__POWERED_BY_WUJIE__) {
5
10
  window.__WUJIE_MOUNT = () => {
6
- syncMicroState()
7
- resolve()
11
+ try {
12
+ syncMicroState()
13
+ resolve()
14
+ } catch (error) {
15
+ console.error('[Wujie] Error during mount:', error)
16
+ if (isComponentResolutionError(error)) {
17
+ handleComponentResolutionError(error, 'wujie-mount')
18
+ }
19
+ reject(error)
20
+ }
8
21
  }
9
22
  window.__WUJIE_UNMOUNT = () => {
10
- app.unmount()
23
+ try {
24
+ app.unmount()
25
+ } catch (error) {
26
+ console.error('[Wujie] Error during unmount:', error)
27
+ if (isComponentResolutionError(error)) {
28
+ handleComponentResolutionError(error, 'wujie-unmount')
29
+ }
30
+ }
31
+ }
32
+
33
+ // Add timeout to prevent hanging
34
+ const timeout = setTimeout(() => {
35
+ console.warn('[Wujie] Mount timeout, resolving anyway')
36
+ resolve()
37
+ }, 5000)
38
+
39
+ try {
40
+ window.__WUJIE.mount()
41
+ clearTimeout(timeout)
42
+ } catch (error) {
43
+ clearTimeout(timeout)
44
+ console.error('[Wujie] Error mounting app:', error)
45
+ if (isComponentResolutionError(error)) {
46
+ handleComponentResolutionError(error, 'wujie-mount-init')
47
+ }
48
+ reject(error)
11
49
  }
12
- window.__WUJIE.mount()
13
50
  }
14
51
  else {
15
52
  resolve()
16
53
  }
17
54
  })
18
55
  })
56
+
57
+ // Enhanced error handling for component resolution
58
+ nuxtApp.hook('app:error', (error) => {
59
+ if (isComponentResolutionError(error)) {
60
+ handleComponentResolutionError(error, 'nuxt-app-error')
61
+ }
62
+ })
63
+
64
+ // Handle Vue component errors
65
+ nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
66
+ if (isComponentResolutionError(error)) {
67
+ handleComponentResolutionError(error, 'vue-error-handler')
68
+ } else {
69
+ console.error('[Vue] Error:', error, 'Info:', info)
70
+ }
71
+ }
19
72
  })
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Utility functions for handling component resolution issues in micro-frontend architecture
3
+ */
4
+
5
+ export interface ComponentResolutionError extends Error {
6
+ componentName?: string
7
+ path?: string
8
+ isRecoverable?: boolean
9
+ }
10
+
11
+ /**
12
+ * Detects if an error is related to component resolution
13
+ */
14
+ export function isComponentResolutionError(error: any): error is ComponentResolutionError {
15
+ return error?.message?.includes('Couldn\'t resolve component') ||
16
+ error?.message?.includes('Failed to resolve component') ||
17
+ error?.message?.includes('Component not found')
18
+ }
19
+
20
+ /**
21
+ * Handles component resolution errors with recovery strategies
22
+ */
23
+ export function handleComponentResolutionError(error: ComponentResolutionError, context: string = 'unknown') {
24
+ console.warn(`[${context}] Component resolution error detected:`, error)
25
+
26
+ // Extract component name and path from error message
27
+ const componentMatch = error.message?.match(/component "([^"]+)"/)
28
+ const pathMatch = error.message?.match(/at "([^"]+)"/)
29
+
30
+ if (componentMatch) {
31
+ error.componentName = componentMatch[1]
32
+ }
33
+ if (pathMatch) {
34
+ error.path = pathMatch[1]
35
+ }
36
+
37
+ // Determine if error is recoverable
38
+ error.isRecoverable = !error.message?.includes('permanent') &&
39
+ !error.message?.includes('fatal')
40
+
41
+ if (error.isRecoverable) {
42
+ console.log(`[${context}] Attempting recovery for component: ${error.componentName} at ${error.path}`)
43
+
44
+ // Strategy 1: Wait and retry
45
+ setTimeout(() => {
46
+ if (window.location) {
47
+ console.log(`[${context}] Reloading page for recovery...`)
48
+ window.location.reload()
49
+ }
50
+ }, 1000)
51
+ } else {
52
+ console.error(`[${context}] Non-recoverable component resolution error:`, error)
53
+ }
54
+
55
+ return error.isRecoverable
56
+ }
57
+
58
+ /**
59
+ * Creates a retry mechanism for component resolution
60
+ */
61
+ export function createComponentResolutionRetry(
62
+ maxRetries: number = 3,
63
+ delay: number = 1000
64
+ ) {
65
+ let retryCount = 0
66
+
67
+ return function retryComponentResolution<T>(
68
+ operation: () => T | Promise<T>,
69
+ context: string = 'component-resolution'
70
+ ): Promise<T> {
71
+ return new Promise((resolve, reject) => {
72
+ const attempt = async () => {
73
+ try {
74
+ const result = await operation()
75
+ resolve(result)
76
+ } catch (error) {
77
+ if (isComponentResolutionError(error) && retryCount < maxRetries) {
78
+ retryCount++
79
+ console.warn(`[${context}] Retry ${retryCount}/${maxRetries} for component resolution...`)
80
+
81
+ setTimeout(() => {
82
+ attempt()
83
+ }, delay * retryCount)
84
+ } else {
85
+ handleComponentResolutionError(error as ComponentResolutionError, context)
86
+ reject(error)
87
+ }
88
+ }
89
+ }
90
+
91
+ attempt()
92
+ })
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Debounced component resolution checker
98
+ */
99
+ export function createComponentResolutionChecker(
100
+ checkInterval: number = 100,
101
+ maxChecks: number = 50
102
+ ) {
103
+ let checkCount = 0
104
+
105
+ return function checkComponentResolution(
106
+ componentName: string,
107
+ context: string = 'component-checker'
108
+ ): Promise<boolean> {
109
+ return new Promise((resolve) => {
110
+ const check = () => {
111
+ checkCount++
112
+
113
+ // Check if component exists in DOM
114
+ const componentExists = document.querySelector(`[data-component="${componentName}"]`) ||
115
+ document.querySelector(`[data-v-${componentName}]`) ||
116
+ document.querySelector(`#${componentName}`)
117
+
118
+ if (componentExists) {
119
+ console.log(`[${context}] Component ${componentName} found after ${checkCount} checks`)
120
+ resolve(true)
121
+ } else if (checkCount >= maxChecks) {
122
+ console.warn(`[${context}] Component ${componentName} not found after ${maxChecks} checks`)
123
+ resolve(false)
124
+ } else {
125
+ setTimeout(check, checkInterval)
126
+ }
127
+ }
128
+
129
+ check()
130
+ })
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Global error handler for component resolution issues
136
+ */
137
+ export function setupGlobalComponentResolutionHandler() {
138
+ // Handle unhandled promise rejections
139
+ window.addEventListener('unhandledrejection', (event) => {
140
+ if (isComponentResolutionError(event.reason)) {
141
+ console.warn('[Global] Unhandled component resolution error:', event.reason)
142
+ handleComponentResolutionError(event.reason, 'global-unhandled')
143
+ event.preventDefault()
144
+ }
145
+ })
146
+
147
+ // Handle general errors
148
+ window.addEventListener('error', (event) => {
149
+ if (isComponentResolutionError(event.error)) {
150
+ console.warn('[Global] Component resolution error:', event.error)
151
+ handleComponentResolutionError(event.error, 'global-error')
152
+ event.preventDefault()
153
+ }
154
+ })
155
+ }
156
+
157
+ /**
158
+ * Vue composable for component resolution error handling
159
+ */
160
+ export function useComponentResolutionError() {
161
+ const errorHandler = (error: any, context: string = 'vue-component') => {
162
+ if (isComponentResolutionError(error)) {
163
+ return handleComponentResolutionError(error, context)
164
+ }
165
+ return false
166
+ }
167
+
168
+ const retryHandler = createComponentResolutionRetry()
169
+ const checker = createComponentResolutionChecker()
170
+
171
+ return {
172
+ errorHandler,
173
+ retryHandler,
174
+ checker,
175
+ isComponentResolutionError
176
+ }
177
+ }
@@ -74,16 +74,64 @@ const defaultLifecycles: Lifecycles = {
74
74
  beforeLoad: (appWindow) => {
75
75
  console.log(`${appWindow.__WUJIE.id} beforeLoad`)
76
76
  console.log('[LOG] ~ file: micro.ts:76 ~ appWindow:', appWindow)
77
- addMicroApp(appWindow)
77
+ try {
78
+ addMicroApp(appWindow)
79
+ } catch (error) {
80
+ console.error(`[Micro] Error adding micro app ${appWindow.__WUJIE.id}:`, error)
81
+ }
82
+ },
83
+ beforeMount: (appWindow) => {
84
+ console.log(`${appWindow.__WUJIE.id} beforeMount`)
85
+ // Ensure component resolution is ready
86
+ return new Promise((resolve) => {
87
+ setTimeout(() => {
88
+ resolve()
89
+ }, 100)
90
+ })
91
+ },
92
+ afterMount: (appWindow) => {
93
+ console.log(`${appWindow.__WUJIE.id} afterMount`)
94
+ // Verify component is properly mounted
95
+ try {
96
+ if (appWindow.document && appWindow.document.querySelector('[data-v-app]')) {
97
+ console.log(`${appWindow.__WUJIE.id} component properly mounted`)
98
+ }
99
+ } catch (error) {
100
+ console.warn(`${appWindow.__WUJIE.id} component mount verification failed:`, error)
101
+ }
102
+ },
103
+ beforeUnmount: (appWindow) => {
104
+ console.log(`${appWindow.__WUJIE.id} beforeUnmount`)
105
+ try {
106
+ // Clean up any pending operations
107
+ if (appWindow.__WUJIE?.cleanup) {
108
+ appWindow.__WUJIE.cleanup()
109
+ }
110
+ } catch (error) {
111
+ console.error(`${appWindow.__WUJIE.id} cleanup error:`, error)
112
+ }
113
+ },
114
+ afterUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterUnmount`),
115
+ activated: (appWindow) => {
116
+ console.log(`${appWindow.__WUJIE.id} activated`)
117
+ // Ensure component is ready when activated
118
+ return new Promise((resolve) => {
119
+ setTimeout(() => {
120
+ resolve()
121
+ }, 50)
122
+ })
78
123
  },
79
- beforeMount: appWindow => console.log(`${appWindow.__WUJIE.id} beforeMount`),
80
- afterMount: appWindow => console.log(`${appWindow.__WUJIE.id} afterMount`),
81
- beforeUnmount: appWindow => console.log(`${appWindow.__WUJIE.id} beforeUnmount `),
82
- afterUnmount: appWindow => console.log(`${appWindow.__WUJIE.id} afterUnmount`),
83
- activated: appWindow => console.log(`${appWindow.__WUJIE.id} activated`),
84
124
  deactivated: appWindow => console.log(`${appWindow.__WUJIE.id} deactivated`),
85
- loadError: (url, e) => console.log(`${url}`, e),
86
-
125
+ loadError: (url, e) => {
126
+ console.error(`[Micro] Load error for ${url}:`, e)
127
+ // Attempt recovery for component resolution errors
128
+ if (e.message?.includes('Couldn\'t resolve component')) {
129
+ console.warn('[Micro] Component resolution error detected, attempting recovery...')
130
+ setTimeout(() => {
131
+ window.location.reload()
132
+ }, 2000)
133
+ }
134
+ },
87
135
  }
88
136
 
89
137
  const plugins: Array<plugin> = [