学习
实践
活动
工具
TVP
写文章
专栏首页liulunvscode源码分析【二】程序的启动逻辑,第一个窗口是如何创建的

vscode源码分析【二】程序的启动逻辑,第一个窗口是如何创建的

我们在package.json里能找到他的入口文件;

"main": "./out/main",

electron是分主进程和渲染进程的; 渲染进程是主进程启动的; ./out/main.js显然这就是主进程的入口程序; 确实不假 但别着急去分析这个文件; 因为它是在out目录下,明显是什么东西输出出来的; 我们先打扫一遍src目录下的东西; 发现了tsconfig.json

"outDir": "../out",

哈,这是typescript代码,编译后输出到./out/目录下的; 那么我们来看src下的main.js 分析代码最主要的就是目的明确,我们的目的是看看他的启动逻辑(主窗口是怎么打开的) 无关的东西先不管,要不然很容易迷失...; 我们在main.js里找electron的ready事件

app.once('ready', function () {
	if (args['trace']) {
		// @ts-ignore
		const contentTracing = require('electron').contentTracing;

		const traceOptions = {
			categoryFilter: args['trace-category-filter'] || '*',
			traceOptions: args['trace-options'] || 'record-until-full,enable-sampling'
		};

		contentTracing.startRecording(traceOptions, () => onReady());
	} else {
		onReady();
	}
});

先去看onReady方法 onReady里主要就是执行这个方法:

const startup = 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');
				});
			};

到这里,我们先看看bootstrap-amd都干了啥 发现他其实调用了/vs/loader里的方法(下面这行代码里面entrypoint就是:vs/code/electron-main/main)

loader([entrypoint], onLoad, onError);

loader是微软自家的AMD模块加载开源项目:https://github.com/Microsoft/vscode-loader/ 没啥好说的,我们接着来看vs/code/electron-main/main.ts的代码, 发现它一开始就加载了一大堆模块,头大! 先不管它加载的这些模块都是干嘛的,我们看它本身的入口,代码拉到末尾,发现:

    const code = new CodeMain();
    code.main();

马上去看这个模块的main函数;发现main函数对于我们唯一有用的就是:

this.startup(args);

这个函数启动了一堆服务之后,就执行了:

const mainIpcServer = yield this.doStartup(logService, environmentService, lifecycleService, instantiationService, true);

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

我们先看第一行,在doStartup里,只有这行代码看起来有用:

server = await serve(environmentService.mainIPCHandle);

serve是上面加载的那一大堆模块之一:vs/base/parts/ipc/node/ipc.net 发现它的serve其实就是启动了一个服务:

    function serve(hook) {
        return new Promise((c, e) => {
            const server = net_1.createServer();
            server.on('error', e);
            server.listen(hook, () => {
                server.removeListener('error', e);
                c(new Server(server));
            });
        });
    }

对我们目前的分析,帮助不大! 我们再返回头看第二行代码: instantiationService.ts在vs/platform/instantiation/common/instantiationService.ts 他的createInstance是个工厂函数,第一个参数是类型(或构造函数),后面的参数都是这个类型的构造函数所需要的参数。 那么我们主要看第一个参数CodeApplication,这个类型的代码在这里:vs/code/electron-main/app.ts 我们找到CodeApplication的startup方法,看到这一句:

// Open Windows
		const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));

这应该就是我们找的启动主窗口的方法了,跟进去看看: 一开始是一大堆IPC通信相关的代码(主线程和渲染线程通信的代码) 之后创建了IWindowsMainservice的实例

const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);

然后用这个实例创建了窗口

		return windowsMainService.open({
			context,
			cli: args,
			forceNewWindow: args['new-window'] || (!hasCliArgs && args['unity-launch']),
			diffMode: args.diff,
			noRecentEntry,
			waitMarkerFileURI,
			initialStartup: true
		});

IWindowsMainservice接口具体实例的类型是WindowsManager(可以在app.ts文件中找到下面的代码)

services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv]));

(IWindowsMainservice接口的描述文件在这里:vs\platform\windows\electron-main\windows.ts) WindowsManager在vs/code/electron-main/windows.ts文件中定义, 那我们去看看WindowsManager的open方法,发现了:

const usedWindows = this.doOpen(openConfig, workspacesToOpen, foldersToOpen, emptyToRestore, emptyToOpen, fileInputs, foldersToAdd);

好,再去看doOpen,发现最后的:

			// Finally, if no window or folder is found, just open the files in an empty window
			else {
				usedWindows.push(this.openInBrowserWindow({
					userEnv: openConfig.userEnv,
					cli: openConfig.cli,
					initialStartup: openConfig.initialStartup,
					fileInputs,
					forceNewWindow: true,
					remoteAuthority: fileInputs.remoteAuthority,
					forceNewTabbedWindow: openConfig.forceNewTabbedWindow
				}));

				// Reset these because we handled them
				fileInputs = undefined;
			}

注意:这两个方法有一个重要的逻辑就是:如果已经有一个窗口了,那么就用现成的窗口打开目录(或文件) 再去看openInBrowserWindow

