CesiumJS 2022^ 原始碼解讀[0] - 文章目錄與原始碼工程結構

四季留歌發表於2022-07-04

很高興你能在浮躁的年代裡還有興趣閱讀原始碼,CesiumJS 至今已有十年以上,程式碼量也積累了三十多萬行(未壓縮狀態)。

我也很榮幸自己的文章能被讀者看到,如果對你有幫助、有啟發,點個贊就是對我最大的鼓勵,感激不盡。本系列文章寫於 2022 年,梳理的是 CesiumJS 前端庫中的主要原始碼結構,不涉及著色器原理、WebGL 效果原理剖析等內容較為專一、可以獨立出文的內容。

如果想看文章目錄,直接拉到本文最後一節即可。



1. 原始碼工程目錄詳解

前置說明

  • 當我在說“xx指令”時,指的是 package.json 下的 node-script(即 scripts 列表中的某一個),可以使用 npm、yarn 或者 pnpm 執行;
  • 當我在說“開發者頁面”時,指的是你將原始碼工程的依賴下載下來,啟動 start 指令,啟動本地開發伺服器,開啟的那個主頁;
  • CesiumJS 指的是 Source 資料夾下的前端庫原始碼 + 測試程式碼 + 前端靜態資源 + 構建與原始碼開發工具的統稱,前端庫即 Cesium.js 只是 CesiumJS 的主要構建產物。

① 根目錄下

  • gulpfile.cjs:gulp 的配置檔案,有好幾個 node-script 是與裡面的 gulp 任務關聯的;
  • CONTRIBUTORS.md:所有參與過 CesiumJS 專案的貢獻者名單;
  • CHANGES.md:釋出日誌;
  • index.html & server.cjs:CesiumJS 這個工程使用了 express 這個庫,允許你使用 start 這個 node-script 啟動本地 express 伺服器,預設埠是 8080,開啟開發者頁面,也就是 index.html;
  • CONTRIBUTING.md:如何參與貢獻,也就是開發者或者 bug 發現者的指導書;
  • .husky:CesiumJS 使用 husky + lint-staged + prettier 來管理程式碼風格;

② Source 目錄

CesiumJS 的前端庫部分,主要就是在 Source 目錄下的。目前,Source 目錄下的程式碼檔案絕大多數已完成 ESModule 改造,含少量 css 檔案。

雖然幾乎所有的原始碼都是 ESModule 的,但是這個 Source 目錄並沒有 node 包經典的索引檔案 index.jsSource 目錄的入口索引檔案,是要執行 build 指令後才會出現的,檔名是 Cesium.js;這個入口索引檔案也沒什麼東西,主要是匯出原始碼中的所有模組,無論公開私有,以及著色器字串,以及當前 CesiumJS 的版本號。

下面對 Source 目錄的各個子資料夾作說明:

image

  • Assets,一些靜態資源,例如預設天空盒、離線兩級世界影像(TMS)等;
  • Core,數學 API、Geometry API、高頻輔助函式、資源與請求 API、Terrain API 等;
  • DataSources,基於 Scene 模組中較為底層的三維 API 再次封裝出來的上層 API,包括 Entity APIProperty APIDataSource API,旨在更易接入人類友好型資料格式,例如 Gpx、KML、GeoJson 以及 CesiumJS 官方設計的 Czml,熟讀之後可以自行建立,這三個 API 要結合 Viewer 使用,單獨的 Scene 模組無法執行;
  • Renderer,籠統地稱這個資料夾下的程式碼為 Renderer 模組,封裝並擴充套件了 WebGL 原生介面,例如 Framebuffer 對應 WebGLFramebuffer 等;
  • Scene,場景模組,基於 Core 模組和 Renderer 模組,CesiumJS 的三維世界由此模組建立,包括 Primitive APIModel APIGlobe/QuadtreePrimitive APIGPUPicking API3DTiles API 等重要 API,通常稱之為 Scene 模組,是 CesiumJS 的基石;含 ModelExperimental 新架構和 GltfPipeline 子模組;
  • Shaders,字尾名是 .glsl 的著色器程式碼檔案,build 指令執行後生成同名的 ESModule js 模組檔案,匯出著色器程式碼的字串;
  • ThirdParty,第三方庫,例如 draco 解碼庫以及相關的 worker 等;
  • Widgets,帶 UI 的一些功能型類,例如大家熟悉的 ViewerTimelineBaseLayerPicker,樣式檔案也在此目錄下;
  • Worker & WorkerES6,WebWorker 檔案,後者是原始碼,前者是根據後者在執行 build 指令後生成的 requirejs 版本。

③ Specs 目錄

這個是測試程式碼目錄。子目錄結構與 Source 下的基本一樣,要測試某個模組,則測試檔案以那個模組的檔名 + Spec 尾綴,例如想測試 Core/Matrix4.js 模組下的四階方陣類,那麼就建立一個 Specs/Core/Matrix4Spec.js(官方有了,你可以開啟學習)。

測試框架是 jasmine-core

④ App 目錄

