自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從 VSCode 看大型 IDE 技術架構

新聞 架構
談起 Web IDE,沒人能繞開 VSCode,它非常流行,同時又完全開源,總共 350000 行 TypeScript 代碼的巨大工程,使用了 142 個開源庫。

零、前言

為什么要去看 VSCode?

因為我們團隊在做中后臺 Web 編輯器 是一款類似 Web IDE 形態(tài)的產(chǎn)品:

從 VSCode 看大型 IDE 技術架構

而談起 Web IDE,沒人能繞開 VSCode,它非常流行,同時又完全開源,總共 350000 行 TypeScript 代碼的巨大工程,使用了 142 個開源庫。市面上選擇基于 VSCode 去修改定制的 IDE 比比皆是:Weex Studio、白鷺Egret Wing、快應用IDE...

我希望從 VSCode 身上看到什么?

  • 大型復雜 GUI 軟件(如 IDE 類)如何組織功能模塊代碼
  • 如何使用 Electron 技術將 Web 軟件桌面化
  • 如何在打造插件化開放生態(tài)的同時保證軟件整體質量與性能
  • 如何打造一款好用的、流行的工具軟件

一、VSCode 是什么

官方定義

https://code.visualstudio.com/

從 VSCode 看大型 IDE 技術架構

關鍵詞:

  • 代碼編輯(工具屬性)
  • 跨平臺運行、開源
  • 核心功能:
    • IntelliSense(代碼提示)、 debugging(代碼調試)、 git(代碼管理) 都是圍繞代碼編輯的核心鏈路
    • extensions (插件)則肩負著打造開放生態(tài)的責任
從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構

點評:

對于工具軟件而言,需要內(nèi)心能想清楚邊界。哪些是自己應該專注去做的,哪些可以外溢到交給第三方擴展來滿足。

發(fā)展歷程

  • 2015-04 (4年前) 發(fā)布
  • 2015-11 (發(fā)布之后半年)開源
  • 2019-05 發(fā)布 VSCode Remote Development

團隊負責人:Erich Gamma . JUnit 作者之一,《設計模式》作者之一, Eclipse 架構師。2011 加入微軟,在瑞士蘇黎世組建團隊開發(fā)基于 web 技術的編輯器,也就是后來的 monaco-editor。VSCode 開發(fā)團隊從 10 來個人開始,早期成員大多有 Eclipse 開發(fā)團隊的背景。

Visual Studio Code有哪些工程方面的亮點 維護一個大型開源項目是怎樣的體驗?「Shape Up」 適合中小團隊的一種工作方式

從 VSCode 看大型 IDE 技術架構

Erich Gamma 在 GOTO 2016 發(fā)表了主題為 《The journey of visual studio code: Building an App Using JS/TypeScript, Node, Electron & 100 OSS Components》的演講,詳細講解了這個項目的發(fā)展歷程:

沒時間觀看視頻的可以下載完整 PDF

PPT 的第一頁,就是 Erich Gamma 截取自己正式加入微軟之后收到的工作內(nèi)容描述的郵件:

”探索一種全新的和桌面 IDE 一樣成功的在線開發(fā)工具模式“

從 VSCode 看大型 IDE 技術架構

整個團隊從大致 10 個人開始,混合老中新三代不同水平的程序員,在微軟這個巨無霸的商業(yè)公司里面想要落地這樣一個宏大的愿景是不容易的,團隊一開始定下的思路就是像 start up 一樣工作,每月每年都要 ship 東西。

同時他也提出早期會瘋狂的在公司內(nèi)部尋找落地場景,比如 Visual Studio Online 的在線 Code DIff 頁面,TypeScript 的官網(wǎng)的 Playground 編輯器,OneDrive 代碼文件,Edge Dev Tool 的代碼瀏覽等。

一個重要轉折點是微軟本身發(fā)生的巨大變化:

從 VSCode 看大型 IDE 技術架構

伴隨微軟整個的開放開源跨平臺風潮,Erich Gamma 敏銳的決定將產(chǎn)品從 Browser Based IDE 轉向跨平臺的 Desktop IDE,但仍然使用 Web 技術,于是 electron 粉墨登場,VSCode 開源這些事情接連發(fā)生,VSCode 團隊花了六個月使用 Electron 將 Web 編輯器桌面化,又花了六個月將整個 IDE 插件化。

從 VSCode 看大型 IDE 技術架構

