5.8 KiB
5.8 KiB
认证系统构造函数错误修复
问题描述
系统出现 "Illegal constructor" 错误,错误堆栈指向 lib/authStorage.ts:
TypeError: Illegal constructor
at gi (lib/authStorage.ts:27:16)
at TT (lib/authStorage.ts:27:16)
...
根本原因
模块级静态导入导致浏览器API过早访问:
在 Login.tsx 和 Register.tsx 中,直接在模块顶层导入了 authStorage 中的函数:
// ❌ 问题代码 - 模块级静态导入
import { validatePasswordLogin, validatePhoneLogin, sendSmsCode } from '../../lib/authStorage';
import { registerUser, getAllEnterprises } from '../../lib/authStorage';
这会导致:
- 模块加载时立即执行
authStorage.ts authStorage.ts中的代码可能尝试访问浏览器API(如window.localStorage)- 在某些初始化阶段,这些API可能还未完全可用,导致"Illegal constructor"错误
修复方案
将所有静态导入改为动态导入(Dynamic Import):
1. 移除模块级导入
Login.tsx 修改:
// ✅ 移除这行
// import { validatePasswordLogin, validatePhoneLogin, sendSmsCode } from '../../lib/authStorage';
Register.tsx 修改:
// ✅ 移除这行
// import { registerUser, sendSmsCode, getAllEnterprises } from '../../lib/authStorage';
2. 在函数内使用动态导入
Login.tsx - 密码登录:
const handlePasswordLogin = async (e: React.FormEvent) => {
// ...
try {
// ✅ 函数内动态导入
const { validatePasswordLogin } = await import('../../lib/authStorage');
const result = await validatePasswordLogin(/* ... */);
// ...
}
}
Login.tsx - 手机登录:
const handlePhoneLogin = async (e: React.FormEvent) => {
// ...
try {
const { validatePhoneLogin } = await import('../../lib/authStorage');
const result = await validatePhoneLogin(/* ... */);
// ...
}
}
Login.tsx - 发送验证码:
const handleSendCode = async () => {
// ...
try {
const { sendSmsCode } = await import('../../lib/authStorage');
const result = await sendSmsCode(phoneForm.phone);
// ...
}
}
Register.tsx - 加载企业列表:
useEffect(() => {
const loadEnterprises = async () => {
const { getAllEnterprises } = await import('../../lib/authStorage');
const enterpriseList = getAllEnterprises();
setEnterprises(enterpriseList);
};
loadEnterprises();
}, []);
Register.tsx - 用户注册:
const handleRegister = async (e: React.FormEvent) => {
// ...
try {
const { registerUser } = await import('../../lib/authStorage');
const result = await registerUser({ /* ... */ });
// ...
}
}
Register.tsx - 发送验证码:
const handleSendCode = async () => {
// ...
try {
const { sendSmsCode } = await import('../../lib/authStorage');
const result = await sendSmsCode(form.phone);
// ...
}
}
技术原理
静态导入 vs 动态导入
静态导入(有问题):
import { func } from './module'; // 模块加载时立即执行
- 在模块加载阶段执行
- 可能在浏览器环境未完全初始化时运行
- 可能导致访问未就绪的API
动态导入(解决方案):
const { func } = await import('./module'); // 函数执行时才导入
- 在函数调用时才执行
- 此时浏览器环境已完全初始化
- 所有API都已就绪
AuthContext 已使用动态导入
AuthContext.tsx 早已正确使用了动态导入:
const initAuth = async () => {
try {
const authStorage = await import('../../lib/authStorage');
const token = authStorage.getToken();
// ...
}
}
这就是为什么 AuthContext 没有出现错误,而 Login/Register 组件会出错的原因。
修复文件清单
已修复文件
-
✅
/components/auth/Login.tsx- 移除静态导入
handlePasswordLogin使用动态导入handlePhoneLogin使用动态导入handleSendCode使用动态导入
-
✅
/components/auth/Register.tsx- 移除静态导入
- 企业列表加载使用动态导入
handleRegister使用动态导入handleSendCode使用动态导入
无需修改
- ✅
/components/auth/AuthContext.tsx- 已使用动态导入 - ✅
/lib/authStorage.ts- 已使用延迟初始化
验证测试
测试步骤
- 清除浏览器缓存(重要)
- 刷新页面
- 检查控制台 - 应无 "Illegal constructor" 错误
- 测试密码登录功能
- 测试手机号登录功能
- 测试用户注册功能
预期结果
- ✅ 无构造函数错误
- ✅ 登录功能正常
- ✅ 注册功能正常
- ✅ 自动登录功能正常
性能影响
动态导入的性能影响:
- 首次导入会有轻微延迟(几毫秒)
- 后续导入会使用缓存,无额外开销
- 对用户体验影响可忽略不计
优点:
- ✅ 避免模块初始化错误
- ✅ 提高代码健壮性
- ✅ 符合最佳实践
注意事项
后续开发规范
禁止直接导入 authStorage:
// ❌ 错误 - 不要这样做
import { someFunc } from '../../lib/authStorage';
// ✅ 正确 - 使用动态导入
async function myFunction() {
const { someFunc } = await import('../../lib/authStorage');
await someFunc();
}
适用范围
此修复方案适用于所有可能访问浏览器API的工具模块,包括但不限于:
- localStorage/sessionStorage
- window对象
- document对象
- navigator对象
总结
通过将静态导入改为动态导入,彻底解决了"Illegal constructor"错误。这是一个架构级的改进,提高了系统的稳定性和健壮性。
修复完成时间: 2025-10-23
影响范围: 认证系统(Login/Register组件)
测试状态: 待验证