调试Cesium源码分析并解决在Vite中使用遇到的问题

CesiumJS 库与所有构建系统和框架兼容。但是,考虑到渲染引擎的性质,在使用 Vitewebpack 时,您需要采取一些额外的步骤来为您的应用程序配置它。

尽管找各种资料完全可以很快照着完成,但各种配置背后的作用和原理 是什么呢?于是本文总结在 Vite 中使用CesiumJs详细步骤,并通过debug的方式分析并解决过程中出现的问题。

1. 创建账号获取token

使用Cesium需要注册Cesium ion账户(免费)获取token

2. 下载Cesium资源包

Cesium提供CDNnpm两种方式引入资源包。CDN方式这里不做赘述,看这里

使用npm下载cesium依赖:

npm install cesium

3. 引入控件样式文件、设置Ion默认token

widgets.css文件是cesium内置控件的样式,包括导航控件(Navigation)、时间轴控件(Timeline)、动画控件(Animation)、全屏按钮(Fullscreen Button)、地理编码搜索框(Geocoder)和场景模式切换器(SceneModePicker)等。

ts 复制代码
// main.ts
import "cesium/Build/Cesium/Widgets/widgets.css";
import { Ion } from 'cesium';
Ion.defaultAccessToken = 'your token';

3.1 设置Ion Token的作用

访问cesium的一些地图服务需要用到,如请求一些地形数据 (Terrain)、影像数据 (Imagery)、3D Tiles数据等。但如果不设置自己的token,在源码 中可以看到Ion有一个默认的token

js 复制代码
// packages/engine/Source/Core/Ion.js
const defaultAccessToken =
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZDdmNWJiNy0wMmNlLTQ1MWUtODM2YS02NGM1MTBlOGMwMWQiLCJpZCI6MjU5LCJpYXQiOjE3MzMxNTc4OTV9.B3URHf0VdHDtGckb-hv7uqATdn8KfvkiuoAFZUq8tAo";
const Ion = {};
Ion.defaultAccessToken = defaultAccessToken;

默认的token请求数量有限;注册用户token会有更多的月度配额;付费的token可以访问更高分辨率的数据等。

4. 创建一个demo_cesium.vue文件:

vue 复制代码
<!-- demo_cesium.vue -->
<template>
    <div id="cesiumContainer"></div>
</template>
<script lang="ts" setup>
import { Cartesian3, createOsmBuildingsAsync, Ion, Terrain, Viewer } from 'cesium';
import { onMounted } from 'vue';

// Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
onMounted(async () => {
    const viewer = new Viewer('cesiumContainer', {
        terrain: Terrain.fromWorldTerrain(),
    });

    // Fly the camera to San Francisco at the given longitude, latitude, and height.
    viewer.camera.flyTo({
        destination: Cartesian3.fromDegrees(-122.4175, 37.655, 400)
    });

    // Add Cesium OSM Buildings, a global 3D buildings layer.
    const buildingTileset = await createOsmBuildingsAsync();
    viewer.scene.primitives.add(buildingTileset);
})

</script>

<style lang="less" scoped>
#cesiumContainer {
    width: 100%;
    height: 100%;
}
</style>

打开浏览器devtool面板,发现如下报错:

根据报错链接进入source面板断点发现:

显然JSON.parse不能解析html文本,所以报错。在调用堆栈中找到上层函数调用:

发现 Resource.fetchJson 这个地址: "http://192.168.31.212:5173/welcome-to-my-website/node_modules/.vite/deps/Assets/approximateTerrainHeights.json"

那现在出现2个问题:

  1. 为什么fetchJson这个地址最终会变成JSON.parsehtml文本?
  2. "http://192.168.31.212:5173/welcome-to-my-website/node_modules/.vite/deps"这个前缀哪里来的?

第1个问题暂且可以搁置不管,解决报错需要寻找第2个问题的答案 。于是鼠标hoverbuildModuleUrl方法上:

点击[[FunctionLocation]]查看其实现:

同样的方式我们进入getCesiumBaseUrl方法:

发现源码中判断CESIUM_BASE_URL如果为空,就判断当前的模块环境,如果是ESM则是getAbsoluteUri(".", import.meta.url)其结果就是我们想要验证的前缀:"http://192.168.31.212:5173/welcome-to-my-website/node_modules/.vite/deps/"

所以我们要配置CESIUM_BASE_URL

4. 托管Cesium静态资源文件、配置 CESIUM_BASE_URL