產(chǎn)品定位

Erich Gamma 在 2017 SpringOne Platform 上有一個 關于 VSCode 的分享,講解了在他開發(fā) Eclipse 的過往經(jīng)驗基礎上,對 VSCode 進行頂層設計時的諸多思路與決策,其中提到過對于 VSCode 的產(chǎn)品定位:

從 VSCode 看大型 IDE 技術架構

從圖中可以看出 VSCode 定位是處于編輯器和 IDE 的中間并且偏向輕量編輯器一側的。

VSCode 的核心是“編輯器 + 代碼理解 + 調試“,圍繞這個關鍵路徑做深做透,其他東西非常克制,產(chǎn)品保持輕量與高性能。

點評:

生產(chǎn)力工具類的軟件一定要守住主線,否則很可能會變成不收門票的游樂園牛逼的產(chǎn)品背后一定有牛逼的團隊,比如微軟挖到 Anders Hejlsberg,接連創(chuàng)造了 C# 和 TypeScript,挖到 Erich Gamma,接連誕生了 monaco 和 vscode 這些明珠

二、Electron 是什么

上文提到 VSCode 有一個特性是跨平臺,它的跨平臺實質是通過 electron 實現(xiàn)的。所以我們需要先簡單了解下 electron

官方定義

從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構

核心技術

從 VSCode 看大型 IDE 技術架構
  • 使用 Web 技術來編寫 UI,用 chrome 瀏覽器內(nèi)核來運行
  • 使用 NodeJS 來操作文件系統(tǒng)和發(fā)起網(wǎng)絡請求
  • 使用 NodeJS C++ Addon 去調用操作系統(tǒng)的 native API

應用架構

https://electronjs.org/docs/tutorial/application-architecture

從 VSCode 看大型 IDE 技術架構
  • 1 個主進程:一個 Electron App 只會啟動一個主進程,它會運行 package.json 的 main 字段指定的腳本
  • N 個渲染進程:主進程代碼可以調用 Chromium API 創(chuàng)建任意多個 web 頁面,而 Chromium 本身是多進程架構,每個 web 頁面都運行在屬于它自己的渲染進程中

進程間通訊:

  • Render 進程之間的通訊本質上和多個 Web 頁面之間通訊沒有差別,可以使用各種瀏覽器能力如 localStorage
  • Render 進程與 Main 進程之間也可以通過 API 互相通訊 (ipcRenderer/ipcMain)

點評:

普通 web 頁面無法調用 native api,因此缺少一些能力electron 的 web 頁面所處的 Render 進程可以將任務轉發(fā)至運行在 NodeJS 環(huán)境的 Main 進程,從而實現(xiàn) native API這套架構大大擴展了 electron app 相比 web app 的能力豐富度,但同時又保留了 web 快捷流暢的開發(fā)體驗,再加上 web 本身的跨平臺優(yōu)勢,結合起來讓 electron 成為性價比非常高的方案

三、VSCode 技術架構

多進程架構

從 VSCode 看大型 IDE 技術架構
  • 主進程:VSCode 的入口進程,負責一些類似窗口管理、進程間通信、自動更新等全局任務
  • 渲染進程:負責一個 Web 頁面的渲染
  • 插件宿主進程:每個插件的代碼都會運行在一個獨屬于自己的 NodeJS 環(huán)境的宿主進程中,插件不允許訪問 UI
  • Debug 進程:Debugger 相比普通插件做了特殊化
  • Search 進程:搜索是一類計算密集型的任務,單開進程保證軟件整體體驗與性能
  1. # 檢出代碼git clone git@github.com:microsoft/vscode.gitcd vscode# 安裝依賴yarn# 啟動 web 版yarn watch && yarn web# 啟動 桌面 版yarn watch && ./scripts/code.sh# 打包yarn run gulp vscode-[platform]yarn run gulp vscode-[platform]-min# platforms: win32-ia32 | win32-x64 | darwin | linux-ia32 | linux-x64 | linux-arm 

開發(fā)流程

  • 開發(fā)文檔:https://github.com/Microsoft/vscode/wiki/How-to-Contribute
  • 主倉庫:https://github.com/microsoft/vscode
  • 其它關聯(lián)項目:https://github.com/Microsoft/vscode/wiki/Related-Projects

 

 

源碼組織

https://github.com/microsoft/vscode/wiki/Source-Code-Organization

