Об авторе Техническая команда zqlu Ant Financial Data Experience
VS Code — это новый инструмент, который сочетает в себе простоту редактора кода с инструментами, необходимыми разработчикам программ в процессе разработки, сборки и отладки. Code обеспечивает полную поддержку редактирования и отладки, расширяемую модель и упрощенную интеграцию с существующими инструментами.
ЭтоVSCode GithubСогласно введению на склад, сегодня количество звезд GitHub VSCode достигло 47 000. VSCode использует электрон, а использованный редактор кода называется Monaco. Monaco также является редактором кода, используемым сервисом Team Custome (Visual Studio Online ). Выше VSCode использует свой собственный разработку языка напечатает.
Прежде чем приступить к анализу собственного исходного кода VSCode, давайте сначала посмотрим на Electron, от которого зависит VSCode, и поймем, что Electron может лучше понять организацию кода и зависимости VSCode; во-вторых, режим внедрения зависимостей, используемый в исходном коде VSCode.
Electron
Electron — это фреймворк, который может использовать HTML, JavaScript и CSS для разработки десктопных приложений во фронтенде, материалов об Electron много. Мы можем взглянуть на пример приложения для быстрого старта, предоставленного официальным сайтом Electron:
вpackage.json
Определение выглядит следующим образом, обратите внимание наmain
поля иstart
сценарий: выполнитьnpm start
То есть запустить приложение Electron:
{
"name": "electron-quick-start",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"repository": "https://github.com/electron/electron-quick-start",
"keywords": ["Electron", "quick", "start", "tutorial", "demo"],
"author": "GitHub",
"license": "CC0-1.0",
"devDependencies": {
"electron": "~1.7.8"
}
}
тогда смотриmain.js
сценарий:
const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({ width: 800, height: 600 });
// and load the index.html of the app.
mainWindow.loadURL(
url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true,
}),
);
// Open the DevTools.
// mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function() {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', function() {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', function() {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
можно увидеть,main
Сценарий в основном определяет функции обработки приложения для нескольких событий, среди которыхready
В обработчике событий создайтеBrowseWindow
объект и загрузитьindex.html
страница.
существуетindex.html
, и снова загрузите его через тег скриптаrenderer.js
сценарий:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
We are using Node.js <script>document.write(process.versions.node)</script>,
Chromium <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</body>
</html>
На данный момент приложение экземпляра быстрого запуска Electron завершено, выполнитеnpm start
После этого вы можете увидеть дисплей на интерфейсеindex.html
в содержании.
Первое, что нам нужно понять, это два типа процессов, с которыми мы столкнемся в приложении Electron выше, и их различия, они называются основным процессом и процессом рендеринга.
Сначала взгляните на определения основного процесса и процесса рендеринга:
В электронном приложении,
package.json
серединаmain
Процесс, в котором выполняется сценарий, называется основным процессом, а сценарий, работающий в основном процессе, отображает пользовательский интерфейс, создавая веб-страницы. Приложение Electron всегда имеет один и только один основной процесс. Поскольку Electron использует Chromium для отображения веб-страниц, в Chromium также используется многопроцессорная архитектура. Каждая веб-страница в Electron работает сама по себе.процесс рендерингасередина. В обычных браузерах веб-страницы обычно работают в изолированной среде, и им не разрешается касаться собственных ресурсов. Однако пользователи Electron могут выполнять некоторые низкоуровневые взаимодействия с операционной системой на странице с поддержкой Node.js API.
Разница между основным процессом и процессом рендеринга:
использование основного процесса
BrowseWindow
страница создания экземпляра, каждыйBrowseWindow
Экземпляры запускают страницы в своем собственном процессе рендеринга. когдаBrowseWindow
После уничтожения экземпляра соответствующий процесс рендеринга также прекращается. Основной процесс управляет всеми веб-страницами и соответствующими процессами рендеринга. Каждый процесс рендеринга независим, он заботится о веб-странице, на которой работает.
Для разработчиков важнее то, какие API могут использоваться скриптами в основном процессе и в процессе рендеринга.
Прежде всего, Electron API предоставляет множество API, некоторые из которых можно использовать только в основном процессе, некоторые API можно использовать только в процессе рендеринга, а некоторые можно использовать как в основном процессе, так и в процессе рендеринга.
Тогда для Node.js API, а также сторонних пакетов npm можно напрямую использовать как основной процесс, так и процесс рендеринга.
Наконец, поскольку процесс рендеринга выполняется на страницах хрома, все они также могут быть API-интерфейсами, предоставляемыми браузерами, такими как API-интерфейсы манипуляции с DOM.
API | основной процесс | процесс рендеринга |
---|---|---|
Electron API | часть | часть |
Node.js API/module | да | да |
API браузера | нет | да |
Узнав об Electron, мы увидим, какой код в VSCode выполняется в основном процессе, а какой — в процессе рендеринга.
внедрение зависимости
Внедрение зависимостей, как шаблон проектирования, возможно, мало используется разработчиками интерфейса, но его можно увидеть повсюду в исходном коде VSCode, так что вот краткое введение. Сначала взгляните на определение внедрения зависимостей:
В программной инженерии внедрение зависимостей — это шаблон проектирования, который предоставляет объекты, от которых зависит класс объектов. Зависимые объекты называются
Service
, инъекция относится к объекту, от которого будет зависетьService
передается объекту, потребляющему услугу (называемомуClient
), чтобы покупательClient
Нет необходимости активно создавать (новые) зависимые сервисыService
, и не нужно получать зависимые сервисы через заводской режимService
.
В типичном шаблоне внедрения зависимостей существуют следующие категории ролей:
- Объекты, от которых зависят и которые используются, т.е.
Service
- Клиентский объект, который использует службу, т.е.
Client
- Определение интерфейса для клиента, чтобы использовать службу,
Interface
- Инжектор: отвечает за создание сервисных объектов и предоставление их клиентам, обычно также отвечает за создание клиентских объектов.
Реализация внедрения зависимостей имеет несколько форм, одна из которых является распространенной — это внедрение зависимостей в стиле конструктора: Клиент объявляет службу, от которой он зависит, в параметрах своего конструктора, как показано в следующем коде TypeScript:
class Client {
constructor(serviceA: ServiceA, serviceB: ServiceB) {
// 注入器在建立Client的时候,将依赖的 Service 通过构造函数参数传递给 Client
// Client此时即可将依赖的服务保存在自身状态内:
this.serviceA = serviceA;
this.serviceB = serviceB;
}
}
Благодаря этому режиму Клиенту не нужно создавать требуемый объект Сервиса при его использовании.Одним из преимуществ этого является разделение построения и поведения объекта.После введения интерфейса зависимости между Клиентом и Сервисом нужен только интерфейс, чтобы определить, какие зависимые сервисные интерфейсы нужны Клиенту в параметрах конструктора, в сочетании с инжектором, могут дать клиентскому объекту больше гибкости и разъединения.
Наконец, в исходном коде VSCode большинство основных функций реализовано в виде сервисных объектов.Определение сервиса разделено на две части:
- сервисный интерфейс
- Идентификация сервисов: реализовано через декораторы на TypeScript
Когда Клиент объявляет зависимую Службу, он также объявляет ее в параметре конструктора Пример выглядит следующим образом:
class Client {
constructor(
@IModelService modelService: IModelService,
@optional(IEditorService) editorService: IEditorService,
) {
// ...
this.modelService = modelService;
this.editorService = editorService;
}
}
Здесь объявленный клиентский объектClient
, зависит отService
имеютIModelService
а такжеIEditorService
, где декоратор@IModelService
это идентификатор ModelService, за которым следуетIModelService
Просто определение интерфейса в TypeScript;@optional(IEditorService)
является идентификатором EditorService и передается черезoptional
Декоратор объявляется как необязательная зависимость.
Наконец, в коде, который фактически используетсяClient
объект, он должен быть предоставлен инжекторомinstantiationService
Чтобы создать экземпляр Client:
const myClient = instantiationService.createInstance(Client);
организация исходного кода
После понимания Electron и внедрения зависимостей мы можем взглянуть на организацию исходного кода самого VSCode.
VSCode Core
Во-первых, ядро его общего VSCodecore
и встроенные расширенияExtensions
сочинение,core
Он реализует базовый редактор кода и настольное приложение VSCode, а именно VSCode workbench; он также предоставляет API-интерфейсы расширений, позволяющие использовать встроенные расширения и расширения, разработанные сторонними компаниями, для расширения возможностей VSCode Core.
Первый взглядCore
организация исходного кода,Core
Исходный код разделен на следующие каталоги:
-
src/vs/base
: определение основных служебных методов и основных элементов управления DOM UI. -
src/vs/code
: Редактор кода Monaco Editor: Он содержит отдельно упакованный редактор Monaco Editor и части, которые можно использовать только в VSCode. -
src/vs/platform
: Реализация внедрения зависимостей и основных сервисов, используемых VSCode. -
src/vs/workbench
: Внедрение VSCode Desktop Application Workbench. -
src/vs/code
: Запись приложения VSCode Electron, включая запись основного процесса Electron.
Во-вторых, поскольку VSCode опирается на Electron, мы упоминали выше, что у Electron есть основной процесс и процесс рендеринга, но API, которые они могут использовать, недоступны, поэтому VSCodeCore
Организация каждого каталога также организована в соответствии с API, которые они могут использовать. В каждом подкаталоге Core целевая среда, в которой выполняется код, делится на следующие категории:
-
common
: используйте только исходный код JavaScript API, может работать в любой среде. -
browser
: исходный код, который должен использовать API, предоставляемый браузером, например манипулирование DOM и т. д. -
node
: нужно использоватьNode.js
Исходный код предоставленного API -
electron-browser
: Исходный код, необходимый для использования API рендерера Electron. -
electron-main
: Исходный код, необходимый для использования API основного процесса Electron.
Согласно приведенным выше правилам, а именноsrc/vs/workbench/browser
Исходный код может использовать только базовый API JavaScript и API, предоставляемый браузером, в то время какsrc/vs/workbench/electron-browser
Исходный код в браузере может использовать API JavaScript, API, предоставляемый браузером,Node.js
Предоставленный API и API в процессе рендеринга Electron.
VSCode Extensions
В репозитории кода VSCode указанный вышеsrc/vs
изCore
Кроме того, есть большой кусок встроенных расширений VSCode, их исходный код находится вextensions
Внутри.
Во-первых, VSCode используется как редактор кода, но время от времени расширяются различные функции редактирования кода, такие как подсветка синтаксиса, подсказки о завершении, проверка и т.д. Поэтому среди встроенных расширений VSCode большую часть составляют поддерживающие расширения различных языков программирования, такие как:extensions\html
,extensions\javascript
,extensions\cpp
И так далее, большинство языковых расширений будут выглядеть как.tmTheme
,.tmLanguage
и т.д. Определение синтаксиса TextMate.
Другим типом встроенного расширения является расширение тела VSCode, такое как тело VSCode по умолчанию.extensions/theme-defaults
Ждать.
Ссылаться на
В этой статье кратко представлены некоторые приготовления, необходимые перед чтением исходного кода VSCode, в основном структура приложения Electron, шаблон проектирования внедрения зависимостей, а также исходный код VSCode и общая организация.
Следующее уведомление: ввод из командной строкиcode
Каков поток выполнения кода VSCode до появления настольного приложения VSCode?
Если вам интересна наша команда, вы можете подписаться на рубрику и подписатьсяgithubИли отправьте свое резюме на 'tao.qit####alibaba-inc.com'.replace('####', '@'), люди с высокими идеалами могут присоединиться~
Оригинальный адрес:GitHub.com/proto team/no…