# Understanding the Build Process for Open-SEO: Vite, TypeScript, and Cloudflare Workers

> Discover the open-seo build process using Vite, TypeScript, and Cloudflare Workers. Learn how to bundle UI and worker code efficiently and optimize bundle sizes.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: internals
- Published: 2026-09-11

---

**The open-seo build process uses Vite to bundle both the React UI and Cloudflare Worker code, followed by TypeScript type-checking via `tsc --noEmit`, utilizing a custom lean-worker-bundle plugin to strip heavy dependencies and enforce strict bundle size constraints.**

Open-SEO is a modern SEO toolkit designed for edge deployment on Cloudflare Workers. Understanding the build process for open-seo reveals how the project balances rapid bundling with strict type safety and minimal worker bundle sizes. The pipeline orchestrates Vite, TypeScript, and custom plugins defined in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) and [`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts) to create a deterministic, fast build suitable for serverless edge environments.

## Build Pipeline Overview

The complete build sequence follows a four-stage pipeline defined in the repository root. According to the source code in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) (lines 13-14), the production build combines Vite bundling with TypeScript validation to ensure both functional correctness and type integrity.

The pipeline executes as follows:

1. **Dependency Installation** – Packages are installed via `pnpm install` as specified in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json).
2. **Vite Bundling** – The `vite build` command bundles the React UI and Cloudflare Worker code, applying the custom `leanWorkerBundle()` plugin to enforce size constraints.
3. **Type-Checking** – The `tsc --noEmit` command validates TypeScript types without emitting additional files, as configured in [`tsconfig.json`](https://github.com/every-app/open-seo/blob/main/tsconfig.json) (lines 21-22).
4. **Optional Source Maps** – When `POSTHOG_SOURCEMAPS=true`, the build outputs to `dist-sourcemaps` instead of the standard `dist` directory.

## Core Configuration Files

### Vite Configuration ([`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts))