下面是整個 VSCode project 的一些頂級的重點文件夾,后文會重點關注 src 與 extensions:

  1. ├── build         # 構建腳本├── extensions    # 內(nèi)置插件├── scripts       # 工具腳本├── out           # 產(chǎn)物目錄├── src           # 源碼目錄├── test          # 測試代碼 

VSCode 的代碼架構也是隨著產(chǎn)品的階段演進演進不斷更迭的:

從 VSCode 看大型 IDE 技術架構

下文會分享一些整個 VScode 源碼組織的一些亮點與特色:

1. 隔離內(nèi)核 (src) 與插件 (extensions),內(nèi)核分層模塊化

  • /src/vs:分層和模塊化的 core
    • /src/vs/base: 通用的公共方法和公共視圖組件
    • /src/vs/code: VSCode 應用主入口
    • /src/vs/platform:可被依賴注入的各種純服務
    • /src/vs/editor: 文本編輯器
    • /src/vs/workbench:整體視圖框架
  • /src/typings: 公共基礎類型
  • /extensions:內(nèi)置插件

2. 每層按環(huán)境隔離

內(nèi)核里面每一層代碼都會遵守 electron 規(guī)范,按不同環(huán)境細分文件夾:

  • common: 公共的 js 方法,在哪里都可以運行的
  • browser: 只使用瀏覽器 API 的代碼,可以調用 common
  • node: 只使用 NodeJS API 的代碼,可以調用 common
  • electron-browser: 使用 electron 渲染線程和瀏覽器 API 的代碼,可以調用 common,browser,node
  • electron-main: 使用 electron 主線程和 NodeJS API 的代碼,可以調用 common, node
  • test: 測試代碼

點評:

實際開發(fā)中也遇到了類似問題,作為一個 低代碼 + 可視化 的研發(fā)平臺,許多功能模塊的實現(xiàn)都需要橫跨編輯態(tài)和運行態(tài),如果代碼不加以限制和區(qū)分,很容易導致錯誤的依賴關系和預期之外的 bug,因此最終也決定采用 (editor/runtime/common) 類似的隔離架構

3. 內(nèi)核代碼本身也采用擴展機制: Contrib

可以看到 /src/vs/workbench/contrib 這個目錄下存放著非常多的 VSCode 的小的功能單元:

  1. ├── backup├── callHierarchy├── cli├── codeActions├── codeEditor├── comments├── configExporter├── customEditor├── debug├── emmet├──....中間省略無數(shù)....├── watermark├── webview└── welcome 

Contrib 有一些特點:

  • Contrib 目錄下的所有代碼不允許依賴任何本文件夾之外的文件
  • Contrib 主要是使用 Core 暴露的一些擴展點來做事情
  • 每一個 Contrib 如果要對外暴露,將API 在一個出口文件里面導出 eg: contrib/search/common/search.ts
  • 一個 Contrib 如果要和另一個 Contrib 發(fā)生調用,不允許使用除了出口 API 文件之外的其它文件
  • 接上一條,即使 Contrib 可以調用另一個 Contrib 的出口 API,也要審慎的考慮,應盡量避免兩個 Contrib 互相依賴

VSCode 開發(fā)團隊做這個設計的目的我猜大概是因為重型的工具軟件功能點實在太多,如果這些功能代碼直接采用原始的模塊引用的方式聚合瓶裝起來,是一個自頂向下的架構,對維護性的挑戰(zhàn)比較大。

而采用暴露擴展點的方式,可以將依賴關系反轉,依附于擴展點協(xié)議,將核心功能和非核心功能分割開,獨立的小功能的代碼實現(xiàn)可以單獨聚合,降低信息密度與提升維護性。

但是 VSCode Contrib 的具體業(yè)務代碼組織其實看起來沒有太多范式,而且這個內(nèi)核代碼的擴展機制 Contrib 和 VSCode 開放給外界的插件化機制 extension 是有差異的,讀起來十分頭疼。

通過和 CloudIDE 開發(fā)同學木農(nóng)的交流,我得到兩條主要差異性:

  • extension 每一個都是運行在歸宿于自己的獨立宿主進程,而 contrib 的功能基本是要運行在主進程的
  • extension 只能依附于 core 開放的擴展點而活,但是 contrib 可以通過依賴注入拿到所有 core 內(nèi)部實現(xiàn)的 class (雖然官方不推薦)

4. 依賴注入

