# How to Configure Vite for CesiumJS Assets in God’s Eye View

> Configure Vite for CesiumJS assets in God's Eye View. Use createBrowserViteConfig to copy static assets, inject API tokens, and enforce security with vite-plugin-cesium.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: how-to-guide
- Published: 2026-09-13

---

**To configure Vite for CesiumJS assets in God’s Eye View, use the `createBrowserViteConfig` helper in [`build/vite.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/build/vite.js) with `vite-plugin-cesium` to copy static assets, inject API tokens via the `define` option, and enforce security policies through `server.fs.deny` and host restrictions.**

God’s Eye View treats CesiumJS as an external dependency to prevent duplicate bundles and ensure consistent 3-D tile rendering across the application. The build-time configuration lives in [`build/vite.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/build/vite.js) and exposes a factory function that assembles the necessary plugins, environment definitions, and server security rules required to serve Cesium’s workers and textures correctly in both development and production environments.

## Core Vite Configuration Architecture

### The createBrowserViteConfig Helper

The central configuration logic resides in **[`build/vite.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/build/vite.js)**, which exports the `createBrowserViteConfig` function. This factory accepts parameters for API keys, host settings, and additional plugins, returning a plain Vite configuration object that the development server and production builds consume.

```javascript
// build/vite.js
import cesium from 'vite-plugin-cesium';

export function createBrowserViteConfig({
  plugins = [],
  googleApiKey,
  cesiumToken,
  host = 'localhost',
  port = 4173,
} = {}) {
  return {
    plugins: [cesium(), ...plugins],
    server: {
      host,
      port: parseInt(port, 10) || 4173,
      allowedHosts:
        host === '0.0.0.0' || host === '::' ? true : ['localhost', '127.0.0.1', '.local'],
      fs: {
        deny: ['.env', '.env.*', '*.{crt,pem}', '**/.git/**', '**/ENVIRONMENT'],
      },
      headers: {
        'X-Frame-Options': 'DENY',
        'Content-Security-Policy': "frame-ancestors 'none'",
      },
    },
    define: {
      'import.meta.env.GOOGLE_MAPS_API_KEY': JSON.stringify(googleApiKey),
      'import.meta.env.CESIUM_ION_TOKEN': JSON.stringify(cesiumToken),
    },
    build: { chunkSizeWarningLimit: 1500 },
  };
}

```

### vite-plugin-cesium Integration

The **`vite-plugin-cesium`** plugin is the only build tool in the chain that understands Cesium’s static asset structure. It automatically discovers and copies directories such as `Build/Cesium/Assets`, `Workers`, and `ThirdParty` into the Vite output folder while preserving the relative paths that Cesium’s runtime expects. During production builds, the plugin rewrites URLs generated by `Cesium.buildModuleUrl()` to point at the bundled locations.

### Secure Environment Variable Injection

Rather than exposing `.env` files to the client, the configuration uses Vite’s **`define`** option to statically replace global identifiers at build time. The `GOOGLE_MAPS_API_KEY` and `CESIUM_ION_TOKEN` are injected as `import.meta.env` properties, allowing Cesium to fetch 3-D tiles without leaking secrets into the static asset directory.

## Security Hardening and Server Rules

### File System Restrictions

The **`server.fs.deny`** array explicitly blocks Vite from serving sensitive files. According to the source in [`build/vite.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/build/vite.js), the server refuses access to `.env` files, certificates (`*.crt`, `*.pem`), Git repositories, and any file named `ENVIRONMENT`, ensuring that Cesium asset serving does not accidentally expose credentials.

### Network Host Policies

The **`allowedHosts`** configuration adapts based on the `host` parameter. When binding to `0.0.0.0` or `::`, all hosts are permitted; otherwise, the server restricts traffic to `localhost`, `127.0.0.1`, and `.local` domains. Combined with `X-Frame-Options: DENY` and a strict Content Security Policy, these settings protect the Cesium canvas from clickjacking and cross-origin attacks.

## Asset Pipeline and Build Optimization

### Static Asset Handling

In **development mode**, `vite-plugin-cesium` serves assets directly from the Cesium source folder, enabling hot module replacement without rebuilding the entire Cesium distribution. In **production**, the plugin copies assets into the `dist` directory and rewrites internal URLs so that `Cesium.buildModuleUrl('Worker.js')` resolves correctly to the hashed output files.

### Single Instance Enforcement

