Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,42 +1,63 @@
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';
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<string, unknown>) {}
}

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', () => {
Expand Down
12 changes: 3 additions & 9 deletions packages/vrender-core/src/graphic/graphic-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<TGraphic extends IGraphic = IGraphic, TAttributes = any>(
Expand Down
27 changes: 1 addition & 26 deletions packages/vrender-core/src/graphic/graphic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ export const NOWORK_ANIMATE_ATTR = {
* 3. 所有节点的transform修改,或者globalTransform修改,都会下发到自己的shadowRoot上
*/

abstract class GraphicImpl<T extends Partial<IGraphicAttribute> = Partial<IGraphicAttribute>>
export abstract class Graphic<T extends Partial<IGraphicAttribute> = Partial<IGraphicAttribute>>
extends Node
implements IGraphic<T>, IAnimateTarget
{
Expand Down Expand Up @@ -3230,31 +3230,6 @@ abstract class GraphicImpl<T extends Partial<IGraphicAttribute> = Partial<IGraph
}
}

export type Graphic<T extends Partial<IGraphicAttribute> = Partial<IGraphicAttribute>> = GraphicImpl<T>;

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) {
Expand Down
Loading