refactor: inject an instance of typescript-vfs.worker

Modified tsVfsWorker worker initialization logic
This commit is contained in:
aparziale
2025-10-25 10:10:10 +02:00
committed by Kristiyan Kostadinov
parent a03c82564d
commit e155a1e9d7
4 changed files with 53 additions and 8 deletions
+2
View File
@@ -32,6 +32,7 @@ import {ContentLoader} from './core/services/content-loader.service';
import {CustomErrorHandler} from './core/services/errors-handling/error-handler';
import {ExampleContentLoader} from './core/services/example-content-loader.service';
import {routerProviders} from './routing/router_providers';
import {TYPESCRIPT_VFS_WORKER_PROVIDER} from './editor/code-editor/workers/factory-provider';
export const appConfig: ApplicationConfig = {
providers: [
@@ -51,5 +52,6 @@ export const appConfig: ApplicationConfig = {
useFactory: (document: Document) => windowProvider(document),
deps: [DOCUMENT],
},
TYPESCRIPT_VFS_WORKER_PROVIDER,
],
};
@@ -17,6 +17,7 @@ import {EmbeddedTutorialManager} from '../embedded-tutorial-manager.service';
import {CodeMirrorEditor, EDITOR_CONTENT_CHANGE_DELAY_MILLIES} from './code-mirror-editor.service';
import {TutorialConfig, TutorialMetadata} from '@angular/docs';
import {TYPESCRIPT_VFS_WORKER_FACTORY} from './workers/factory-provider';
class FakeNodeRuntimeSandbox {
async writeFile(path: string, content: string) {}
@@ -64,8 +65,16 @@ export class FakeEmbeddedTutorialManager {
}
}
class MockWorker {
addEventListener = jasmine.createSpy('addEventListener');
postMessage = jasmine.createSpy('postMessage');
removeEventListener = jasmine.createSpy('removeEventListener');
terminate = jasmine.createSpy('terminate');
}
describe('CodeMirrorEditor', () => {
let service: CodeMirrorEditor;
let mockWorker: MockWorker;
const fakeNodeRuntimeSandbox = new FakeNodeRuntimeSandbox();
const fakeEmbeddedTutorialManager = new FakeEmbeddedTutorialManager();
@@ -80,6 +89,8 @@ describe('CodeMirrorEditor', () => {
}
beforeEach(() => {
mockWorker = new MockWorker();
TestBed.configureTestingModule({
providers: [
CodeMirrorEditor,
@@ -87,6 +98,10 @@ describe('CodeMirrorEditor', () => {
provide: NodeRuntimeSandbox,
useValue: fakeNodeRuntimeSandbox,
},
{
provide: TYPESCRIPT_VFS_WORKER_FACTORY,
useValue: () => mockWorker as unknown as Worker,
},
{
provide: EmbeddedTutorialManager,
useValue: fakeEmbeddedTutorialManager,
@@ -29,6 +29,7 @@ import {TsVfsWorkerActions} from './workers/enums/actions';
import {CodeChangeRequest} from './workers/interfaces/code-change-request';
import {ActionMessage} from './workers/interfaces/message';
import {NodeRuntimeState} from '../node-runtime-state.service';
import {TYPESCRIPT_VFS_WORKER_FACTORY} from './workers/factory-provider';
export interface EditorFile {
filename: string;
@@ -71,7 +72,6 @@ export class CodeMirrorEditor {
// An instance of web worker used to run virtual TypeScript environment in the browser.
// It allows to enrich CodeMirror UX for TypeScript files.
private tsVfsWorker: Worker | null = null;
// EventManager gives ability to communicate between tsVfsWorker and CodeMirror instance
private readonly eventManager$ = new Subject<ActionMessage>();
@@ -81,6 +81,8 @@ export class CodeMirrorEditor {
private readonly typingsLoader = inject(TypingsLoader);
private readonly destroyRef = inject(DestroyRef);
private readonly diagnosticsState = inject(DiagnosticsState);
private readonly tsVfsWorkerFactory = inject(TYPESCRIPT_VFS_WORKER_FACTORY);
private tsVfsWorker: Worker | null = null;
private _editorView: EditorView | null = INITIAL_STATES._editorView;
private readonly _editorStates = new Map<EditorFile['filename'], EditorState>();
@@ -182,14 +184,11 @@ export class CodeMirrorEditor {
}
private initTypescriptVfsWorker(): void {
if (this.tsVfsWorker) {
if (this.tsVfsWorker || !this.tsVfsWorkerFactory) {
return;
}
this.tsVfsWorker = new Worker(new URL('./workers/typescript-vfs.worker', import.meta.url), {
type: 'module',
});
this.tsVfsWorker = this.tsVfsWorkerFactory();
this.tsVfsWorker.addEventListener('message', ({data}: MessageEvent<ActionMessage>) => {
this.eventManager$.next(data);
});
@@ -214,10 +213,13 @@ export class CodeMirrorEditor {
// Method is responsible for sending request to Typescript VFS worker.
private sendRequestToTsVfs = <T>(request: ActionMessage<T>) => {
if (!this.tsVfsWorker) return;
if (!this.tsVfsWorker) {
console.warn('TypeScript VFS worker not available');
return;
}
// Send message to tsVfsWorker only when current file is TypeScript file.
if (!this.currentFile().filename.endsWith('.ts')) return;
if (!this.currentFile()?.filename.endsWith('.ts')) return;
this.tsVfsWorker.postMessage(request);
};
@@ -0,0 +1,26 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {InjectionToken, Provider} from '@angular/core';
export type TypescriptVfsWorkerFactory = () => Worker;
export const TYPESCRIPT_VFS_WORKER_FACTORY = new InjectionToken<TypescriptVfsWorkerFactory>(
'TYPESCRIPT_VFS_WORKER_FACTORY',
);
export function createTypescriptVfsWorker(): Worker {
return new Worker(new URL('./typescript-vfs.worker.ts', import.meta.url), {
type: 'module',
});
}
export const TYPESCRIPT_VFS_WORKER_PROVIDER: Provider = {
provide: TYPESCRIPT_VFS_WORKER_FACTORY,
useValue: createTypescriptVfsWorker,
};