# Configuration and Workflow for Building and Packaging TUUI with Vite and electron-builder

> Learn the configuration and workflow for building and packaging TUUI with Vite and electron-builder. This guide covers bundling Vue 3, Electron processes, and creating native installers.

- Repository: [AIQL/tuui](https://github.com/ai-ql/tuui)
- Tags: how-to-guide
- Published: 2026-02-23

---

**TUUI uses a dual-stage build pipeline where Vite bundles the Vue 3 renderer interface alongside Electron's main and preload processes, then electron-builder packages the compiled `dist/` output into native installers for macOS, Windows, and Linux.**

TUUI (ai-ql/tuui) is an Electron desktop application built with Vue 3 and Vuetify. Its build system orchestrates Vite for frontend bundling and electron-builder for native packaging. The workflow is defined across `vite.config.mts`, [`buildAssets/builder/config.js`](https://github.com/ai-ql/tuui/blob/main/buildAssets/builder/config.js), and npm scripts in [`package.json`](https://github.com/ai-ql/tuui/blob/main/package.json).

## Key Configuration Files

The build pipeline relies on three primary files to coordinate the Vite and electron-builder integration:

| File | Purpose |
|------|---------|
| **`vite.config.mts`** | Configures Vite for the renderer process and registers separate builds for the Electron main ([`src/main/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/index.ts)) and preload ([`src/preload/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/preload/index.ts)) entry points. |
| **[`buildAssets/builder/config.js`](https://github.com/ai-ql/tuui/blob/main/buildAssets/builder/config.js)** | Defines electron-builder packaging rules, including product metadata, target platforms, icon paths, and file exclusion patterns. |
| **[`package.json`](https://github.com/ai-ql/tuui/blob/main/package.json)** | Contains npm scripts that orchestrate the development and production workflows, plus dependency versions for `vite`, `electron`, and `electron-builder`. |

## Vite Configuration for Electron

The `vite.config.mts` file centralizes the build logic for all three Electron processes. It uses `vite-plugin-electron` to inject the main and preload builds into the Vite pipeline.

### Renderer Process Setup

The renderer configuration targets the Vue 3 frontend located in `src/renderer/`. It registers plugins for Vue single-file components, JSX support, and Vuetify auto-importing:

```typescript
// vite.config.mts (renderer section)
root: resolve('./src/renderer'),
publicDir: resolve('./src/renderer/public'),
base: './',
plugins: [
  Vue(),
  VueJsx(),
  VuetifyPlugin({ autoImport: true }),
  RendererPlugin()  // Enables Node.js integration in renderer
]

```

### Main and Preload Process Builds

The `ElectronPlugin` accepts an array of `ElectronOptions` that define separate Vite builds for the main and preload scripts. Each entry specifies its TypeScript entry point, output directory, and Rollup externals:

```typescript
// vite.config.mts (Electron entry points)
const electronPluginConfigs: ElectronOptions[] = [
  {
    entry: 'src/main/index.ts',
    onstart({ startup }) { startup() },
    vite: {
      root: resolve('.'),
      build: {
        outDir: 'dist/main',
        rollupOptions: {
          external: ['electron', ...builtinModules]
        }
      }
    }
  },
  {
    entry: 'src/preload/index.ts',
    onstart({ reload }) { reload() },
    vite: {
      root: resolve('.'),
      build: { outDir: 'dist/preload' }
    }
  }
]

```

### Environment Variable Injection

The configuration merges environment variables from `.env` files so both the renderer and Electron processes access the same values:

```typescript
process.env = { ...loadEnv(mode, process.cwd()), ...process.env }

```

Additionally, the config removes stale build artifacts before each run:

```typescript
rmSync('dist', { recursive: true, force: true })

```

## electron-builder Configuration

The [`buildAssets/builder/config.js`](https://github.com/ai-ql/tuui/blob/main/buildAssets/builder/config.js) file defines how electron-builder packages the compiled `dist/` output into platform-specific installers.

### Core Packaging Settings

The configuration reads product metadata from [`package.json`](https://github.com/ai-ql/tuui/blob/main/package.json) and defines universal packaging rules:

```javascript
// buildAssets/builder/config.js
const packageJson = require('../../package.json')

const baseConfig = {
  productName: packageJson.name,        // "tuui"
  appId: packageJson.appId,             // "com.tuui.app"
  asar: true,
  compression: 'maximum',
  artifactName: '${productName}__${version}_${os}_${arch}.${ext}',
  directories: {
    output: './release/${version}'
  }
}

```

### Platform-Specific Targets

The config defines distinct build targets for each operating system:

**macOS** (DMG with hardened runtime):

```javascript
mac: {
  hardenedRuntime: true,
  icon: 'buildAssets/icons/icon.icns',
  target: [
    { target: 'dmg', arch: ['x64', 'arm64', 'universal'] }
  ]
}

```

**Windows** (multiple formats):

```javascript
win: {
  icon: 'buildAssets/icons/icon.ico',
  target: [
    { target: 'appx', arch: 'x64' },
    { target: 'zip', arch: 'x64' },
    { target: 'portable', arch: 'x64' },
    { target: 'nsis', arch: 'x64' }
  ]
}

```

**Linux** (DEB, RPM, Snap):

```javascript
linux: {
  executableName: packageJson.name.toLowerCase(),
  icon: 'buildAssets/icons',
  target: [
    { target: 'snap', arch: 'x64' },
    { target: 'deb', arch: 'x64' },
    { target: 'rpm', arch: 'x64' },
    { target: 'tar.gz', arch: 'x64' }
  ]
}

```

### File Inclusion and Exclusion Rules

The `files` array controls which compiled assets are packaged, while excluding development artifacts:

```javascript
files: [
  'dist/**/*',
  '!dist/main/index.dev.js',
  '!docs/**/*',
  '!tests/**/*',
  '!release/**/*'
]

```

Static assets required by the main process at runtime are copied via `extraResources`:

```javascript
extraResources: [
  { from: 'src/main/assets', to: 'assets' }
]

```

## Build Workflow and npm Scripts

The [`package.json`](https://github.com/ai-ql/tuui/blob/main/package.json) scripts orchestrate the entire build pipeline, from development hot-reload to multi-platform distribution.

### Development Mode

The `dev` script launches Vite with the configuration from `vite.config.mts`, which automatically starts the Electron process:

```bash
npm run dev

```

This enables hot-module replacement for the Vue renderer and automatic restarts when `src/main` or `src/preload` files change.

### Production Build Pipeline

The `build:pre` script performs quality checks and compiles the production bundle:

```bash
npm run build:pre

```

This executes three steps sequentially:

1. **Lint and format** – `npm run format:fix`
2. **Type checking** – `vue-tsc --noEmit` validates TypeScript across the entire project
3. **Vite production build** – `vite build` outputs to `dist/`

### Platform-Specific Packaging

The main `build` script runs the full pipeline and invokes electron-builder:

```bash
npm run build

```

This executes `build:pre` followed by `electron-builder --config=buildAssets/builder/config.js`.

Platform-specific shortcuts are available:

- **`npm run build:mac`** – `electron-builder --mac`
- **`npm run build:win`** – `electron-builder --win`
- **`npm run build:linux`** – `electron-builder --linux`

For CI environments, the `build:all` script generates artifacts for all platforms:

```bash
npm run build:all

# Equivalent to: electron-builder -wml (Windows, macOS, Linux)

```

## Practical Build Examples

### Running the Application in Development

Start the hot-reload development environment:

```bash

# Install dependencies

npm ci

# Launch Vite dev server and Electron

npm run dev

```

The renderer updates instantly on Vue file changes, while the main process restarts when [`src/main/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/index.ts) or [`src/preload/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/preload/index.ts) are modified.

### Creating a Windows Installer

Generate a production Windows package with NSIS:

```bash
npm run build:win

```

The output appears at `release/1.4.1/tuui__1.4.1_win_x64.exe` (path derived from the `artifactName` template in [`buildAssets/builder/config.js`](https://github.com/ai-ql/tuui/blob/main/buildAssets/builder/config.js)).

### Building for Multiple Platforms in CI

On a Linux CI runner, generate all platform artifacts:

```bash
npm run build:all

```

This produces:
- **macOS**: `tuui__1.4.1_mac_universal.dmg`
- **Windows**: `tuui__1.4.1_win_x64.exe` (NSIS), `.zip`, `.appx`
- **Linux**: `.deb`, `.rpm`, `.snap`, and `.tar.gz` archives

### Configuring Environment Variables

Create a `.env` file in the project root:

```bash

# .env

VITE_API_URL=https://api.example.com
VITE_FEATURE_FLAG=true

```

These values are injected by `loadEnv` in `vite.config.mts` and become available in renderer code via `import.meta.env.VITE_API_URL` and in the main process via `process.env.VITE_API_URL`.

## Summary

- **Vite handles three builds**: The `vite.config.mts` file configures separate Rollup builds for the Vue renderer (`src/renderer`), main process ([`src/main/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/index.ts)), and preload script ([`src/preload/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/preload/index.ts)).
- **electron-builder consumes the dist output**: The [`buildAssets/builder/config.js`](https://github.com/ai-ql/tuui/blob/main/buildAssets/builder/config.js) defines platform targets (DMG, NSIS, DEB, etc.), icons, and packaging rules, reading the compiled `dist/` directory created by Vite.
- **npm scripts orchestrate the pipeline**: `dev` starts hot-reload development, `build:pre` runs linting and type-checking before Vite compilation, and `build` invokes electron-builder to generate installers.
- **Cross-platform support**: Single commands (`build:mac`, `build:win`, `build:linux`, `build:all`) generate native packages for all supported operating systems using the unified configuration.

## Frequently Asked Questions

### How does TUUI handle environment variables during the build?

TUUI merges environment variables from `.env` files using Vite's `loadEnv` function inside `vite.config.mts`. This exposes variables prefixed with `VITE_` to the renderer process via `import.meta.env`, while the main process accesses them through `process.env`. Both processes share the same values because the configuration merges `loadEnv` output with `process.env` before defining the Electron builds.

### What is the difference between `build:pre` and `build` scripts?

The `build:pre` script performs quality assurance and compilation steps without creating installers. It runs ESLint/Prettier fixes, executes `vue-tsc --noEmit` for TypeScript type checking, and invokes `vite build` to output the `dist/` directory. The `build` script executes `build:pre` first, then invokes `electron-builder` with [`buildAssets/builder/config.js`](https://github.com/ai-ql/tuui/blob/main/buildAssets/builder/config.js) to generate the actual platform-specific installers and packages.

### How are the main and preload processes bundled separately from the renderer?

Inside `vite.config.mts`, the `ElectronPlugin` accepts an array of `ElectronOptions` objects that define distinct Vite builds for each process. The main process entry point ([`src/main/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/main/index.ts)) builds to `dist/main/` with `electron` and Node.js built-in modules marked as external. The preload script ([`src/preload/index.ts`](https://github.com/ai-ql/tuui/blob/main/src/preload/index.ts)) builds to `dist/preload/`. These run as separate Rollup builds alongside the standard Vite dev server for the renderer (`src/renderer/`).

### Can I build for macOS on a Windows machine or vice versa?

electron-builder supports cross-platform compilation with limitations. You can build for Windows and Linux on any platform, but macOS targets (DMG, PKG) require a macOS host or specific cross-compilation tools. The `build:all` script attempts to build for all platforms (`-wml` flag), but in practice, macOS builds typically require `build:mac` to run on macOS hardware or CI runners with the appropriate Xcode toolchain.