很高興你能在浮躁的年代裏還有興趣閱讀源代碼,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. 文章目錄
本篇即源碼工程結構。