上一篇文章:https://www.cnblogs.com/liulun/
(小广告:我做的开源免费的,个人知识管理及自媒体营销工具“想学吗”:https://github.com/xland/xiangxuema

我们在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窗口创建出来了

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

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

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 启动追踪 代码文件:src\main.js 如果指定了特定的启动参 ...

  2. vscode源码分析【七】主进程启动消息通信服务

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

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

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  4. vscode源码分析【九】窗口里的主要元素

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  5. vscode源码分析【八】加载第一个画面

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  6. vscode源码分析【六】服务实例化和单例的实现

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  7. vscode源码分析【五】事件分发机制

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  8. Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析

    Tomcat启动加载过程(一)的源码解析 今天,我将分享用源码的方式讲解Tomcat启动的加载过程,关于Tomcat的架构请参阅<Tomcat源码分析二:先看看Tomcat的整体架构>一文 ...

  9. SpringBoot源码分析之SpringBoot的启动过程

    SpringBoot源码分析之SpringBoot的启动过程 发表于 2017-04-30   |   分类于 springboot  |   0 Comments  |   阅读次数 SpringB ...

  10. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

随机推荐

  1. Android 时间对话框 TimePickerDialog

    private int hourOfDay, minute; @Override protected void onCreate(Bundle savedInstanceState) { super. ...

  2. Vue-Cli 3.0 中配置高德地图

    vue 中使用高德地图有两种方式 一.vue-amap 组件 官网: https://elemefe.github.io/vue-amap/#/ 开始的时候是打算用这个组件做地图功能的,但是尝试之后存 ...

  3. Linux(Centos7)下Mysql的安装

    1.1 查看mysql的安装路径: [root@bogon ~]# whereis mysql mysql: /usr/bin/mysql /usr/lib/mysql /usr/share/mysq ...

  4. docker alphine 设置系统日期

    设置时区为上海 RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && ...

  5. 检测服务器是否开启重协商功能(用于CVE-2011-1473漏洞检测)

    背景 由于服务器端的重新密钥协商的开销至少是客户端的10倍,因此攻击者可利用这个过程向服务器发起拒绝服务攻击.OpenSSL 1.0.2及以前版本受影响. 方法 使用OpenSSL(linux系统基本 ...

  6. 查看/运行jpynb文件

    Windows OS:安装好pip包,能使用pip进行安装第三方包. cmd命令行: pip install jupyter jupyter notebook cd (xx.jpynb文件所在文件夹) ...

  7. ResultSet RS_resultxtgg=connDbBean.executeQuery(sqlxtgg);

    <%String sqlxtgg="select * from dx where leibie='系统公告'"; ResultSet RS_resultxtgg=connDb ...

  8. SpringBoot条件注解的总结

    https://blog.csdn.net/qq_31142553/article/details/86439950

  9. Tomcat9+JDK 13报错Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable is needed to run this program

    Tomcat使用的是https://tomcat.apache.org/download-90.cgi Tomcat9 之前安装的JDK 13,有JAVA_HOME环境变量地址(C:\Program ...

  10. vue事件监听机制

    vue事件是同步的.如果绑定了事件(组件标签上绑定事件) 组件的事件触发 组件调用时绑定事件 之后监听事件: $emit 抛出后活等着 $on ,如果监听到了则阻塞执行: 如果为监听到或者未绑定,则会 ...