The project’s **[`docs/CODE-BOUNDARIES.md`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/docs/CODE-BOUNDARIES.md)** mandates that consumers provide exactly one Cesium instance to prevent worker duplication and memory leaks. The Vite configuration enforces this by externalizing Cesium (loaded via `import * as Cesium from 'cesium'` in modules like [`src/worldFocus.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/worldFocus.js)) and delegating all asset management to the plugin, guaranteeing that only one copy of the library and its workers exists in the final bundle.

## Practical Implementation Examples

### Starting a Development Server

The `scripts/pinokio-start.mjs` file demonstrates how to bootstrap the Vite runtime with the Cesium-enabled configuration after the global environment is prepared:

```javascript
// scripts/pinokio-start.mjs
import { createBrowserViteConfig } from '../build/vite.js';

export async function startDevServer() {
  const vite = await loadViteFromCanonicalRoot();
  const config = createBrowserViteConfig({
    googleApiKey: process.env.GOOGLE_MAPS_API_KEY,
    cesiumToken: process.env.CESIUM_ION_TOKEN,
  });
  const server = await vite.createServer(config);
  await server.listen();
}

```

### Importing Cesium in Application Code

Application modules such as **[`src/worldFocus.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/worldFocus.js)** rely on the Vite configuration being active to resolve the `cesium` import and access the bundled assets:

```javascript
// src/worldFocus.js
import * as Cesium from 'cesium';

export function focusOnTarget(viewer, target) {
  const boundingSphere = new Cesium.BoundingSphere(target.position, target.radiusM);
  viewer.camera.flyToBoundingSphere(boundingSphere, {
    offset: new Cesium.HeadingPitchRange(
      Cesium.Math.toRadians(target.headingDeg),
      Cesium.Math.toRadians(target.pitchDeg),
      target.distanceM
    ),
    easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT,
  });
}

```

### Headless Rendering Configuration

For QA and automated testing, **`tools/cesium-render.mjs`** reuses the same Vite configuration to spin up a Puppeteer-controlled browser instance, proving that the asset pipeline works identically in headless environments:

```javascript
// tools/cesium-render.mjs
import puppeteer from 'puppeteer';
import { createBrowserViteConfig } from '../build/vite.js';

export async function renderCesiumScene({ googleApiKey, cesiumToken, url }) {
  const vite = await import('vite');
  const config = createBrowserViteConfig({ googleApiKey, cesiumToken });
  const server = await vite.createServer(config);
  await server.listen();

  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(`http://localhost:${config.server.port}${url}`);
  // Capture screenshot logic here...
  await browser.close();
  await server.close();
}

```

## Summary

- **Use `createBrowserViteConfig`** from [`build/vite.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/build/vite.js) as the single source of truth for all Cesium-enabled Vite builds in God’s Eye View.
- **Install `vite-plugin-cesium`** to automatically copy workers, textures, and static assets while preserving Cesium’s expected directory structure.
- **Inject tokens via `define`** rather than exposing `.env` files, keeping `GOOGLE_MAPS_API_KEY` and `CESIUM_ION_TOKEN` secure.
- **Enforce `server.fs.deny`** rules to block access to certificates and environment files during asset serving.
- **Depend on the plugin’s externalization** to guarantee only one Cesium instance exists, preventing duplicate worker bundles as documented in [`docs/CODE-BOUNDARIES.md`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/docs/CODE-BOUNDARIES.md).

## Frequently Asked Questions

### How does God’s Eye View prevent duplicate Cesium bundles in the Vite build?

According to [`docs/CODE-BOUNDARIES.md`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/docs/CODE-BOUNDARIES.md), the project treats Cesium as an external dependency that must be supplied by the consumer. The `vite-plugin-cesium` plugin handles all static assets and ensures that `import * as Cesium from 'cesium'` resolves to a single instance, preventing the memory leaks and worker conflicts that occur when multiple Cesium copies load simultaneously.

### Why does the Vite configuration block access to `.env` files?

The `server.fs.deny` array in [`build/vite.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/build/vite.js) explicitly lists `.env`, `.env.*`, and certificate files to prevent the development server from accidentally exposing secrets when serving Cesium’s static assets. API keys are instead injected safely via the `define` configuration, which performs static replacement at build time without placing sensitive data in the public directory.

### Can the same Vite configuration be used for headless browser testing?

Yes. The `tools/cesium-render.mjs` utility imports `createBrowserViteConfig` to start a Vite server that Puppeteer can connect to for screenshots. This demonstrates that the asset copying, URL rewriting, and environment injection work identically in both interactive development and automated CI environments.

### What is the purpose of the `allowedHosts` logic in the server configuration?

The conditional `allowedHosts` setting supports both local development and network-wide testing. When the `host` parameter is set to `0.0.0.0` or `::`, the server allows any interface; otherwise, it restricts connections to localhost and `.local` domains, ensuring that Cesium asset previews remain secure while remaining flexible for containerized or LAN-based workflows.