// Create the window
			window = this.instantiationService.createInstance(CodeWindow, {
				state,
				extensionDevelopmentPath: configuration.extensionDevelopmentPath,
				isExtensionTestHost: !!configuration.extensionTestsPath
			});

它创建了一个CodeWindow的实例,这个类型在:vs/code/electron-main/window.ts中定义 这个类型的构造函数里调用了这个方法:

this.createBrowserWindow(config);

在这个方法里完成了窗口的创建:

// Create the browser window.
		this._win = new BrowserWindow(options);

至此:VSCode窗口创建出来了

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!
本文分享自作者个人站点/博客:http://www.cnblogs.com/liulun/复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • vscode源码分析【四】程序启动的逻辑,最初创建的服务

    在第一节中提到的startup函数里(src\vs\code\electron-main\main.ts) 有一个createServices的调用:

    liulun
  • vscode源码分析【三】程序的启动逻辑,性能问题的追踪

    代码文件:src\main.js 如果指定了特定的启动参数:trace vscode会在启动之初,执行下面的代码:

    liulun
  • vscode 是怎么跑起来的

    vscode 是前端工程师常用的 ide,而且它的实现也是基于前端技术。既然是前端技术实现的,那么我们用所掌握的前端技术,完全可以实现一个类似 vscode 的...

    公众号@魔术师卡颂
  • 一次关于Flutter的碰壁 | VSCode中搭建开发环境(插件 | 虚拟机 | 新建项目并运行)

    到桌面--右键“此电脑”--点击属性--高级系统设置--环境变量--系统变量栏--点击Path,新建一个环境变量,把刚刚复制的路径加进来--确定--确定-...

    凌川江雪
  • Python玩数据入门必备系列(2):vs code 写 Python

    > 最近有许多小伙伴问我要入门 Python 的资料,还有小伙伴完全没有入门 Python 就直接购买了我的 pandas 专栏。因此我决定写几篇 Python...

    咋咋
  • 从 VSCode 看大型 IDE 技术架构

    为什么要去看 VSCode?因为我们团队在做的中后台快速研发平台云凤蝶也是一款类似 Web IDE 形态的产品:

    Nealyang
  • Python玩数据入门必备系列(2):vs code 写 Python

    VS Code好强大,最近看了一些推文发现,有1万+的插件生态,你看,连Jupter Note Book都有了,看来我也要花些时间来玩玩VS Code了。

    Excel催化剂
  • 你会在本地搭建 Web 版 VS Code 吗,看完这一篇你就能轻松实现了!

    Visual Studio Code 是微软推出的一款轻量级编辑器,与它一起在市场争锋的相似软件还有 Atom 和 Sublime Text,面世第二年的它只占...

    iMike
  • .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

    上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着带着你一步一步的配置了.NET Core的开发环境并创建了一个ASP.NET Core的...

    依乐祝
  • .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

    上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着带着你一步一步的配置了.NET Core的开发环境并创建了一个ASP.NET Core的...

    依乐祝
  • 官网教程中文极简版: vs code的C++环境配置

    中间会让你多次选择y/n,选择y进行安装即可,最后一次输入y,窗口会消失,从开始菜单中找到MSYS2,然后再次打开,运行如下命令更新剩下的基本包:

    用户9875047
  • VS Code 源码分析 - 多语言实现

    传统前端 App 多语言最简单的实现可以由一套响应式数据流管理系统来托管多语言文案,切换语言时通过数据流的变化使得界面根据文案重新渲染。但由于 VS Code ...

    刘小夕
  • Anaconda+VSCode配置tensorflow开发环境的教程详解

    Anaconda是一个开源的python发行版本,是现在比较流行的python数据科学平台,可以对python的科学包做到有效管理。在配置python开发环境时...

    砸漏
  • 让你 nodejs 水平暴增的 debugger 技巧

    我觉得学习 nodejs 除了要掌握基础的 api、常用的一些包外,最重要的能力是学会使用 debugger。因为当流程复杂的时候,断点调试能够帮你更好的理清逻...

    刘小夕
  • VsCode设置ESP32工具链+刨根问底点灯

    ESP-IDF扩展使您可以轻松开发,构建,刷新,监视和调试ESP-IDF代码,其中一些功能包括:

    云深无际
  • Python升级之路( Lv1 ) Python 入门

    最近打算新开一个坑, 但一直不知道做什么合适, 直到最近在看 《UNIX/Linux系统管理技术手册》 这一书的 脚本编程与shell 这一章节中得到启发, 书...

    时间静止不是简史
  • PYQT5 vscode联合操作qtdesigner的方法

    通过pycharm生成的为一个和designer一样的py文件,如上图中第二个文件。通过vscode生成的是以Ui_开头的一个py文件。

    砸漏
  • 如何阅读源码 —— 以 Vetur 为例

    我很早就意识到,能熟练、高效阅读开源前端框架源码是成为一个高级前端工程师必须具备的基本技能之一,所以在我职业生涯的最早期,就已经开始做了很多次相关的尝试,但结果...

    Tecvan

扫码关注腾讯云开发者

领取腾讯云代金券