diff --git a/packages/vrender-core/__tests__/unit/graphic/graphic-factory-migration.test.ts b/packages/vrender-core/__tests__/unit/graphic/graphic-factory-migration.test.ts index 6ecd94d2f..e989f5fe4 100644 --- a/packages/vrender-core/__tests__/unit/graphic/graphic-factory-migration.test.ts +++ b/packages/vrender-core/__tests__/unit/graphic/graphic-factory-migration.test.ts @@ -1,7 +1,6 @@ import type { IRectGraphicAttribute } from '../../../src/interface'; import { createGraphic, graphicCreator, registerGraphic } from '../../../src/graphic'; import { Arc3d } from '../../../src/graphic/arc3d'; -import { Graphic } from '../../../src/graphic/base'; import { DefaultGraphicService } from '../../../src/graphic/graphic-service/graphic-service'; import { Group } from '../../../src/graphic/group'; import { Rect } from '../../../src/graphic/rect'; @@ -9,34 +8,56 @@ import { registerArc3dGraphic } from '../../../src/register/register-arc3d'; import { registerGroupGraphic } from '../../../src/register/register-group'; import { registerRectGraphic } from '../../../src/register/register-rect'; +declare const require: any; + class GraphicStub { constructor(public readonly attribute: Record) {} } -describe('graphic factory migration', () => { - test('graphic registry should use realm-level shared state for duplicated ESM entry evaluation', () => { - registerGraphic('realm-shared-stub', GraphicStub as any); - - const registryState = (globalThis as any)[Symbol.for('@visactor/vrender-core/graphic-registry')]; +class OtherGraphicStub extends GraphicStub {} - expect(registryState).toBeDefined(); - expect(registryState.graphicCreator).toBe(graphicCreator); - expect(registryState.graphicFactory.create('realm-shared-stub', { x: 1 })).toBeInstanceOf(GraphicStub); - expect(createGraphic('realm-shared-stub', { x: 2 })).toBeInstanceOf(GraphicStub); +describe('graphic factory migration', () => { + test('graphic registry should stay module-local for duplicated module evaluation', () => { + const slot = Symbol.for('@visactor/vrender-core/graphic-registry'); + delete (globalThis as any)[slot]; + + jest.resetModules(); + const firstRegistry = require('../../../src/graphic/graphic-registry'); + firstRegistry.registerGraphic('module-local-stub', GraphicStub as any); + + jest.resetModules(); + const secondRegistry = require('../../../src/graphic/graphic-registry'); + secondRegistry.registerGraphic('module-local-stub', OtherGraphicStub as any); + + try { + expect(secondRegistry.graphicCreator).not.toBe(firstRegistry.graphicCreator); + expect(firstRegistry.createGraphic('module-local-stub', { x: 1 })).toBeInstanceOf(GraphicStub); + expect(firstRegistry.createGraphic('module-local-stub', { x: 1 })).not.toBeInstanceOf(OtherGraphicStub); + expect(secondRegistry.createGraphic('module-local-stub', { x: 2 })).toBeInstanceOf(OtherGraphicStub); + expect(Object.prototype.hasOwnProperty.call(globalThis, slot)).toBe(false); + } finally { + delete (globalThis as any)[slot]; + } }); - test('Graphic class should use realm-level shared state for duplicated ESM entry evaluation', () => { - registerGroupGraphic(); - registerArc3dGraphic(); + test('Graphic class should stay module-local for duplicated module evaluation', () => { + const slot = Symbol.for('@visactor/vrender-core/graphic-class'); + delete (globalThis as any)[slot]; - const classState = (globalThis as any)[Symbol.for('@visactor/vrender-core/graphic-class')]; - const group = createGraphic('group', {}); - const arc3d = createGraphic('arc3d', {}); + let firstGraphic: unknown = null; + let secondGraphic: unknown = null; + + jest.resetModules(); + firstGraphic = require('../../../src/graphic/graphic').Graphic; + jest.resetModules(); + secondGraphic = require('../../../src/graphic/graphic').Graphic; - expect(classState).toBeDefined(); - expect(classState.Graphic).toBe(Graphic); - expect(group).toBeInstanceOf(classState.Graphic); - expect(arc3d).toBeInstanceOf(classState.Graphic); + try { + expect(secondGraphic).not.toBe(firstGraphic); + expect(Object.prototype.hasOwnProperty.call(globalThis, slot)).toBe(false); + } finally { + delete (globalThis as any)[slot]; + } }); test('registerGraphic should register creators for createGraphic', () => { diff --git a/packages/vrender-core/src/graphic/graphic-registry.ts b/packages/vrender-core/src/graphic/graphic-registry.ts index b974c0b4f..a226fe7d2 100644 --- a/packages/vrender-core/src/graphic/graphic-registry.ts +++ b/packages/vrender-core/src/graphic/graphic-registry.ts @@ -106,18 +106,12 @@ function createGraphicRegistryState(): IGraphicRegistryState { }; } -export function getGraphicRegistryState(): IGraphicRegistryState { - const scope = globalThis as typeof globalThis & { [GRAPHIC_REGISTRY_SYMBOL]?: IGraphicRegistryState }; - - if (!scope[GRAPHIC_REGISTRY_SYMBOL]) { - scope[GRAPHIC_REGISTRY_SYMBOL] = createGraphicRegistryState(); - } +const sharedGraphicRegistry = createGraphicRegistryState(); - return scope[GRAPHIC_REGISTRY_SYMBOL] as IGraphicRegistryState; +export function getGraphicRegistryState(): IGraphicRegistryState { + return sharedGraphicRegistry; } -const sharedGraphicRegistry = getGraphicRegistryState(); - export const graphicCreator = sharedGraphicRegistry.graphicCreator; export function registerGraphic( diff --git a/packages/vrender-core/src/graphic/graphic.ts b/packages/vrender-core/src/graphic/graphic.ts index d87ea1fd5..e6d184533 100644 --- a/packages/vrender-core/src/graphic/graphic.ts +++ b/packages/vrender-core/src/graphic/graphic.ts @@ -306,7 +306,7 @@ export const NOWORK_ANIMATE_ATTR = { * 3. 所有节点的transform修改,或者globalTransform修改,都会下发到自己的shadowRoot上 */ -abstract class GraphicImpl = Partial> +export abstract class Graphic = Partial> extends Node implements IGraphic, IAnimateTarget { @@ -3230,31 +3230,6 @@ abstract class GraphicImpl = Partial = Partial> = GraphicImpl; - -export const GRAPHIC_CLASS_SYMBOL = Symbol.for('@visactor/vrender-core/graphic-class'); - -export interface IGraphicClassState { - Graphic: typeof GraphicImpl; -} - -function createGraphicClassState(): IGraphicClassState { - return { - Graphic: GraphicImpl - }; -} - -export function getGraphicClassState(): IGraphicClassState { - const globalScope = globalThis as typeof globalThis & { - [GRAPHIC_CLASS_SYMBOL]?: IGraphicClassState; - }; - - globalScope[GRAPHIC_CLASS_SYMBOL] ??= createGraphicClassState(); - return globalScope[GRAPHIC_CLASS_SYMBOL]; -} - -export const Graphic = getGraphicClassState().Graphic; - Graphic.mixin(EventTarget); function backgroundNotImage(image: any) {