上一小節(jié)提到了 VSCode 的代碼大量使用了依賴注入,這項技術的具體實現(xiàn)細節(jié)本文不會展開細講,感興趣的可以閱讀一些好的實現(xiàn):

  • 團隊揚遠同學寫的 power-di
  • 社區(qū)開源的強大的 http://inversify.io

TS 依賴注入常見的實現(xiàn)原理是使用 reflect-metadata 設置與獲取元信息,從而可以實現(xiàn)在運行時拿到本來屬于編輯態(tài)的 TypeScript 類型相關元信息,具體來說就是下面這些 API:

  • Reflect.getMetadata("design:type", , target, key): 獲取 class 屬性類型元信息
  • Reflect.getMetadata("design:paramtypes", target, key): 獲取 class 方法參數(shù)元信息
  • Reflect.getMetadata("design:returntype", target, key):獲取 class 方法返回值元信息
  • Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey):設置元信息
  • Reflect.getMetadata(metadataKey, target, propertyKey): 獲取元信息

不過具體到 VSCode 的依賴注入,它沒有使用 reflect-metadata 這一套,而是基于 decorator 去標注元信息,整個實現(xiàn)了一套自己的依賴注入方式,具體可以參考vscode 源碼解析-依賴注入 這篇文章,大致包含如下幾類角色:

  • Service:服務的實現(xiàn)邏輯
  • Interface:服務的接口描述
  • Client:服務使用方
  • Manger:服務管理器