使用 Source 目錄下的原始碼直接建立出來的現成應用程式,包括我們熟悉的 Sandcastle(沙盒)程式,還有兩個簡單的,有興趣自行開啟檢視(使用 start 這個命令啟動開發伺服器,從主頁進)。含少量測試資料。

⑤ [構建後] Build 目錄

執行 build/combine/minify 等指令,這個資料夾才會出現。它主要是釋出出來 CesiumJS 的 iife 庫版本,以及附帶必須要用的四大靜態資原始檔夾 - AssetsThirdPartyWidgetsWorkers

根據指令的不同,釋出的 iife 庫版本不一樣,也影響是不是有 TypeScript 型別定義檔案、SourceMap 對映檔案。

combine 指令釋出的是 CesiumUnminified 未壓縮版本,也就是主庫檔案有 37 萬行的版本;minify 指令釋出的是 Cesium 資料夾下的壓縮版本,程式碼經過簡化。

如下圖所示:

image

⑥ Documentation 目錄

文件目錄,使用 generateDocumentation 指令生成的 API 手冊,從開發者主頁可以進去。

⑦ ThirdParty 目錄

第三方依賴庫,CesiumJS 不希望安裝在 node-package-dependencies 列表中的就放在這裡,手動升級,並將依賴列表寫入根目錄下的 ThirdParty.extra.json 檔案內。

每當執行 prepare 這個 node-script 後,gulp 就會把這個目錄裡面的一些資源(測試框架、Draco 庫等)複製到指定位置。

⑧ Tools 目錄

gulp 部分任務需要用到的工具庫或配置,例如 rollup 額外配置、jsdoc 配置等。

未來可能的改進

官方論壇中有討論過 monorepo 技術的接入,也就是一工程多子庫的結構,見:Is there interest in a compact Cesium math library?

但是我認為在 3DTiles 1.1 推廣完畢、構建工具大換血之前,這個可能並不會有什麼實質性的推動,畢竟 CesiumJS 已經是 ESModule 格式的了,而且內部各種邏輯隨時可能按需求變動會改進,把 CesiumJS 本身拆成 monorepo 可能不太現實。

2. 構建命令

既然 CesiumJS 是作為一個 NodeJS 包存在的,那麼它就支援 node-script,也就是 package.json 裡的 “scripts”列表。

先介紹如果用到原始碼開發用到的常用指令:

  • prepare,在你安裝依賴(npm install)後會自動拉起的一個命令,會執行 gulp 同名任務,並安裝 husky 庫;
  • build,最初始的一個指令,將 Source 下的原始碼合併出一個 Source/Cesium.js,也就是 CesiumJS 原始碼的 ESModule 入口檔案,同時會把 Source/Shaders 下所有 glsl 檔案複製並改寫成匯出著色器字串的 js 檔案;另外,只有這個指令執行後在沙盒中才能看到開發者示例程式碼;
  • startstartPublic,啟動開發伺服器,後者允許公開訪問本機,預設 8080 埠
  • release,一個複合指令,先後執行 build → build-ts → combine → minifyRelease → generateDocumentation 指令;
  • generateDocumentation,使用 jsdoc 根據 Source 下的原始碼註釋生成 API 幫助文件;
  • makeZipFile,一個複合指令,先執行 release 指令後將指定的檔案壓縮成一個 zip 檔案,也就是每個月月初你在 GitHub 釋出頁面下載的那一個稍大的壓縮包;
  • combine,也是工程中 gulp 的預設任務,它會連著 build 指令一起執行,將 Source 下的原始碼使用 rollup 轉譯成 iife 庫,輸出到 Build/CesiumUnminified 目錄下,是未壓縮版本庫,37萬行,主檔案 12.3 MB;combienRelease 不輸出 sourcemap 檔案;
  • minify,與 combine 目的一樣,只不過告訴 rollup 要生成壓縮版本的庫,輸出到 Build/Cesium 目錄下;也有 minifyRelease 姐妹命令;
  • clean,清理 build/release/combine 等指令生成的產出檔案,恢復未構建時的乾淨工程狀態

然後是其它可能用到的:

  • prettierprettier-check,統一程式碼風格
  • test 等一系列 test 指令:執行 Specs 目錄下的測試程式碼

最後有一個隱藏的指令,這個允許你把 jsdoc 註釋為私有的 API,即 @private 註釋的,也在開發者文件中展示出來,但是這個指令並沒有在 node-script 列表中。

npm run generateDocumentation -- --private

這個功能來自 PR CesiumGS/cesium#10261

未來可能的改進

官方正在內測使用 esbuild 改進 gulp 和 rollup 的構建效能和質量,參考:CesiumGS/cesium#10399,目前已知使用 esbuild 構建後的主庫體積、SourceMap 檔案體積都有明顯的下降。

筆者也在官方論壇發起這項議題時參與了討論:CesiumJS Build Tooling Revamp

希望在不久的將來能用上檔案體積更小的庫。

3. 文章目錄

本篇即原始碼工程結構。

相關文章