From 6330286c7ecf02a33d51b97731dc74f5ec2407ba Mon Sep 17 00:00:00 2001 From: Bohan Jiang <52446949+Bohan-J@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:17:21 +0800 Subject: [PATCH] fix(lark): use named import for react-qr-code to survive electron-vite interop (#3718) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(lark): use named import for react-qr-code to survive electron-vite interop Clicking Bind on the agent detail page white-screened the desktop app at the QR step: Element type is invalid: expected a string or a class/function but got: object. Check the render method of `LarkInstallDialog`. react-qr-code is a CJS package. `import QRCode from "react-qr-code"` relies on the bundler's __esModule default-interop to unwrap `.default`. Next.js (web) unwraps it correctly; electron-vite's dep-optimizer handed back the whole module namespace object `{ default, QRCode, __esModule }` instead of the component, so React got an object where it expected a component the moment mounted — desktop-only white screen, web unaffected. Switch to the named import `{ QRCode }`, which maps straight to `exports.QRCode` and doesn't depend on the flaky default-interop path. Resolves correctly under both bundlers; the package's own .d.ts exports both the named class and the default, so it typechecks unchanged. Not a backend / Lark-config issue — purely a frontend CJS interop bug. * test(lark): expose named QRCode export in react-qr-code mock Follow-up to the named-import switch in lark-tab. The test stubbed react-qr-code with only a `default` export; now that the component imports `{ QRCode }`, the named binding resolved to undefined and the 3 QR-rendering tests failed with "No QRCode export is defined on the react-qr-code mock". Return the stub as both `QRCode` and `default`, defined inside the factory (vi.mock is hoisted above top-level vars). --- .../views/settings/components/lark-tab.test.tsx | 14 ++++++++++---- packages/views/settings/components/lark-tab.tsx | 9 ++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/views/settings/components/lark-tab.test.tsx b/packages/views/settings/components/lark-tab.test.tsx index 4b225c96e4..14d93354aa 100644 --- a/packages/views/settings/components/lark-tab.test.tsx +++ b/packages/views/settings/components/lark-tab.test.tsx @@ -133,11 +133,17 @@ vi.mock("sonner", () => ({ // react-qr-code renders SVG that jsdom doesn't fully support — a stub // keeps the dialog DOM compact and lets us assert on the surrounding // chrome (status text, buttons) without QR mechanics. -vi.mock("react-qr-code", () => ({ - default: ({ value }: { value: string }) => ( +// Expose the stub as BOTH the named `QRCode` export (what lark-tab now +// imports — see the named-import interop fix) and `default`, so the mock +// stays correct regardless of how the component pulls it in. The stub is +// defined inside the factory because vi.mock is hoisted above any +// top-level variable. +vi.mock("react-qr-code", () => { + const QrStub = ({ value }: { value: string }) => ( - ), -})); + ); + return { QRCode: QrStub, default: QrStub }; +}); import { LarkAgentBindButton, LarkTab } from "./lark-tab"; diff --git a/packages/views/settings/components/lark-tab.tsx b/packages/views/settings/components/lark-tab.tsx index 1f4b7f2a60..fc70cb6f34 100644 --- a/packages/views/settings/components/lark-tab.tsx +++ b/packages/views/settings/components/lark-tab.tsx @@ -4,7 +4,14 @@ import { useEffect, useRef, useState } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { ExternalLink, RefreshCw, Trash2 } from "lucide-react"; -import QRCode from "react-qr-code"; +// Named import, NOT default: react-qr-code is CJS, and electron-vite's +// dep-optimizer default-import interop handed back the module namespace +// object instead of the component, throwing "Element type is invalid … +// got: object" the moment mounted (the QR step of the install +// dialog) — desktop white-screened while web (Next.js, different interop) +// was fine. The named export maps straight to `exports.QRCode` and +// resolves correctly under both bundlers. +import { QRCode } from "react-qr-code"; import { Button } from "@multica/ui/components/ui/button"; import { Card, CardContent } from "@multica/ui/components/ui/card"; import {