Files
smart-crop-ui/src/AUTH_CONSTRUCTOR_ERROR_FIXED.md

5.8 KiB
Raw Blame History

认证系统构造函数错误修复

问题描述

系统出现 "Illegal constructor" 错误,错误堆栈指向 lib/authStorage.ts

TypeError: Illegal constructor
    at gi (lib/authStorage.ts:27:16)
    at TT (lib/authStorage.ts:27:16)
    ...

根本原因

模块级静态导入导致浏览器API过早访问

Login.tsxRegister.tsx 中,直接在模块顶层导入了 authStorage 中的函数:

// ❌ 问题代码 - 模块级静态导入
import { validatePasswordLogin, validatePhoneLogin, sendSmsCode } from '../../lib/authStorage';
import { registerUser, getAllEnterprises } from '../../lib/authStorage';

这会导致:

  1. 模块加载时立即执行 authStorage.ts
  2. authStorage.ts 中的代码可能尝试访问浏览器APIwindow.localStorage
  3. 在某些初始化阶段这些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 - 已使用延迟初始化

验证测试

测试步骤

  1. 清除浏览器缓存(重要)
  2. 刷新页面
  3. 检查控制台 - 应无 "Illegal constructor" 错误
  4. 测试密码登录功能
  5. 测试手机号登录功能
  6. 测试用户注册功能

预期结果

  • 无构造函数错误
  • 登录功能正常
  • 注册功能正常
  • 自动登录功能正常

性能影响

动态导入的性能影响:

  • 首次导入会有轻微延迟(几毫秒)
  • 后续导入会使用缓存,无额外开销
  • 对用户体验影响可忽略不计

优点:

  • 避免模块初始化错误
  • 提高代码健壮性
  • 符合最佳实践

注意事项

后续开发规范

禁止直接导入 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组件
测试状态: 待验证