Vite 中零配置接入 Cesium.js:vite-plugin-cesium-engine 深度解析

痛点:CesiumJS 与 Vite 集成的 "四步仪式"

如果你曾经尝试在 Vite 项目中使用 CesiumJS,一定对那套繁琐的初始化流程印象深刻。在看到地球渲染出来之前,你必须依次完成:

  1. 手动拷贝 WASM Worker 与静态资源到构建输出目录
  2. 在任何 Cesium 模块加载之前 设置 window.CESIUM_BASE_URL
  3. 手动注入 CesiumWidget.css<link> 标签
  4. 想方设法把 Ion 访问令牌塞进打包产物

几乎每个项目的开局都如出一辙:从 StackOverflow 复制一段配置,改到开发环境能跑,一上线生产环境又崩了,然后陷入无限循环的调试。

本文要介绍的 vite-plugin-cesium-engine,就是为了让这一切彻底消失。

定位差异:专为 @cesium/engine 而生

社区里其实已经有几个 Cesium 的 Vite 插件,但它们无一例外都面向完整的 cesium 包 ------ 也就是自带整套 Viewer UI 的那个版本。

但如果你想要的是更轻量的 @cesium/engine 核心库(不包含任何 Widget 组件,完全由你自己掌控 UI 层),此前几乎没有现成方案,只能自己动手折腾。

vite-plugin-cesium-engine 的定位非常明确:只为 @cesium/engine 服务,不做全能型选手。

安装与基础使用

安装依赖

bash

bash 复制代码
# npm
npm i -D @cesium/engine vite-plugin-cesium-engine

# pnpm
pnpm add -D @cesium/engine vite-plugin-cesium-engine

# yarn
yarn add -D @cesium/engine vite-plugin-cesium-engine

最小配置

vite.config.ts 中引入插件即可:

typescript

运行

javascript 复制代码
import { defineConfig } from "vite";
import { cesiumEngine } from "vite-plugin-cesium-engine";

export default defineConfig({
  plugins: [cesiumEngine()],
});

这就是全部配置。不需要设置 CESIUM_BASE_URL,不需要写资源拷贝脚本,不需要手动导入 CSS。

然后在业务代码中直接使用:

typescript

运行

javascript 复制代码
import { CesiumWidget, Terrain } from "@cesium/engine";

const widget = new CesiumWidget(document.getElementById("app")!, {
  terrain: Terrain.fromWorldTerrain(),
});

插件自动完成的工作

这个插件在背后默默帮你搞定了四件事:

  • 构建时 :自动将 WASM Worker、编译产物和 CesiumWidget.css 拷贝到输出目录
  • HTML 注入 :在任何模块加载之前,将 window.CESIUM_BASE_URL 注入到页面中
  • CSS 注入 :自动添加 CesiumWidget.css<link> 标签
  • 开发服务器vite dev 时直接从 node_modules 提供静态资源,无需拷贝

主流框架集成示例

插件的配置在所有框架中完全一致,差异仅在于组件的生命周期钩子。

React

tsx

javascript 复制代码
import { useEffect, useRef } from "react";
import { CesiumWidget, Terrain } from "@cesium/engine";

export default function App() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!containerRef.current) return;
    const widget = new CesiumWidget(containerRef.current, {
      terrain: Terrain.fromWorldTerrain(),
    });
    return () => widget.destroy();
  }, []);

  return (
    <div
      ref={containerRef}
      style={{ width: "100%", height: "100vh" }}
    />
  );
}

Vue 3

vue

xml 复制代码
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from "vue";
import { CesiumWidget, Terrain } from "@cesium/engine";

const container = ref<HTMLDivElement>();
let widget: CesiumWidget;

onMounted(() => {
  widget = new CesiumWidget(container.value!, {
    terrain: Terrain.fromWorldTerrain(),
  });
});

onBeforeUnmount(() => widget?.destroy());
</script>

<template>
  <div ref="container" style="width: 100%; height: 100%" />
</template>

Svelte

svelte

xml 复制代码
<script lang="ts">
  import { onMount } from "svelte";
  import { CesiumWidget, Terrain } from "@cesium/engine";

  let container: HTMLDivElement;

  onMount(() => {
    const widget = new CesiumWidget(container, {
      terrain: Terrain.fromWorldTerrain(),
    });
    return () => widget.destroy();
  });
</script>

<div bind:this={container} style="width: 100%; height: 100%" />

原生 TypeScript

typescript

运行

javascript 复制代码
import { CesiumWidget, Terrain } from "@cesium/engine";

const widget = new CesiumWidget(document.getElementById("app")!, {
  terrain: Terrain.fromWorldTerrain(),
});

// 支持 HMR 热更新时的资源清理
if (import.meta.hot) {
  import.meta.hot.dispose(() => widget.destroy());
}

仓库的 examples/ 目录下提供了以上四种框架的完整可运行脚手架。

进阶配置

Ion 令牌:构建时注入

通过插件选项传入 Cesium Ion 访问令牌,它会在构建阶段被注入,无需在业务代码中写 Ion.defaultAccessToken = ...,也不需要运行时读取环境变量:

typescript

运行

