认识vscode二

46次阅读

共计 3611 个字符,预计需要花费 10 分钟才能阅读完成。

前一篇文章简单的介绍了一下 vscode 源码结构. 这次我们来了解一下 vscode 的运行流程. 下一篇文章我们则切换主题的小案例来深入了解 vscode.

首先入口文件是 main.js, 这个相信大部分人都知道. 那么我们来看看 main.js 的源码. 这里相当于运行的是 electron 的主进程. 这里做了一些初始化操作以后 (设置 schemes, 初始化一些全局配置比如编辑器工作路径) 就调用 startup 函数来 loading vs/code/electron-main/main.ts

function startup(cachedDataDir, nlsConfig) {
    nlsConfig._languagePackSupport = true;

    process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig);
    process.env['VSCODE_NODE_CACHED_DATA_DIR'] = cachedDataDir || '';

    // Load main in AMD
    perf.mark('willLoadMainBundle');
    require('./bootstrap-amd').load('vs/code/electron-main/main', () => {perf.mark('didLoadMainBundle');
    });
}

electron-main/main.ts 则会先初始化一些基础服务

    private createServices(args: ParsedArgs, bufferLogService: BufferLogService): [IInstantiationService, IProcessEnvironment] {const services = new ServiceCollection();

        const environmentService = new EnvironmentService(args, process.execPath);
        const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment
        services.set(IEnvironmentService, environmentService);

        const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
        process.once('exit', () => logService.dispose());
        services.set(ILogService, logService);

        services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource));
        services.set(ILifecycleMainService, new SyncDescriptor(LifecycleMainService));
        services.set(IStateService, new SyncDescriptor(StateService));
        services.set(IRequestService, new SyncDescriptor(RequestMainService));
        services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
        services.set(ISignService, new SyncDescriptor(SignService));

        return [new InstantiationService(services, true), instanceEnvironment];
    }

然后创建 ipcServer 把接力棒交给 app.ts

            
            // Startup
            await instantiationService.invokeFunction(async accessor => {const environmentService = accessor.get(IEnvironmentService);
                const logService = accessor.get(ILogService);
                const lifecycleMainService = accessor.get(ILifecycleMainService);
                const configurationService = accessor.get(IConfigurationService);

                const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleMainService, instantiationService, true);

                bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
                once(lifecycleMainService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose());

                return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();});

这里我们先了解到 instantiationService. 后续我们就经常接触整个服务. 这可以理解成是 vscode 实现 DI 的容器. 通过调用 instantiationService.createInstance 创建的对象, 对象 constructor 内使用装饰器声明了需要注入的 service 类型. 则 instantistionService 会自动将已有的 service 注入

main.ts

return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();

app.ts constructor

    constructor(
        private readonly mainIpcServer: Server,
        private readonly userEnv: IProcessEnvironment,
        @IInstantiationService private readonly instantiationService: IInstantiationService,
        @ILogService private readonly logService: ILogService,
        @IEnvironmentService private readonly environmentService: IEnvironmentService,
        @ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
        @IConfigurationService private readonly configurationService: IConfigurationService,
        @IStateService private readonly stateService: IStateService
    ) {super();

        this.registerListeners();}

app.ts 在最后会调用 window.ts 中的 open 函数来打开一个 vscode 窗口. 每个 window 窗口都会打开 workbench.html 用来渲染我们所看到的整个 vscode 界面.

    private doGetUrl(config: object): string {return `${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`;
    }

今天的分享就到这里. 明天我们就来通过实现切换主题 (dark mode) 来深入了解 workbench 的逻辑。

正文完
 0