最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vscode 是怎么跑起来的

    正文概述 掘金(zxg_神说要有光)   2021-07-22   571

    vscode 是前端工程师常用的 ide,而且它的实现也是基于前端技术。既然是前端技术实现的,那么我们用所掌握的前端技术,完全可以实现一个类似 vscode 的 ide。但在那之前,我们首先还是要把 vscode 是怎么实现的理清楚。本文我们就来理一下 vscode 是怎么跑起来的。

    首先, vscode 是一个 electron 应用,窗口等功能的实现基于 electron,所以想梳理清楚 vscode 的启动流程,需要先了解下 electron。

    electron

    electron 基于 node 和 chromium 做 js 逻辑的执行和页面渲染,并且提供了 BrowserWindow 来创建窗口,提供了 electron 包的 api,来执行一些操作系统的功能,比如打开文件选择窗口、进程通信等。

    每个 BrowserWindow 窗口内的 js 都跑在一个渲染进程,而 electron 有一个主进程,负责和各个窗口内的渲染进程通信。

    vscode 是怎么跑起来的

    如图所示,主进程可以使用 nodejs 的 api 和 electron 提供给主进程的 api,渲染进程可以使用浏览器的 api、nodejs 的 api 以及 electron 提供给渲染进程的 api,除此以外,渲染进程还可以使用 html 和 css 来做页面的布局。

    vscode 的每个窗口就是一个 BrowserWindow,我们启动 vscode 的时候是启动的主进程,然后主进程会启动一个 BrowserWindow 来加载窗口的 html,这样就完成的 vscode 窗口的创建。(后续新建窗口也是一样的创建 BrowserWindow,只不过要由渲染进程通过 ipc 通知主进程,然后主进程再创建 BrowserWindow,不像第一次启动窗口直接主进程创建 BrowserWindow 即可。)

    vsocde 窗口启动流程

    我们知道 vscode 基于 electron 来跑,electron 会加载主进程的 js 文件,也就是 vscode 的 package.json 的 main 字段所声明的 ./out/main.js,我们就从这个文件开始看。

    src/main

    (下面的代码都是我从源码简化来的,方便大家理清思路)

    // src/main.js
    const { app } = require('electron');
    
    app.once('ready', onReady);
    
    async function onReady() {
        try {
            startup(xxxConfig);
        } catch (error) {
            console.error(error);
        }
    }
    
    function startUp() {
        require('./bootstrap-amd').load('vs/code/electron-main/main');
    }
    

    可以看到,./src/main.js 里面只是一段引导代码,在 app 的 ready 事件时开始执行入口 js。也就是 vs/code/electron-main/main,这是主进程的入口逻辑。

    CodeMain

    // src/vs/code/electron-main/main.ts
    class CodeMain {
        main(): void {
            try {
                this.startup();
            } catch (error) {
                console.error(error.message);
                app.exit(1);
            }
        }
        private async startup(): Promise<void> {
            // 创建服务
            const [
                instantiationService, 
                instanceEnvironment,
                environmentMainService,
                configurationService,
                stateMainService
            ] = this.createServices();
            
            // 初始化服务
            await this.initServices();
            
            // 启动
            await instantiationService.invokeFunction(async accessor => {
                //创建 CodeApplication 的对象,然后调用 startup
                return instantiationService.createInstance(CodeApplication).startup();
            });
    
        }
    }
    
    const code = new CodeMain();
    code.main();
    

    可以看到,vscode 创建了 CodeMain 的对象,这个是入口逻辑的开始,也是最根上的一个类。它创建和初始化了一些服务,然后创建了 CodeApplication 的对象。

    也许你会说,创建对象为啥不直接 new,还要调用 xxx.invokeFunction() 和 xxx.createInstance() 呢?

    这是因为 vscode 实现了 ioc 的容器,也就是在这个容器内部的任意对象都可以声明依赖,然后由容器自动注入。

    本来是直接依赖,但是通过反转成注入依赖的方式,就避免了耦合,这就是 ioc (invert of control)的思想,或者叫 di(dependency inject)。

    这个 CodeApplication 就是 ioc 容器。 vscode 是怎么跑起来的

    CodeApplication

    //src/vs/code/electron-main/app.ts
    
    export class CodeApplication {
    
        // 依赖注入
        constructor(
            @IInstantiationService private readonly mainInstantiationService: IInstantiationService,
            @IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService
        ){
            super();
        }
        
        async startup(): Promise<void> {
            const mainProcessElectronServer = new ElectronIPCServer();
            this.openFirstWindow(mainProcessElectronServer)
        }
        
        private openFirstWindow(mainProcessElectronServer: ElectronIPCServer): ICodeWindow[] {
            this.windowsMainService.open({...});
        }
    }
    
    

    CodeApplication 里面通过装饰器的方式声明依赖,当通过容器创建实例的时候会自动注入声明的依赖。

    startup 里面启动了第一个窗口,也就是渲染进程,因为主进程和渲染进程之间要通过 ipc 通信,所以还会创建一个 ElectronIPCServer 的实例(其实它只是对 ipc 通信做了封装)。

    最终通过 windowMainService 的服务创建了窗口。

    虽然比较绕,但是通过 service 和 ioc 的方式,能够更好的治理复杂度,保证应用的架构不会越迭代越乱。

    然后我们来看具体的窗口创建逻辑。

    windowMainService

    //src/vs/platform/windows/electron-main/windowsMainService.ts
    
    export class WindowsMainService {
        
        open(openConfig): ICodeWindow[] {
           this.doOpen(openConfig);
        }
        
        doOpen(openConfig) {
            this.openInBrowserWindow();
        }
        
        openInBrowserWindow(options) {
            // 创建窗口
            this.instantiationService.createInstance(CodeWindow);
        }
    }
    

    在 windowMainService 里面最终创建了 CodeWindow 的实例,这就是对 BrowserWindow 的封装,也就是 vscode 的窗口。(用 xxx.createIntance 创建是因为要受 ioc 容器管理)

    CodeWindow

    //src/vs/platform/windows/electron-main/window.ts
    import { BrowserWindow } from 'electron';
    
    export class CodeWindow {
        constructor() {
            const options = {...};
            this._win = new BrowserWindow(options);
            this.registerListeners();
            this._win.loadURL('vs/code/electron-browser/workbench/workbench.html');
        }
    }
    

    CodeWindow 是对 electron 的 BrowserWindow 的封装,就是 vscode 的 window 类。

    它创建 BrowserWindow 窗口,并且监听一系列窗口事件,最后加载 workbench 的 html。这就是 vscode 窗口的内容,也就是我们平时看到的 vscode 的部分。

    至此,我们完成了 electron 启动到展示第一个 vscode 窗口的逻辑,已经能够看到 vscode 的界面了。

    总结

    vscode 是怎么跑起来的

    vscode 是基于 electron 做窗口的创建和进程通信的,应用启动的时候会跑主进程,从 src/main 开始执行,然后创建 CodeMain 对象。

    CodeMain 里会初始化很多服务,然后创建 CodeApplication,这是 ioc 的实现,全局唯一。对象的创建由容器来管理,里面所有的对象都可以相互依赖注入。

    最开始会先通过 windowMainSerice 服务来创建一个 CodeWindow 的实例,这就是窗口对象,是对 electron 的BrowserWindow 的封装。

    窗口内加载 workbench.html,这就是我们看到的 vscode 的界面。

    vscode 就是通过这样的方式来基于 electron 实现了窗口的创建和界面的显示,感兴趣的可以参考本文去看下 vscode 1.59.0 的源码,是能学到很多架构方面的东西的,比如 ioc 容器来做对象的统一管理,通过各种服务来管理各种资源,这样集中管理的方式使得架构不会越迭代越乱,复杂度得到了很好的治理,此外,学习 vscode 源码也能够提升对 electron 的掌握。


    起源地下载网 » vscode 是怎么跑起来的

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元