diff --git a/blocksuite/affine/blocks/code/src/code-block-service.ts b/blocksuite/affine/blocks/code/src/code-block-service.ts index b101fe8b0..5a309cd93 100644 --- a/blocksuite/affine/blocks/code/src/code-block-service.ts +++ b/blocksuite/affine/blocks/code/src/code-block-service.ts @@ -19,8 +19,12 @@ import { export class CodeBlockHighlighter extends LifeCycleWatcher { static override key = 'code-block-highlighter'; - private _darkThemeKey: string | undefined; + // Singleton highlighter instance + private static _sharedHighlighter: HighlighterCore | null = null; + private static _highlighterPromise: Promise | null = null; + private static _refCount = 0; + private _darkThemeKey: string | undefined; private _lightThemeKey: string | undefined; highlighter$: Signal = signal(null); @@ -44,18 +48,45 @@ export class CodeBlockHighlighter extends LifeCycleWatcher { this.highlighter$.value = highlighter; }; + private static async _getOrCreateHighlighter(): Promise { + if (CodeBlockHighlighter._sharedHighlighter) { + return CodeBlockHighlighter._sharedHighlighter; + } + + if (!CodeBlockHighlighter._highlighterPromise) { + CodeBlockHighlighter._highlighterPromise = createHighlighterCore({ + engine: createOnigurumaEngine(() => getWasm), + }).then(highlighter => { + CodeBlockHighlighter._sharedHighlighter = highlighter; + return highlighter; + }); + } + + return CodeBlockHighlighter._highlighterPromise; + } + override mounted(): void { super.mounted(); - createHighlighterCore({ - engine: createOnigurumaEngine(() => getWasm), - }) + CodeBlockHighlighter._refCount++; + + CodeBlockHighlighter._getOrCreateHighlighter() .then(this._loadTheme) .catch(console.error); } override unmounted(): void { - this.highlighter$.value?.dispose(); + CodeBlockHighlighter._refCount--; + + // Only dispose the shared highlighter when no instances are using it + if ( + CodeBlockHighlighter._refCount === 0 && + CodeBlockHighlighter._sharedHighlighter + ) { + CodeBlockHighlighter._sharedHighlighter.dispose(); + CodeBlockHighlighter._sharedHighlighter = null; + CodeBlockHighlighter._highlighterPromise = null; + } } } diff --git a/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts b/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts index b60216a62..3ec05e1d8 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/text-renderer.ts @@ -4,7 +4,7 @@ import { getViewManager } from '@affine/core/blocksuite/manager/view'; import type { FeatureFlagService } from '@affine/core/modules/feature-flag'; import { PeekViewProvider } from '@blocksuite/affine/components/peek'; import { Container, type ServiceProvider } from '@blocksuite/affine/global/di'; -import { WithDisposable } from '@blocksuite/affine/global/lit'; +import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit'; import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference'; import { codeBlockWrapMiddleware, @@ -106,7 +106,9 @@ export type TextRendererOptions = { }; // todo: refactor it for more general purpose usage instead of AI only? -export class TextRenderer extends WithDisposable(ShadowlessElement) { +export class TextRenderer extends SignalWatcher( + WithDisposable(ShadowlessElement) +) { static override styles = css` .ai-answer-text-editor.affine-page-viewport { background: transparent; diff --git a/packages/frontend/core/src/components/comment/sidebar/style.css.ts b/packages/frontend/core/src/components/comment/sidebar/style.css.ts index ad5715a46..a80923de3 100644 --- a/packages/frontend/core/src/components/comment/sidebar/style.css.ts +++ b/packages/frontend/core/src/components/comment/sidebar/style.css.ts @@ -20,7 +20,7 @@ export const header = style({ height: '40px', position: 'sticky', top: 0, - backgroundColor: cssVarV2('layer/background/overlayPanel'), + backgroundColor: cssVarV2('layer/background/primary'), zIndex: 2, });