Skip to content

Commit

Permalink
fix: fix univer plugin lifecycle not triggered (#2023)
Browse files Browse the repository at this point in the history
* fix: fix univer plugin lifecycle not triggered

* feat: add start API on Univer
  • Loading branch information
wzhudev committed Apr 20, 2024
1 parent 5b0a103 commit 827e5a3
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 66 deletions.
6 changes: 3 additions & 3 deletions examples/src/sheets/main.ts
Expand Up @@ -85,6 +85,9 @@ univer.registerPlugin(UniverDataValidationPlugin);
univer.registerPlugin(UniverSheetsDataValidationPlugin);
univer.registerPlugin(UniverSheetsFindReplacePlugin);

// sheet condition formatting
univer.registerPlugin(UniverSheetsConditionalFormattingUIPlugin);

// create univer sheet instance
univer.createUniverSheet(DEFAULT_WORKBOOK_DATA_DEMO);

Expand All @@ -93,9 +96,6 @@ univer.createUniverSheet(DEFAULT_WORKBOOK_DATA_DEMO);
// univer.__getInjector().get(IUniverInstanceService).disposeUnit(DEFAULT_WORKBOOK_DATA_DEMO.id);
// }, 5000);

// sheet condition formatting
univer.registerPlugin(UniverSheetsConditionalFormattingUIPlugin);

declare global {
interface Window {
univer?: Univer;
Expand Down
15 changes: 10 additions & 5 deletions packages/core/src/services/plugin/plugin-holder.ts
Expand Up @@ -26,12 +26,14 @@ import { type Plugin, type PluginCtor, PluginRegistry, PluginStore } from './plu

export class PluginHolder extends Disposable {
protected _started: boolean = false;
get started(): boolean { return this._started; }

protected readonly _pluginRegistered = new Set<string>();
protected readonly _pluginStore = new PluginStore();
protected readonly _pluginRegistry = new PluginRegistry();

constructor(
private readonly _immediateStart: boolean,
@ILogService protected readonly _logService: ILogService,
@Inject(Injector) protected readonly _injector: Injector,
@Inject(LifecycleService) protected readonly _lifecycleService: LifecycleService,
Expand All @@ -48,7 +50,7 @@ export class PluginHolder extends Disposable {
this._pluginRegistry.removePlugins();
}

protected _registerPlugin<T extends PluginCtor<Plugin>>(pluginCtor: T, config?: ConstructorParameters<T>[0]): void {
registerPlugin<T extends PluginCtor<Plugin>>(pluginCtor: T, config?: ConstructorParameters<T>[0]): void {
const { pluginName } = pluginCtor;
if (this._pluginRegistered.has(pluginName)) {
this._logService.warn('[PluginService]', `plugin ${pluginName} has already been registered. This registration will be ignored.`);
Expand All @@ -58,21 +60,24 @@ export class PluginHolder extends Disposable {
this._pluginRegistry.registerPlugin(pluginCtor, config);
}

_start(): void {
start(): void {
if (this._started) return;
this._started = true;

this._flush();
this.flush();
}

_flush(): void {
flush(): void {
if (!this._started) return;

const plugins = this._pluginRegistry.getRegisterPlugins().map(({ plugin, options }) => this._initPlugin(plugin, options));
this._pluginRegistry.removePlugins();

this.disposeWithMe(this._lifecycleService.subscribeWithPrevious().subscribe((stage) => {
const lifecycleSubscription = this.disposeWithMe(this._lifecycleService.subscribeWithPrevious().subscribe((stage) => {
this._pluginsRunLifecycle(plugins, stage);
if (stage === LifecycleStages.Steady) {
lifecycleSubscription.dispose();
}
}));
}

Expand Down
97 changes: 43 additions & 54 deletions packages/core/src/services/plugin/plugin.service.ts
Expand Up @@ -14,11 +14,10 @@
* limitations under the License.
*/

import type { IDisposable } from '@wendellhu/redi';
import { Inject, Injector } from '@wendellhu/redi';
import type { UniverType } from '@univerjs/protocol';
import { type UnitType, UniverInstanceType } from '../../common/unit';
import { LifecycleInitializerService, LifecycleService } from '../lifecycle/lifecycle.service';
import { LifecycleStages } from '../lifecycle/lifecycle';
import { ILogService } from '../log/log.service';
import { PluginHolder } from './plugin-holder';
import type { Plugin, PluginCtor } from './plugin';

Expand All @@ -27,42 +26,61 @@ const INIT_LAZY_PLUGINS_TIMEOUT = 200;
/**
* This service manages plugin registration.
*/
export class PluginService extends PluginHolder {
private _pluginHoldersForTypes = new Map<UnitType, PluginHolder>();
export class PluginService implements IDisposable {
private readonly _pluginHolderForUniver: PluginHolder;
private readonly _pluginHoldersForTypes = new Map<UnitType, PluginHolder>();

constructor(
@ILogService _logService: ILogService,
@Inject(Injector) _injector: Injector,
@Inject(LifecycleService) _lifecycleService: LifecycleService,
@Inject(LifecycleInitializerService) _lifecycleInitializerService: LifecycleInitializerService
@Inject(Injector) private readonly _injector: Injector
) {
super(_logService, _injector, _lifecycleService, _lifecycleInitializerService);
this._pluginHolderForUniver = this._injector.createInstance(PluginHolder, true);
}

override dispose(): void {
dispose(): void {
this._clearFlushLazyPluginsTimer();

// Dispose all plugin holders including self.
super.dispose();
for (const holder of this._pluginHoldersForTypes.values()) {
holder.dispose();
}

this._pluginHolderForUniver.dispose();
}

/** Register a plugin into univer. */
registerPlugin<T extends PluginCtor<Plugin>>(plugin: T, config?: ConstructorParameters<T>[0]): void {
this._assertPluginValid(plugin);

if (this._pluginHolderForUniver.started) {
this._scheduleInitPluginAfterStarted();
}

const { type } = plugin;
if (type === UniverInstanceType.UNIVER) {
return this._registerPlugin(plugin, config);
this._pluginHolderForUniver.registerPlugin(plugin, config);
} else {
// If it's type is for specific document, we should run them at specific time.
const holder = this._ensurePluginHolderForType(type);
holder.registerPlugin(plugin, config);
}
}

// If it's type is for specific document, we should run them at specific time.
start(): void {
this._pluginHolderForUniver.start();
}

startPluginForType(type: UniverType): void {
const holder = this._ensurePluginHolderForType(type);
holder.start();
}

// @ts-ignore
holder._registerPlugin(plugin, config);
_ensurePluginHolderForType(type: UnitType): PluginHolder {
if (!this._pluginHoldersForTypes.has(type)) {
const pluginHolder = this._injector.createInstance(PluginHolder, false);
this._pluginHoldersForTypes.set(type, pluginHolder);
return pluginHolder;
}

return this._pluginHoldersForTypes.get(type)!;
}

private _assertPluginValid(plugin: PluginCtor<Plugin>): void {
Expand All @@ -77,44 +95,14 @@ export class PluginService extends PluginHolder {
}
}

protected override _registerPlugin<T extends PluginCtor<Plugin>>(pluginCtor: T, options?: ConstructorParameters<T>[0]): void {
const { pluginName } = pluginCtor;
if (this._pluginRegistered.has(pluginName)) {
this._logService.warn('[PluginService]', `plugin ${pluginName} has already been registered. This registration will be ignored.`);
return;
}

this._pluginRegistered.add(pluginName);

if (this._started) {
this._pluginRegistry.registerPlugin(pluginCtor, options);

// If Univer has already started, we should manually call onStarting for the plugin.
// We do that in an asynchronous way, because user may lazy load several plugins at the same time.
return this._scheduleInitPluginAfterStarted();
} else {
// For plugins at Univer level. Plugins would be initialized immediately so they can register dependencies.
const pluginInstance: Plugin = this._injector.createInstance(pluginCtor, options);
this._pluginStore.addPlugin(pluginInstance);
this._pluginsRunLifecycle([pluginInstance], LifecycleStages.Starting);
}
}

_ensurePluginHolderForType(type: UnitType): PluginHolder {
if (!this._pluginHoldersForTypes.has(type)) {
const pluginHolder = this._injector.createInstance(PluginHolder);
this._pluginHoldersForTypes.set(type, pluginHolder);
return pluginHolder;
}

return this._pluginHoldersForTypes.get(type)!;
}

private _initLazyPluginsTimer?: number;
private _scheduleInitPluginAfterStarted() {
if (this._initLazyPluginsTimer === undefined) {
this._initLazyPluginsTimer = setTimeout(
() => this._flushLazyPlugins(),
() => {
this._flushLazyPlugins();
this._clearFlushLazyPluginsTimer();
},
INIT_LAZY_PLUGINS_TIMEOUT
) as unknown as number;
}
Expand All @@ -128,10 +116,11 @@ export class PluginService extends PluginHolder {
}

private _flushLazyPlugins() {
this._flush();

this._pluginHolderForUniver.flush();
for (const [_, holder] of this._pluginHoldersForTypes) {
holder._flush();
if (holder.started) {
holder.flush();
}
}
}
}
10 changes: 6 additions & 4 deletions packages/core/src/univer.ts
Expand Up @@ -111,6 +111,10 @@ export class Univer {
return this._univerInstanceService.createUnit<ISlideData, SlideDataModel>(UniverInstanceType.SLIDE, data);
}

start(): void {
this._tryProgressToStart();
}

private _init(injector: Injector): void {
this._univerInstanceService.registerCtorForType(UniverInstanceType.SHEET, Workbook);
this._univerInstanceService.registerCtorForType(UniverInstanceType.DOC, DocumentDataModel);
Expand All @@ -122,11 +126,9 @@ export class Univer {
this._tryProgressToStart();

if (!this._startedTypes.has(type)) {
this._pluginService.startPluginForType(type);
this._startedTypes.add(type);

const pluginHolder = this._pluginService._ensurePluginHolderForType(type);
pluginHolder._start();

const model = injector.createInstance(ctor, data);
univerInstanceService.__addUnit(model);

Expand All @@ -143,7 +145,7 @@ export class Univer {
}

private _tryProgressToStart(): void {
this._pluginService._start();
this._pluginService.start();
}

private _tryProgressToReady(): void {
Expand Down

0 comments on commit 827e5a3

Please sign in to comment.