舉個例子來看,在 /src/core/platform 里面定義了大量 service,其他地方消費者 Client 都可以用依賴注入的方式使用到,偽代碼如下:

  1. class Client {  // 構造函數(shù)參數(shù)注入(依賴注入方式的一種)  constructor(    // 必選    @IModelService modelService: IModelService,     // 可選    @optional(IEditorService) editorService: IEditorService  ) {    // use services  }}// 實例化instantiationService.createInstance(Client); 

5. 絕對路徑 import

從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構

點評:絕對路徑 import 是一個非常值得學習的技巧,具體的方式是配置 TypeScript compilerOptions.paths

相對路徑 import 對閱讀者的大腦負擔高,依賴當前文件位置上下文信息才能理解重構代碼的時候移動文件位置,相對路徑需要修改本文件的所有 import,絕對路徑不需要

6. 命令系統(tǒng)

VSCode 和 monaco-editor 都有自己的命令系統(tǒng),螞蟻 CloudIDE 團隊的同學也曾經(jīng)對命令系統(tǒng)的優(yōu)勢做過總結:

傳統(tǒng)的模塊調用是個網(wǎng)狀,不太好找到一個切面來理解或治理:

從 VSCode 看大型 IDE 技術架構

而命令系統(tǒng)是中心化的,各功能末端變成了扁平化的結構:

從 VSCode 看大型 IDE 技術架構

7. TypeScript

從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構

啟動流程 (TLDR)

上文初步了解了 vscode 的技術架構與源碼組織,手癢的同學估計有點等不及嘗試走一遍 vscode 的啟動流程了。

然后在正式發(fā)車之前,我需要給大家一點友情提醒,如果你沒耐心看完下面的 VSCode 的啟動流程,應該知道,人生得過且過 o(╥﹏╥)o

總體來看,VSCode 的啟動代碼真正 show 給我們看了一個復雜的客戶端軟件的代碼會工程化到什么地步,這其中摻雜了大量的基于 TypeScript 的 OOP 式的代碼組織,各種對邊界,宿主環(huán)境,上下文的處理,本來簡單的啟動 APP 渲染一個頁面流程變得極其復雜。

下面精簡抽取核心啟動鏈路的文件和方法看一看:

  • 入口:package.json { "main": "./out/main" } : electron 的標準啟動入口
  • '/out/main.js': 是構建產(chǎn)物的入口文件,它對應源碼 '/src/main.js'
  1. // /src/main.js 的精簡核心鏈路const { app, protocol } = require('electron');app.once('ready', function () {  // electron 啟動好之后,調用 vscode 的入口    onReady();});async function onReady() {    // 獲取緩存文件目錄地址和語言配置,執(zhí)行啟動        const [cachedDataDir, nlsConfig] = await Promise.all([nodeCachedDataDir.ensureExists(), resolveNlsConfiguration()]);        startup(cachedDataDir, nlsConfig);}function startup(cachedDataDir, nlsConfig) {  // 先加載 vscode 自己開源的 AMD Loader https://github.com/Microsoft/vscode-loader/  // 再使用這個 loader 去加載 VSCode 的主入口文件    require('./bootstrap-amd').load('vs/code/electron-main/main');}  
  1. // /src/vs/code/electron-main/main.ts 精簡核心鏈路// 初始化主類const code = new CodeMain();// 執(zhí)行主入口函數(shù)code.main();class CodeMain {  main() {    // vscode 的 class public 入口一般只是空殼,真正的都在 private 邏輯里面    this.startUp();  }  private async startup() {    // 先創(chuàng)建依賴的初始化 service        const [instantiationService, instanceEnvironment] = this.createServices();    // 創(chuàng)建編輯器實例并調用 startUp 方法    return instantiationService.createInstance(CodeApplication).startup();  }} 
  1. // /src/vs/code/electron-main/app.tsexport class CodeApplication extends Disposable {    async startup(): Promise<void> {        // IPC Server        const electronIpcServer = new ElectronIPCServer();        // SharedProcess        const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);        // 創(chuàng)建一大堆依賴的 service        // IUpdateService IWindowsMainService IDialogMainService IMenubarService IStorageMainService......        const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient);        // 打開一個窗口            const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));    }      private openFirstWindow() {      const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);            return windowsMainService.open();    }} 
  1. // /src/vs/platform/windows/electron-main/windowsMainService.tsexport class WindowsMainService extends Disposable implements IWindowsMainService {  open() {    // 執(zhí)行 open    this.doOpen();  }  private doOpen() {    // 打開瀏覽器窗口    this.openInBrowserWindow();  }  private openInBrowserWindow() {            // 創(chuàng)建窗口            const createdWindow = window = this.instantiationService.createInstance(CodeWindow, {                state,                extensionDevelopmentPath: configuration.extensionDevelopmentPath,                isExtensionTestHost: !!configuration.extensionTestsPath            });  }    private doOpenInBrowserWindow() {        // 加載頁面    window.load(configuration);  }} 
  1. // /src/vs/code/electron-main/window.tsexport class CodeWindow extends Disposable implements ICodeWindow {  load() {        // 調用 electron 的 api 加載一個 url 的 html 頁面        this._win.loadURL(this.getUrl(configuration));  }    private getUrl() {    // 獲取要打開的 url    let configUrl = this.doGetUrl(config);    return configUrl;  }    private doGetUrl(config: object): string {    // 終于看到 html 了??!淚流滿面〒▽〒    // 打開 VSCode 的工作臺,也就是 workbench         return `${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`;    }} 

代碼編輯器技術

因為本文關注的重點并不在真正的代碼編輯器技術而是在調研一下大型軟件的工程化,因此本文只會簡要介紹一下代碼編輯相關的的一些核心技術:

  • monaco-editor 文本編輯器,非常精深的領域,不展開聊,可以看一些有意思的細節(jié):
    • Text Buffer 性能優(yōu)化
    • MVVM 架構
  • language server protocol 語言提示, 也是 vscode 的一大創(chuàng)舉:
    • 不再關注 AST 和 Parser,轉而關注 Document 和 Position,從而實現(xiàn)語言無關。
    • 將語言提示變成 CS 架構,核心抽象成當點擊了文檔的第幾行第幾列位置需要 server 作出什么響應的一個簡單模型,基于 JSON RPC 協(xié)議傳輸,每個語言都可以基于協(xié)議實現(xiàn)通用后端
從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構
  • Debug Adaptor Prototal: 調試協(xié)議
從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構
從 VSCode 看大型 IDE 技術架構

點評:

monaco-editor 可以看出專家級人物的領域積累,屬于 VSCode 的核心競爭力language server protocol 和 Debug Adaptor Prototal 的設計就屬于高屋建瓴,可以看出思想層次,把自己的東西做成標準,做出生態(tài),開放共贏

四、VSCode 插件系統(tǒng)

理念差異

從 VSCode 看大型 IDE 技術架構

對比幾大 IDE:

  • Visual Studio / IntelliJ:不需要插件,all in one (不夠開放)
  • Eclipse: 一切皆插件 (臃腫、慢、不穩(wěn)定、體驗差)
  • VSCode:中庸之道

VSCode 插件的強隔離

從 VSCode 看大型 IDE 技術架構
  • 獨立進程:VSCode plugin 代碼運行在只屬于自己的獨立 Extension Host 宿主進程里
  • 邏輯與視圖隔離:插件完全無法訪問 DOM 以及操作 UI,插件只能響應 VSCode Core 暴露的擴展點
  • 視圖擴展能力非常弱:VSCode 有非常穩(wěn)定的交互與視覺設計,提供給插件的 UI 上的洞(component slot)非常少且穩(wěn)定
  • 只能使用限制的組件來擴展:VSCode 對視圖擴展的能力限制非常強,洞里面的 UI 是并不能隨意繪制的,只能使用一些官方提供的內(nèi)置組件,比如 TreeView 之類

vscode 有哪些擴展能力?https://code.visualstudio.com/api/extension-capabilities/overview

點評:

視圖擴展的克制帶來統(tǒng)一的視覺與交互風格,帶來好的用戶體驗,便于建立穩(wěn)定的用戶心智插件獨立進程,與視圖隔離,保證整體軟件的質量、性能、安全性

Workbench 視圖結構

https://code.visualstudio.com/docs/getstarted/userinterface

從 VSCode 看大型 IDE 技術架構
  • 標題欄: Title Bar
  • 活動欄: Activity Bar
  • 側邊欄: Side Bar
  • 面板: Panal
  • 編輯器: Editor
  • 狀態(tài)欄: Status Bar

在這個視圖結構里面有哪些可擴展呢?詳見 extending workbench:

從 VSCode 看大型 IDE 技術架構

插件 API 注入

插件開發(fā)者調用 core 能力時需要引入名為 vscode 的 npm 模塊

  1. import * as vscode from 'vscode'

而實際上這只是一個 vscode.d.ts 類型聲明文件,它聲明了所有插件可用的 API 類型。

這些 API 的具體實現(xiàn)在 src/vs/workbench/api/common/extHost.api.impl.ts createApiFactoryAndRegisterActors

那么具體這些 API 在 plugin 執(zhí)行上下文是何時注入的呢?其實是在插件 import 語句執(zhí)行的時候動了手腳。

  1. // /src/vs/workbench/api/common/extHostRequireInterceptor.tsclass VSCodeNodeModuleFactory implements INodeModuleFactory {    public load(_request: string, parent: URI): any {        // get extension id from filename and api for extension        const ext = this._extensionPaths.findSubstr(parent.fsPath);        if (ext) {            let apiImpl = this._extApiImpl.get(ExtensionIdentifier.toKey(ext.identifier));            if (!apiImpl) {                apiImpl = this._apiFactory(ext, this._extensionRegistry, this._configProvider);                this._extApiImpl.set(ExtensionIdentifier.toKey(ext.identifier), apiImpl);            }            return apiImpl;        }        // fall back to a default implementation        if (!this._defaultApiImpl) {            let extensionPathsPretty = '';            this._extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`);            this._logService.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`);            this._defaultApiImpl = this._apiFactory(nullExtensionDescription, this._extensionRegistry, this._configProvider);        }        return this._defaultApiImpl;    }} 

vscode plugin 的 require 全部被 Microsoft/vscode-loader 劫持了,通過對 require 的 hack 將插件 API 注入到了運行環(huán)境。

插件開發(fā)與配置

腳手架: https://github.com/Microsoft/vscode-generator-code

官方 demo: https://github.com/Microsoft/vscode-eslint

  1. npm install -g yo generator-codeyo code 

一個插件核心就是一個配置文件:Extension Manifest JSON (package.json 里面的一個字段)

https://code.visualstudio.com/api/references/extension-manifest

一些關鍵配置如下:

main:主文件入口,比如導出一個 activate 方法,可以接受 ctx 做一些事情
  1. "main""./src/extension.js"

  1. // extension.jsconst vscode = require("vscode");function activate(context) {  console.log('Congratulations, your extension "helloworld" is now active!');  let disposable = vscode.commands.registerCommand(    "extension.helloWorld",    function() {      vscode.window.showInformationMessage("Hello World!");    }  );  context.subscriptions.push(disposable);}exports.activate = activate; 
Activation Events 激活時機
  • onLanguage:包含該語言類型的文件被打開
    • onLanguage:json
  • onCommand:某個命令
    • onCommand:extension.sayHello
  • onDebug:開始調試
  • onDebugInitialConfigurations
  • onDebugResolve
  • workspaceContains:有匹配規(guī)則的文件被打開
    • workspaceContains:**/.editorconfig
  • onFileSystem:打開某個特殊協(xié)議的文件
    • onFileSystem:sftp
  • onView:某個 id 的視圖被顯示
    • onView:nodeDependencies
  • onUri:向操作系統(tǒng)注冊的 schema
    • vscode://vscode.git/init
  • onWebviewPanel:某種 viewType 的 webview 打開時
    • onWebviewPanel:catCoding
  • *:啟動就立即打開
Contribution Points 擴展點
  • contributes.configuration:本插件有哪些可供用戶配置的選項
  • contributes.configurationDefaults:覆蓋 vscode 默認的一些編輯器配置
  • contributes.commands:向 vscode 的命令系統(tǒng)注冊一些可供用戶調用的命令
  • contributes.menus:擴展菜單
  • ...

五、感想

Eric Raymond 有一本非常知名的著作 《大教堂與集市》,其中提到過一些有意思的觀點:

  • 健壯的結構遠比精巧的設計來得重要。換句話說,結構是第一位的,功能是第二位的。
  • 保持項目的簡單性。設計達到完美的時候,不是無法再增加東西了,而是無法再減少東西了。

VSCode 的一些工程上的優(yōu)秀設計,比如依賴注入、絕對路徑引用、命令系統(tǒng)對于實際項目來說是可以馬上學以致用的,而 contrib 與 extension 的擴展系統(tǒng),則非一日之功,也并不宜盲目下手。

而事實上在嘗試打造每一個開發(fā)者都夢想的萬物皆 plugin 式的工具軟件之前,有一些通用的問題需要先冷靜下來思考:

  • 用戶核心在操作的資源是什么?
  • 用戶的關鍵路徑是什么?
  • 這個軟件的整體功能形態(tài),交互與視覺設計已經(jīng)穩(wěn)定了嗎?
  • 內(nèi)核功能區(qū)和第三方擴展的功能域之間的界限在哪里?
  • 哪些環(huán)節(jié)可能會出現(xiàn)外溢需求需要第三方擴展才能被滿足,不適宜官方動手做嗎?

對 VSCode 而言:

  • 核心操作的資源是文件
  • 關鍵路徑是:打開文件 - 編輯文件 - 保存文件
  • 整體功能設計,交互與視覺設計非常穩(wěn)定
  • 內(nèi)核是文件管理與代碼編輯,多樣性的編程語言生態(tài),CICD 等衍生研發(fā)鏈路等可能會出現(xiàn)擴展需求

六、相關資料

  • https://github.com/JChehe/blog/issues/5
  • https://electronjs.org/docs/tutorial/application-architecture
  • https://zhuanlan.zhihu.com/p/54289476
  • http://phosphorjs.github.io/
  • http://gitlab.alipay-inc.com/bigfish/bigfish-vscode-plugin/tree/master
  • https://developer.egret.com/cn/docs/page/778
  • https://developer.chrome.com/extensions/getstarted
  • https://developer.alipay.com/article/8708
  • https://zhaomenghuan.js.org/blog/vscode-custom-development-basic-preparation.html

 

責任編輯:張燕妮 來源: yuque.com
相關推薦

2016-11-07 21:00:04

網(wǎng)站service架構設計

2009-07-01 08:49:34

架構Web2.0Twitter

2016-01-05 13:22:42

技術架構SaaS客服平臺

2018-02-10 11:11:01

網(wǎng)站技術架構負載均衡

2015-10-22 10:35:06

2019-04-18 14:24:52

技術互聯(lián)網(wǎng)架構

2018-01-23 11:09:04

區(qū)塊鏈技術重用

2016-06-30 16:52:23

開源

2017-05-08 11:53:21

2012-01-16 09:54:37

大型網(wǎng)站

2012-09-23 09:38:13

鐵路客票系統(tǒng)

2016-01-15 10:18:48

ces展望技術

2017-04-01 13:30:23

OpenStack O容器技術

2024-01-19 09:21:35

攜程開源

2015-06-12 10:58:51

綜合布線技術

2009-04-28 18:32:54

2009-07-06 15:55:50

2021-04-16 10:32:28

蜜罐網(wǎng)絡安全

2019-10-08 09:29:41

架構代碼業(yè)務邏輯

2009-07-30 10:28:56

Web高性能開發(fā)
點贊
收藏

51CTO技術棧公眾號