近期准备开始做electron
相关的开发工作,因此借着这个机会就再去了解下electron
。在很久以前的文章中有稍微玩过electron+react+antd
的脚手架,但也只限于快速开发electron
应用,并没有去剖析整个项目结构。因此这次,还是得深入一下。
先前一段时间特别喜欢用开源的Motrix下载器,就是基于electron+vue+aria2
去实现的,所以索性就把源码给clone
了下来。本文就从最基础的开始,以Motrix
的启动逻辑为入口,来研究下一个electron
应用是如何打开的。
首先看一下Motrix
的目录结构,源码基本在src
下,呈现这样的层级关系:
main
:主进程,应用内部逻辑configs
:内部环境配置core
:软件核心管理逻辑menus
:不同os
下的菜单配置pages
:基础页面ui
:各ui
相关的Manager
逻辑utils
:工具方法库Application.js
:应用入口Launcher.js
:启动器入口index.js/index.dev.js
:程序入口index.dev.js
相对于index.js
只是另外安装了devtools
renderer
:渲染进程,vue
页面逻辑,目录结构也是vue
默认的,可以参考这篇文章api
:外部接口assets
:资源文件components
:组件页面pages
:应用页面入口,App.vue+main.js
router
:路由store
:应用内部数据utils
:工具方法库workers
:只有一个tray.worker.js
用来绘制托盘icon
shared
:公用逻辑/工具aria2
:下载工具jslib
locales
:本地化utils
:公用js
工具方法库
从MVC
的角度,main
主进程的逻辑相当于是model
,renderer
渲染进程的逻辑相当于是view
,而至于controller
,可以通过electron
支持下的两个进程的ipc
事件处理机制来呈现。这一点,我们直接看启动逻辑就能明白。
运行yarn run dev
,会启动.election-vue/dev-runner.js
,其中会先初始化renderer
和main
,然后再启动electron
1 | // .election-vue/dev-runner.js |
在startRenderer
和startMain
中会读取js
配置的程序入口,编译后运行。两个进程的入口entry
分别是:
- 渲染进程:
src/pages/index/main.js
- 主进程:
src/main/index.dev.js
首先看渲染进程,运行的入口在这里:
1 | store.dispatch('preference/fetchPreference') |
首先会通过preference/fetchPreference
这个action
来获得应用配置,然后调用init
函数启动界面。先看获取配置的逻辑:
1 | // src/renderer/store/modules/preferences.js |
可以看到最终获取配置的逻辑落到ipcRenderer.invoke('get-app-config')
。ipcRenderer
相当于是渲染进程里进程间(与Main
主进程)通信的handle
,这里相当于是向主进程invoke
了一个get-app-config
事件。在主进程端的ipcMain
可以注册这个事件的监听,然后返回对应的数据。ipcRenderer
和ipcMain
的通信,可以查看这两个文档:
- ipcRenderer模块
- ipcMain模块
到这里就暂停,看下主进程的启动,主进程index.js
会启用一个Launcher
来开始主进程逻辑
1 | // src/main/index.js |
主进程启动逻辑最终落到这handleAppEvents
里面四个handler
,分别是如下作用:
handleAppReady
:监听ready
事件,初始化Application
实例(global.application
)并为其注册监听事件;监听activate
事件,打开index
页面handleOpenUrl
:监听open-url
事件,发送url
给Application
handleOpenFile
:监听open-file
事件,发送file
给Application
handleAppWillQuit
:监听will-quit
事件,停止Application
election-app
的一系列事件,可以在这个网站查阅具体作用
接下来看下Application
实例的初始化:
1 | // src/main/Application.js |
其他的先不说,在handleIpcInvokes
里面注册了get-app-config
的handler
,逻辑如下:
1 | // src/main/Application.js |
这里用了electron-store
持久化用户配置,详情参考这个链接
最终给到渲染进程的config
,就是systemConfig
和userConfig
合并的结果,因此可以再转到渲染进程查看init(config)
的逻辑:
1 | // |
这一段代码主要设置Vue
的内部属性并起了Vue
实例赋予global.app
。在其中,加载了App.vue
中id=app
的页面内容,包括这些:
1 | <template> |
其中,<router-view />
是实质展示了路由为/
的页面,对应到routers
里面就是@/components/Main
以及其下级的task
的路由组件。其他几个分别是:
mo-title-bar
:顶层的最小化、最大化、退出按钮mo-engine-client
:不渲染界面的组件,实质只有js
逻辑,用于管理下载进度mo-ipc
:不渲染界面的组件,实质只有js
逻辑,用于ipc
mo-dynamic-tray
:下载速度显示组件
到了这里,整个app
就启动完成了。