4.1 配置CESIUM_BASE_URL的目的

CesiumJS 需要vite服务托管一些静态文件,例如 Web WorkerSVG 图标。那这些资源在哪呢?我们第一步安装cesium时,它们被安装到了node_modules下:

我们发现上图中箭头指向的Assets/approximateTerrainHeights.json文件正是上文debug解析的文件。

4.2 配置 CESIUM_BASE_URL

其实,开发阶段 我们完全可以直接通过 /node_modules/cesium ...去访问静态资源:

所以理论上我们将window.CESIUM_BASE_URL设置为/welcome-to-my-website/node_modules/cesium/Build/Cesium即可成功,验证如下:

ts 复制代码
// vite.config.ts

export default defineConfig({
    base: '/welcome-to-my-website',
    define: {
        CESIUM_BASE_URL: JSON.stringify(`/welcome-to-my-website/node_modules/cesium/Build/Cesium`),
    }
});

确实可以成功:

但既然使用了构建工具就必须考虑生成环境的打包路径。 正常打包vite会将所有静态资源都打包在assets下:

因此我们需要在开发环境生产环境 可以用同样的路径访问到 Cesium 静态资源,而viteStaticCopy包做了这件事。于是我们进行如下配置:

ts 复制代码
// vite.config.ts

import vue from "@vitejs/plugin-vue";
import { viteStaticCopy } from "vite-plugin-static-copy";

const base = "/welcome-to-my-website";

const cesiumSource = "node_modules/cesium/Build/Cesium";
const cesiumBaseUrl = "cesiumStatic";

export default defineConfig({
    base,
    define: {
        CESIUM_BASE_URL: JSON.stringify(`${base}/${cesiumBaseUrl}`),
    },
    plugins: [
        vue(),
        viteStaticCopy({
            targets: [
                { src: `${cesiumSource}/ThirdParty`, dest: cesiumBaseUrl },
                { src: `${cesiumSource}/Workers`, dest: cesiumBaseUrl },
                { src: `${cesiumSource}/Assets`, dest: cesiumBaseUrl },
                { src: `${cesiumSource}/Widgets`, dest: cesiumBaseUrl },
            ],
        }),
    ]
});

此时通过 http://192.168.31.212:5173/welcome-to-my-website/cesiumStatic/Assets/Images/ion-credit.png 也可以访问到静态资源:

再次打包发现新建了一个cesiumStatic目录存放cesium静态资源:

这样就可以更优雅的使用Cesium了:

4.3 简单概括viteStaticCopy做的事情:

  • 开发环境:映射访问,不复制 ➡️ 更快的开发体验

  • 生产环境:实际复制 ➡️ 确保部署后可用

最后:

其实,无论你是使用原生 html 还是 vite 又或者是 webpack,看 以下资料 就足以快速上手 Cesium。本文更想探寻的是 "照着写" 背后的原因、"不这么写为什么不行" 以及 "还可以怎么写"

  1. CesiumJS Quickstart
  2. Configuring Vite or Webpack for CesiumJS
  3. cesium-webpack-example
  4. cesium-vite-example
相关推荐
A XMan.3 小时前
JSON结构快捷转XML结构API集成指南
xml·java·前端·json·php
小林爱3 小时前
【Compose multiplatform教程06】用IDEA编译Compose Multiplatform常见问题
android·java·前端·kotlin·intellij-idea·compose·多平台
蜗牛快跑2136 小时前
前端正在被“锈”化
前端·代码规范
Jet_closer_burning8 小时前
微信小程序中遇到过的问题
前端·微信小程序·小程序
掘金酱9 小时前
稀土掘金社区2024年度影响力榜单正式公布
android·前端·后端
Keven__Java9 小时前
Java开发-后端请求成功,前端显示失败
java·开发语言·前端
轻口味9 小时前
【每日学点鸿蒙知识】渐变效果、Web组件注册对象报错、深拷贝list、loadContent数据共享、半屏弹窗
前端·list·harmonyos
老K(郭云开)9 小时前
最新版Chrome浏览器加载ActiveX控件技术——alWebPlugin中间件V2.0.28-迎春版发布
前端·chrome·中间件
轻口味9 小时前
【每日学点鸿蒙知识】子窗口方向、RichEdit不居中、本地资源缓存给web、Json转对象丢失方法、监听状态变量数组中内容改变
前端·缓存·harmonyos
我是苏苏9 小时前
Web开发:ORM框架之使用Freesql的分表分页写法
前端·数据库·sql