Skip to content

Commit 61797e4

Browse files
committed
fix: fix esbuildplugin error
1 parent 93fe28a commit 61797e4

12 files changed

Lines changed: 23257 additions & 36313 deletions

File tree

package-lock.json

Lines changed: 23082 additions & 36263 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"build:vite:sentry": "cross-env SENTRY_DISABLE_TELEMETRY=1 SENTRY_SOURCE_MAP=map vite build --config vite.config.ts",
7979
"preview:vite": "vite preview --host --config vite.config.ts",
8080
"prod:serve": "cross-env SENTRY_SOURCE_MAP=no BUILD_SERVE=prod BUILD_GOAL=production NODE_ENV=production webpack --config ./webpack/webpack.prod.js --stats-error-details",
81+
"prod:serve:debug": "cross-env DEBUG_PROD=1 npm run prod:serve",
8182
"dev:serve": "cross-env SENTRY_SOURCE_MAP=no BUILD_SERVE=prod BUILD_GOAL=dev NODE_ENV=production webpack --config ./webpack/webpack.prod.js --stats-error-details",
8283
"test:serve": "cross-env SENTRY_SOURCE_MAP=no BUILD_SERVE=prod BUILD_GOAL=test NODE_ENV=production webpack --config ./webpack/webpack.prod.js --stats-error-details",
8384
"analyze:build": "cross-env SENTRY_SOURCE_MAP=no BUILD_GOAL=production NODE_ENV=production USE_ANALYZE=1 webpack --config ./webpack/webpack.prod.js --stats-error-details --profile --json=compilation-stats.json",
@@ -382,7 +383,14 @@
382383
"zustand": "^5.0.9"
383384
},
384385
"overrides": {
385-
"tmp": "0.2.5"
386+
"tmp": "0.2.5",
387+
"zustand": "^5.0.9",
388+
"tunnel-rat": {
389+
"zustand": "^5.0.9"
390+
},
391+
"@xyflow/react": {
392+
"zustand": "^5.0.9"
393+
}
386394
},
387395
"engines": {
388396
"node": ">=20.12.1",

src/index.tsx

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,6 @@ import * as Sentry from '@sentry/react'
1212
import i18n from './i18n/i18n'
1313
import GlobalBreakpointListener from '@/components/GlobalBreakpointListener'
1414

15-
const patchDefinePropertyDescriptor = () => {
16-
try {
17-
const originalDefineProperty = Object.defineProperty
18-
const originalDefineProperties = Object.defineProperties
19-
20-
const toDescriptor = (desc: unknown): PropertyDescriptor => {
21-
if (desc && typeof desc === 'object') return desc as PropertyDescriptor
22-
return {
23-
value: desc,
24-
writable: true,
25-
configurable: true,
26-
enumerable: true,
27-
}
28-
}
29-
30-
Object.defineProperty = function (obj: any, prop: PropertyKey, descriptor: any) {
31-
return originalDefineProperty(obj, prop, toDescriptor(descriptor))
32-
}
33-
34-
Object.defineProperties = function (obj: any, props: any) {
35-
if (!props || typeof props !== 'object') {
36-
// 保持原语义:让原实现抛错
37-
return originalDefineProperties(obj, props)
38-
}
39-
const normalized: Record<PropertyKey, PropertyDescriptor> = {}
40-
for (const key of Reflect.ownKeys(props)) {
41-
normalized[key] = toDescriptor(props[key])
42-
}
43-
return originalDefineProperties(obj, normalized)
44-
}
45-
} catch {
46-
// ignore
47-
}
48-
}
49-
50-
patchDefinePropertyDescriptor()
51-
5215
const isLocalhostRuntime = () => {
5316
try {
5417
const host = window.location.hostname

src/pages/layout/index.jsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useRef, useState } from 'react'
1+
import React, { useRef, useState, useMemo } from 'react'
22
import { Layout, Drawer } from 'antd'
33
import { useStore } from '@/store'
44
import { ProTabProvider } from '@app-hooks/proTabsContext'
@@ -12,11 +12,25 @@ import ProSecNav from './proSecNav'
1212
import styles from './index.module.less'
1313
import { useProThemeContext } from '@theme/hooks'
1414

15+
/**
16+
* 安全获取 store 状态的 hook
17+
* 当 store 初始化失败时返回默认值
18+
*/
19+
const useSafeStore = (selector, defaultValue) => {
20+
try {
21+
return useStore(selector) ?? defaultValue
22+
} catch (error) {
23+
console.error('Store access error:', error)
24+
return defaultValue
25+
}
26+
}
27+
1528
const ProLayout = () => {
1629
const layoutRef = useRef(null)
1730
const [settingOpen, setSettingOpen] = useState(false)
1831
const [mobileOpen, setMobileOpen] = useState(false)
19-
const isMobile = useStore((s) => s.isMobile)
32+
// 使用安全的 store 访问,当 middleware 加载失败时提供默认值
33+
const isMobile = useSafeStore((s) => s.isMobile, false)
2034

2135
const { themeSettings } = useProThemeContext()
2236
const { layout, themeMode, navTheme } = themeSettings

src/pages/layout/proHeader/index.jsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ import styles from './index.module.less'
3636
import Fullscreen from '../fullscreen'
3737
import { useStore } from '@/store'
3838

39+
/**
40+
* 安全获取 store 状态
41+
*/
42+
const useSafeStore = (selector, defaultValue) => {
43+
try {
44+
return useStore(selector) ?? defaultValue
45+
} catch (error) {
46+
console.error('ProHeader store access error:', error)
47+
return defaultValue
48+
}
49+
}
50+
3951
const DENIED_TIP = '您没有权限访问该页面'
4052

4153
const safeNotifyDeniedOnce = async ({ path, lastDeniedRef, messageApi }) => {
@@ -412,7 +424,7 @@ const ProHeader = ({ layout, onSettingClick, children, onMobileMenuClick }) => {
412424

413425
const iconButtonStyle = React.useMemo(() => ({ fontSize: 16 }), [])
414426

415-
const isMobile = useStore((s) => s.isMobile)
427+
const isMobile = useSafeStore((s) => s.isMobile, false)
416428

417429
return (
418430
<Layout.Header

src/pages/layout/proSecNav/index.jsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,21 @@ const PAGE_CANDIDATE_TEMPLATES = [
1616
(path, ext) => `/src/pages${path}/index${ext}`,
1717
]
1818

19-
const pageModules = import.meta?.glob?.('/src/pages/**/*.{js,jsx,ts,tsx}') ?? {}
19+
// 兼容 Vite 和 Webpack:import.meta.glob 是 Vite 独有功能
20+
// 在 Webpack 构建中 import.meta 会是 undefined 或抛出错误
21+
const getPageModules = () => {
22+
try {
23+
// 检查是否在 Vite 环境中
24+
if (typeof import.meta !== 'undefined' && typeof import.meta.glob === 'function') {
25+
return import.meta.glob('/src/pages/**/*.{js,jsx,ts,tsx}')
26+
}
27+
} catch {
28+
// Webpack 环境下 import.meta 可能会抛出错误
29+
}
30+
return {}
31+
}
32+
33+
const pageModules = getPageModules()
2034

2135
const hasOwn = (obj, key) => obj != null && Object.hasOwn(obj, key)
2236

@@ -413,10 +427,17 @@ const ProSecNav = ({ mode = 'inline', theme = 'light', onMenuClick }) => {
413427
showDeniedOnce(selectedPath)
414428
return
415429
}
416-
redirectTo(selectedPath)
417-
setIsOpenChange(false)
418-
onMenuClick?.()
430+
// 使用 try-catch 包裹路由跳转,防止异步组件加载失败导致菜单卡死
431+
try {
432+
redirectTo(selectedPath)
433+
setIsOpenChange(false)
434+
onMenuClick?.()
435+
} catch (navError) {
436+
console.error('路由跳转失败:', navError)
437+
messageApi.error('页面加载失败,请刷新重试')
438+
}
419439
} catch (error) {
440+
console.error('权限检查失败:', error)
420441
showDeniedOnce(selectedPath)
421442
}
422443
}

src/pages/layout/proSider/index.jsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,25 @@ import { useStore } from '@/store'
66

77
import styles from './index.module.less'
88

9+
/**
10+
* 安全获取 store 状态
11+
*/
12+
const useSafeStore = (selector, defaultValue) => {
13+
try {
14+
return useStore(selector) ?? defaultValue
15+
} catch (error) {
16+
console.error('ProSider store access error:', error)
17+
return defaultValue
18+
}
19+
}
20+
921
const ProSider = ({ children, theme = 'light' }) => {
10-
const isSidebarOpen = useStore((s) => s.isSidebarOpen)
11-
const toggleSidebar = useStore((s) => s.toggleSidebar)
12-
const isMobile = useStore((s) => s.isMobile)
22+
const isSidebarOpen = useSafeStore((s) => s.isSidebarOpen, true)
23+
const toggleSidebar = useSafeStore(
24+
(s) => s.toggleSidebar,
25+
() => {}
26+
)
27+
const isMobile = useSafeStore((s) => s.isMobile, false)
1328

1429
return (
1530
<Layout.Sider

src/routers/config/lazyLoad.config.jsx

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,48 @@ import Home from '@pages/home'
66
import Layout from '@pages/layout'
77
import MyPortfilo from '@pages/portfilo'
88

9+
/**
10+
* 懒加载失败时的备用组件
11+
*/
12+
const LoadError = ({ error, retry }) => (
13+
<div style={{ padding: 24, textAlign: 'center' }}>
14+
<p style={{ color: '#ff4d4f', marginBottom: 16 }}>组件加载失败: {error?.message || '未知错误'}</p>
15+
<button
16+
onClick={retry}
17+
style={{
18+
padding: '8px 16px',
19+
cursor: 'pointer',
20+
backgroundColor: '#1890ff',
21+
color: '#fff',
22+
border: 'none',
23+
borderRadius: 4,
24+
}}
25+
>
26+
重试
27+
</button>
28+
</div>
29+
)
30+
931
/**
1032
* 统一懒加载处理函数
1133
* @param {Function} importFunc - 动态导入函数
1234
* @param {Object} options - 加载选项
1335
* @returns {React.Component} 懒加载组件
1436
*/
15-
const lazyLoad = (importFunc, options = {}) => loadable(importFunc, { fallback: <Loading />, ...options })
37+
const lazyLoad = (importFunc, options = {}) => {
38+
// 包装 importFunc 以捕获并处理动态导入错误
39+
const safeImportFunc = () =>
40+
importFunc().catch((error) => {
41+
console.error('[lazyLoad] 动态导入失败:', error)
42+
// 重新抛出错误让 loadable 的 fallback 处理
43+
throw error
44+
})
45+
46+
return loadable(safeImportFunc, {
47+
fallback: <Loading />,
48+
...options,
49+
})
50+
}
1651

1752
/**
1853
* 路由组件懒加载配置

src/store/useSafeStore.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// src/store/useSafeStore.ts
2+
import { useStore } from './index'
3+
import { StoreState } from './types'
4+
5+
/**
6+
* 安全获取 store 状态的 hook
7+
* 当 store 初始化失败时返回默认值,避免整个组件树崩溃
8+
*
9+
* @param selector - 状态选择器函数
10+
* @param defaultValue - 当 store 访问失败时的默认值
11+
* @returns 选中的状态值或默认值
12+
*
13+
* @example
14+
* // 基本用法
15+
* const isMobile = useSafeStore((s) => s.isMobile, false)
16+
*
17+
* // 获取函数
18+
* const toggleSidebar = useSafeStore((s) => s.toggleSidebar, () => {})
19+
*/
20+
export function useSafeStore<T>(selector: (state: StoreState) => T, defaultValue: T): T {
21+
try {
22+
const result = useStore(selector)
23+
return result ?? defaultValue
24+
} catch (error) {
25+
if (process.env.NODE_ENV === 'development') {
26+
console.error('[useSafeStore] Store access error:', error)
27+
}
28+
return defaultValue
29+
}
30+
}
31+
32+
export default useSafeStore

vite.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ export default defineConfig(({ mode }) => {
137137
'@utils': path.resolve(__dirname, 'src/utils'),
138138
'@theme': path.resolve(__dirname, 'src/theme'),
139139
},
140+
// 确保 zustand 及相关依赖只有一个实例,避免 middleware 错误
141+
dedupe: ['zustand', 'immer', 'react', 'react-dom'],
140142
},
141143
server: {
142144
port: 5173,
@@ -152,6 +154,14 @@ export default defineConfig(({ mode }) => {
152154
chunkSizeWarningLimit: 800,
153155
rollupOptions: {
154156
input: path.resolve(__dirname, 'index.html'),
157+
output: {
158+
// 确保 zustand 及其 middleware 打包到同一个 chunk 中,避免多实例问题
159+
manualChunks: {
160+
'vendor-zustand': ['zustand', 'zustand/middleware', 'zustand/middleware/immer', 'immer'],
161+
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
162+
'vendor-antd': ['antd', '@ant-design/icons'],
163+
},
164+
},
155165
},
156166
},
157167
}

0 commit comments

Comments
 (0)