The [`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts) file orchestrates the entire bundling process. Lines 10-45 define the core build logic, including environment variable loading via `loadEnv` and conditional source-map generation.

The configuration registers several critical plugins as shown in lines 45-60:

```typescript
plugins: [
  leanWorkerBundle(),
  showDevtools ? devtools({ /* … */ }) : null,
  cloudflare({ inspectorPort: false, viteEnvironment: { name: "ssr" } }),
  tsConfigPaths(),
  tanstackStart(),
  viteReact(),
  tailwindcss(),
],

```

The build output directory and source-map settings are conditionally set based on the `POSTHOG_SOURCEMAPS` environment variable (lines 42-44):

```typescript
build: {
  sourcemap: emitSourcemaps,
  outDir: emitSourcemaps ? "dist-sourcemaps" : "dist",
}

```

### TypeScript Configuration ([`tsconfig.json`](https://github.com/every-app/open-seo/blob/main/tsconfig.json))

The TypeScript compiler operates in strict mode with `noEmit: true` as defined in lines 21-22 of [`tsconfig.json`](https://github.com/every-app/open-seo/blob/main/tsconfig.json). This ensures the project type-checks without producing redundant output files, since Vite handles the actual JavaScript emission.

```json
{
  "compilerOptions": {
    "noEmit": true,
    "strict": true
  }
}

```

## The Lean Worker Bundle Plugin

The custom [`vite-plugin-lean-worker-bundle.ts`](https://github.com/every-app/open-seo/blob/main/vite-plugin-lean-worker-bundle.ts) implements aggressive bundle optimization critical for Cloudflare Workers' size constraints. The plugin operates during the `generateBundle` phase (lines 65-66 and 76-84) to analyze the static import graph.

The plugin performs three specific optimizations:

- **Dependency Aliasing** – Heavy packages including `just-bash` and `workers-ai-provider` are replaced with stub files to prevent them from entering the eager startup bundle.
- **Zod Locale Optimization** – The plugin replaces Zod's multilingual locale barrel with an English-only export (`export { default as en } from "./en.js"`), significantly reducing bundle size.
- **Eager-Denylist Enforcement** – During `generateBundle`, the plugin traverses the worker entry chunks' import graph. If any module matches the deny-list (specifically `dataforseo-client`, `autumn-js`, or `cheerio`), the build aborts with an explicit error message.

## Step-by-Step Build Execution

To execute the build process for open-seo locally, use the following commands:

```bash

# Install dependencies

pnpm install

# Standard production build

npm run build

# Executes: vite build && tsc --noEmit

# Build with PostHog source maps

POSTHOG_SOURCEMAPS=true npm run build

# Preview the production build locally

npm run preview

```

The `npm run build` command defined in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) chains the bundling and type-checking phases to ensure both steps complete successfully before the build is considered valid.

## Deployment and Source Maps

While not strictly part of the compilation step, the deployment workflow relies on the build artifacts. The `npm run deploy` script (defined in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) lines 17-20) executes database migrations, triggers the build, and then invokes `wrangler deploy` to push the bundle to Cloudflare's edge network.

For staging environments, the `npm run deploy:postgres` command utilizes the Alchemy CLI with a production `.env` configuration to handle infrastructure provisioning alongside code deployment.

Source map generation is controlled entirely by the `POSTHOG_SOURCEMAPS` environment variable. When enabled, the build outputs to the `dist-sourcemaps` directory instead of `dist`, enabling error tracking and observability in production without affecting the default bundle size.

## Summary

- The open-seo build process combines **Vite bundling** with **TypeScript type-checking** via the `vite build && tsc --noEmit` command sequence in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json).
- The custom **[`vite-plugin-lean-worker-bundle.ts`](https://github.com/every-app/open-seo/blob/main/vite-plugin-lean-worker-bundle.ts)** enforces strict bundle size limits by stubbing heavy dependencies, optimizing Zod locales, and blocking deny-listed modules like `cheerio` and `autumn-js`.
- **Source maps** are conditionally emitted to `dist-sourcemaps` when `POSTHOG_SOURCEMAPS=true`, controlled by logic in [`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts) (lines 42-44).
- **TypeScript** operates in `noEmit` mode as configured in [`tsconfig.json`](https://github.com/every-app/open-seo/blob/main/tsconfig.json) (lines 21-22), ensuring type safety without duplicating Vite's emission process.
- Deployment uses **Wrangler** via `npm run deploy` to push the optimized bundle to Cloudflare Workers.

## Frequently Asked Questions

### What bundler does open-seo use for production builds?

Open-SEO uses **Vite** as its primary bundler, configured in [`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts). The build process bundles both the React UI components and the Cloudflare Worker entry points using a custom plugin architecture that includes the Cloudflare Vite plugin (`@cloudflare/vite-plugin`) for SSR environment handling.

### How does the lean-worker-bundle plugin prevent bundle bloat?

The `leanWorkerBundle()` plugin enforces size constraints through three mechanisms: **aliasing** heavy packages like `just-bash` to stub files, **swapping** Zod's multilingual locale barrel for an English-only export, and **deny-listing** specific modules (`dataforseo-client`, `autumn-js`, `cheerio`) that trigger build failures if they appear in the worker's eager import graph during the `generateBundle` phase.

### Why does the build run `tsc --noEmit` after Vite bundling?

The `tsc --noEmit` command performs **type-checking without emitting files**, as specified in [`tsconfig.json`](https://github.com/every-app/open-seo/blob/main/tsconfig.json) (line 21). Since Vite handles the actual JavaScript and asset emission, running TypeScript with `noEmit: true` ensures complete type validation across the codebase without producing redundant output files or interfering with Vite's bundling process.

### How do you generate source maps for error tracking in open-seo?

Set the environment variable `POSTHOG_SOURCEMAPS=true` before running `npm run build`. When enabled, [`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts) (lines 42-44) configures the build to emit source maps and output the bundle to `dist-sourcemaps` instead of the standard `dist` directory, enabling integration with PostHog's error tracking and observability platform.