jjzjj

CesiumJS 2022^ 源码解读[0] - 文章目录与源码工程结构

岭南灯火 2023-03-28 原文

很高兴你能在浮躁的年代里还有兴趣阅读源代码,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 目录的各个子文件夹作说明:

  • 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 文件夹下的压缩版本,代码经过简化。

如下图所示:

⑥ 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. 文章目录

本篇即源码工程结构。

有关CesiumJS 2022^ 源码解读[0] - 文章目录与源码工程结构的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

  3. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  4. ruby-on-rails - 如何在 Gem 中获取 Rails 应用程序的根目录 - 2

    是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在

  5. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  6. ruby-on-rails - 一般建议和推荐的文件夹结构 - Sinatra - 2

    您将如何构建一个简单的Sinatra应用程序?我正在制作,我希望该应用具有以下功能:“应用程序”更像是一个包含所有信息的管理仪表板。然后另一个应用程序将通过REST访问信息。我还没有创建仪表板,只是从数据库中获取东西session和身份验证(尚未实现)您可以上传图片,其他应用可以显示这些图片我已经使用RSpec创建了一个测试文件通过Prawn生成报告目前的设置是这样的:app.rbtest_app.rb因为我实际上只有应用程序和测试文件。到目前为止,我已经将Datamapper用于ORM,将SQLite用于数据库。这是我的第一个Ruby/Sinatra项目,所以欢迎任何和所有建议-我应

  7. ruby-on-rails - 没有这样的文件或目录 - 用 Mini Magick 识别 - 2

    在我让另一个人重做我的前端UI之前,我的Rails应用程序运行平稳。我已经尝试解决此错误3天了。这是错误:Nosuchfileordirectory-identifyExtractedsource(aroundline#59):575859606162@post=Post.find(params[:id])authorize@postif@post.update_attributes(post_params)flash[:notice]="Postwasupdated."redirect_to[@topic,@post]else{"utf8"=>"✓","_method"=>"patc

  8. ruby - Sinatra 找不到 View 目录 - 2

    我正在尝试以一种更类似于普通RubyGem结构的方式构建我的Sinatra应用程序。我有以下文件树:.├──app.rb├──config.ru├──Gemfile├──Gemfile.lock├──helpers│  ├──dbconfig.rb│  ├──functions.rb│  └──init.rb├──hidden│  └──Rakefile├──lib│  ├──admin.rb│  ├──api.rb│  ├──indexer.rb│  ├──init.rb│  └──magnet.rb├──models│  ├──init.rb│  ├──invite.rb│  ├─

  9. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

  10. ruby-on-rails - 在 Rails 中需要整个目录树的好方法是什么? - 2

    我正在使用Rails3.2.2并希望递归加载某个目录中的所有代码。例如:[Railsroot]/lib/my_lib/my_lib.rb[Railsroot]/lib/my_lib/subdir/support_file_00.rb[Railsroot]/lib/my_lib/subdir/support_file_01.rb...基于谷歌搜索,我试过:config.autoload_paths+=["#{Rails.root.to_s}/lib/my_lib/**"]config.autoload_paths+=["#{Rails.root.to_s}/lib/my_lib/**/"

随机推荐