scss 复制代码
cesiumEngine({
  ionToken: process.env.CESIUM_ION_TOKEN,
});

按环境区分令牌

传入一个 { [mode]: token } 的映射表,可以针对不同 Vite 模式使用不同令牌:

typescript

运行

php 复制代码
cesiumEngine({
  ionToken: {
    development: process.env.CESIUM_ION_TOKEN_DEV,
    production: process.env.CESIUM_ION_TOKEN_PROD,
  },
});
  • vite dev → 注入 CESIUM_ION_TOKEN_DEV
  • vite build → 注入 CESIUM_ION_TOKEN_PROD

插件还会在启动时校验令牌格式是否为合法 JWT,如果 .env 变量替换失败会立即给出警告,避免把问题带到生产环境才暴露。

虚拟模块:类型安全的运行时常量

插件暴露了一个 virtual:cesium 模块,让你可以在不触碰 window 全局变量的情况下读取运行时常量:

json

json 复制代码
// tsconfig.json
{
  "compilerOptions": {
    "types": ["vite-plugin-cesium-engine/virtual"]
  }
}

typescript

运行

javascript 复制代码
import { CESIUM_BASE_URL, ION_TOKEN } from "virtual:cesium";

console.log(CESIUM_BASE_URL); // "/cesium/"
console.log(ION_TOKEN);       // 你的令牌,或 null

这两个值都在构建时解析,如果未使用会被 tree-shaking 移除,不会增加产物体积。

自定义资源路径

对于 CDN 部署或有自己 public 目录约定的框架(如 Laravel、Rails),可以精确控制资源的输出位置和访问路径:

typescript

运行

arduino 复制代码
export default defineConfig({
  base: "/app/",
  plugins: [
    cesiumEngine({
      assetsPath: "vendor/cesium",        // 输出到 dist/vendor/cesium/
      cesiumBaseUrl: "/app/vendor/cesium", // 从此路径提供服务
    }),
  ],
});

如果 cesiumBaseUrl 不以 Vite 的 base 开头,插件会在启动时发出警告,把配置错误扼杀在开发阶段。

调试模式

如果资源注入不符合预期,开启 debug: true 会在开发服务器启动时打印完整的配置摘要:

typescript

运行

lua 复制代码
cesiumEngine({ debug: true });

输出示例:

plaintext

csharp 复制代码
[cesium-engine] mode         : development
[cesium-engine] vite base    : ""
[cesium-engine] cesiumBaseUrl: "/cesium"
[cesium-engine] assetsPath   : "cesium"
[cesium-engine] ionToken     : eyJhbGciOiJ... (mode: development)
[cesium-engine] copying assets:
  ThirdParty/*.wasm → cesium/ThirdParty
  Build/*           → cesium
  Source/Assets/    → cesium
  Widget/*.css      → cesium/Widget

已知问题:protobufjs 的 eval 警告

构建时你可能会看到这样一条 Rollup 警告:

plaintext

bash 复制代码
[EVAL] Use of direct eval function is strongly discouraged
node_modules/protobufjs/dist/minimal/protobuf.js

这来自 @cesium/engine 的传递依赖 protobufjs。该库中的 eval 是有意为之,不存在安全问题。可以在 vite.config.ts 中静默掉这条警告:

typescript

运行

ini 复制代码
build: {
  rollupOptions: {
    onwarn(warning, defaultHandler) {
      if (warning.code === "EVAL" && warning.id?.includes("protobufjs")) return;
      defaultHandler(warning);
    },
  },
},

零运行时依赖

这个插件本身没有任何运行时依赖 ------ 只使用了 Node 内置模块(node:fsnode:path)和 Vite 自身的插件 API。安装它不会给你的项目带来任何额外的第三方包。

总结

vite-plugin-cesium-engine 用一个极简的插件接口,解决了 CesiumJS 与 Vite 集成中长期存在的配置碎片化问题。它的设计哲学很清晰:

  • 专注 :只做 @cesium/engine,不追求大而全
  • 零配置:默认行为覆盖 90% 的使用场景
  • 类型安全:通过虚拟模块提供带类型的运行时常量
  • 错误前置:令牌校验、路径校验都在启动时完成

如果你正在用 Vite 构建三维地球应用,并且希望摆脱繁琐的资源配置,这个插件值得一试。

相关链接:

相关推荐
To_OC2 小时前
后端接口还没交付,前端如何独立把整套业务跑通
前端·react.js·全栈
王琦03182 小时前
WEB服务
前端
霹雳桃2 小时前
Vue3 + Vite 构建版本注入实战:一份 version.json 终结「线上到底是哪一版」
前端
黄金决明子2 小时前
浏览器Window底层操作全解
前端·javascript
ydyd202604213 小时前
设备OEE怎么提升?数据采集+分析优化的完整方案
java·服务器·前端
(╹◡╹)3 小时前
11.RK3588本地大模型内存评估优化
java·linux·前端
电气研究所3 小时前
Java + Redis 实现工业设备告警去抖,避免变频器故障重复推送
java·前端
AI视觉网奇3 小时前
cannot import name ‘model_urls‘ from ‘torchvision.models.resnet‘
linux·前端·javascript