@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 3.84 kB
Source Map (JSON)
{"version":3,"file":"devSingleton.mjs","names":["prev","next"],"sources":["../../src/utils/devSingleton.ts"],"sourcesContent":["const DEV = process.env.NODE_ENV === 'development';\n\ntype Registry = {\n global: Map<string, number>;\n scoped: Map<string, WeakMap<object, number>>;\n};\n\nconst GLOBAL_KEY = '__LOBE_UI_DEV_SINGLETON_REGISTRY__';\n\nconst getRegistry = (): Registry => {\n const g = globalThis as unknown as Record<string, unknown>;\n if (!g[GLOBAL_KEY]) {\n g[GLOBAL_KEY] = {\n global: new Map<string, number>(),\n scoped: new Map<string, WeakMap<object, number>>(),\n } satisfies Registry;\n }\n return g[GLOBAL_KEY] as Registry;\n};\n\nconst getScopedMap = (registry: Registry, name: string) => {\n const existing = registry.scoped.get(name);\n if (existing) return existing;\n const next = new WeakMap<object, number>();\n registry.scoped.set(name, next);\n return next;\n};\n\nconst singletonError = (name: string) =>\n new Error(\n `[lobe-ui] ${name} must be rendered only once in a single React tree. ` +\n `You probably mounted it multiple times (or in multiple roots).`,\n );\n\n/**\n * Dev-only singleton guard.\n * - If `scope` is provided, it's enforced per scope object (e.g. portal root).\n * - Otherwise it's enforced globally in the current JS runtime.\n */\nexport const registerDevSingleton = (name: string, scope?: object | null): (() => void) => {\n if (!DEV) return () => {};\n\n const registry = getRegistry();\n\n // Scoped singleton (preferred)\n if (scope) {\n const scoped = getScopedMap(registry, name);\n const prev = scoped.get(scope) ?? 0;\n const next = prev + 1;\n scoped.set(scope, next);\n\n if (next > 1) {\n // rollback to avoid poisoning the registry after throwing\n if (prev === 0) scoped.delete(scope);\n else scoped.set(scope, prev);\n throw singletonError(name);\n }\n\n return () => {\n const curr = scoped.get(scope) ?? 0;\n const after = curr - 1;\n if (after <= 0) scoped.delete(scope);\n else scoped.set(scope, after);\n };\n }\n\n // Global singleton (fallback)\n const prev = registry.global.get(name) ?? 0;\n const next = prev + 1;\n registry.global.set(name, next);\n\n if (next > 1) {\n // rollback to avoid poisoning the registry after throwing\n if (prev === 0) registry.global.delete(name);\n else registry.global.set(name, prev);\n throw singletonError(name);\n }\n\n return () => {\n const curr = registry.global.get(name) ?? 0;\n const after = curr - 1;\n if (after <= 0) registry.global.delete(name);\n else registry.global.set(name, after);\n };\n};\n"],"mappings":";AAAA,MAAM,MAAM,QAAQ,IAAI,aAAa;AAOrC,MAAM,aAAa;AAEnB,MAAM,oBAA8B;CAClC,MAAM,IAAI;AACV,KAAI,CAAC,EAAE,YACL,GAAE,cAAc;EACd,wBAAQ,IAAI,KAAqB;EACjC,wBAAQ,IAAI,KAAsC;EACnD;AAEH,QAAO,EAAE;;AAGX,MAAM,gBAAgB,UAAoB,SAAiB;CACzD,MAAM,WAAW,SAAS,OAAO,IAAI,KAAK;AAC1C,KAAI,SAAU,QAAO;CACrB,MAAM,uBAAO,IAAI,SAAyB;AAC1C,UAAS,OAAO,IAAI,MAAM,KAAK;AAC/B,QAAO;;AAGT,MAAM,kBAAkB,yBACtB,IAAI,MACF,aAAa,KAAK,oHAEnB;;;;;;AAOH,MAAa,wBAAwB,MAAc,UAAwC;AACzF,KAAI,CAAC,IAAK,cAAa;CAEvB,MAAM,WAAW,aAAa;AAG9B,KAAI,OAAO;EACT,MAAM,SAAS,aAAa,UAAU,KAAK;EAC3C,MAAMA,SAAO,OAAO,IAAI,MAAM,IAAI;EAClC,MAAMC,SAAOD,SAAO;AACpB,SAAO,IAAI,OAAOC,OAAK;AAEvB,MAAIA,SAAO,GAAG;AAEZ,OAAID,WAAS,EAAG,QAAO,OAAO,MAAM;OAC/B,QAAO,IAAI,OAAOA,OAAK;AAC5B,SAAM,eAAe,KAAK;;AAG5B,eAAa;GAEX,MAAM,SADO,OAAO,IAAI,MAAM,IAAI,KACb;AACrB,OAAI,SAAS,EAAG,QAAO,OAAO,MAAM;OAC/B,QAAO,IAAI,OAAO,MAAM;;;CAKjC,MAAM,OAAO,SAAS,OAAO,IAAI,KAAK,IAAI;CAC1C,MAAM,OAAO,OAAO;AACpB,UAAS,OAAO,IAAI,MAAM,KAAK;AAE/B,KAAI,OAAO,GAAG;AAEZ,MAAI,SAAS,EAAG,UAAS,OAAO,OAAO,KAAK;MACvC,UAAS,OAAO,IAAI,MAAM,KAAK;AACpC,QAAM,eAAe,KAAK;;AAG5B,cAAa;EAEX,MAAM,SADO,SAAS,OAAO,IAAI,KAAK,IAAI,KACrB;AACrB,MAAI,SAAS,EAAG,UAAS,OAAO,OAAO,KAAK;MACvC,UAAS,OAAO,IAAI,MAAM,MAAM"}