很高興你能在浮躁的年代裡還有興趣閱讀原始碼,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.js
;Source
目錄的入口索引檔案,是要執行 build
指令後才會出現的,檔名是 Cesium.js
;這個入口索引檔案也沒什麼東西,主要是匯出原始碼中的所有模組,無論公開私有,以及著色器字串,以及當前 CesiumJS 的版本號。
下面對 Source 目錄的各個子資料夾作說明:
- Assets,一些靜態資源,例如預設天空盒、離線兩級世界影像(TMS)等;
- Core,數學 API、
Geometry API
、高頻輔助函式、資源與請求 API、Terrain API
等; - DataSources,基於 Scene 模組中較為底層的三維 API 再次封裝出來的上層 API,包括
Entity API
、Property API
和DataSource API
,旨在更易接入人類友好型資料格式,例如 Gpx、KML、GeoJson 以及 CesiumJS 官方設計的 Czml,熟讀之後可以自行建立,這三個 API 要結合Viewer
使用,單獨的 Scene 模組無法執行; - Renderer,籠統地稱這個資料夾下的程式碼為 Renderer 模組,封裝並擴充套件了 WebGL 原生介面,例如
Framebuffer
對應WebGLFramebuffer
等; - Scene,場景模組,基於 Core 模組和 Renderer 模組,CesiumJS 的三維世界由此模組建立,包括
Primitive API
、Model API
、Globe/QuadtreePrimitive API
、GPUPicking API
、3DTiles API
等重要 API,通常稱之為 Scene 模組,是 CesiumJS 的基石;含ModelExperimental
新架構和GltfPipeline
子模組; - Shaders,字尾名是
.glsl
的著色器程式碼檔案,build
指令執行後生成同名的 ESModule js 模組檔案,匯出著色器程式碼的字串; - ThirdParty,第三方庫,例如 draco 解碼庫以及相關的 worker 等;
- Widgets,帶 UI 的一些功能型類,例如大家熟悉的
Viewer
、Timeline
、BaseLayerPicker
,樣式檔案也在此目錄下; - 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 庫版本,以及附帶必須要用的四大靜態資原始檔夾 - Assets
、ThirdParty
、Widgets
、Workers
。
根據指令的不同,釋出的 iife 庫版本不一樣,也影響是不是有 TypeScript 型別定義檔案、SourceMap 對映檔案。
combine
指令釋出的是 CesiumUnminified
未壓縮版本,也就是主庫檔案有 37 萬行的版本;minify
指令釋出的是 Cesium
資料夾下的壓縮版本,程式碼經過簡化。
如下圖所示:
⑥ 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 檔案;另外,只有這個指令執行後在沙盒中才能看到開發者示例程式碼;start
和startPublic
,啟動開發伺服器,後者允許公開訪問本機,預設 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 等指令生成的產出檔案,恢復未構建時的乾淨工程狀態
然後是其它可能用到的:
prettier
和prettier-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. 文章目錄
本篇即原始碼工程結構。