How the Vite Build Configuration Works for Production in Thunderbolt
Thunderbolt uses a single vite.config.ts file that configures both development and production builds, where the build section activates only during vite build, generating optimized static assets in dist/ while externalizing native modules and conditionally enabling features via environment variables.
Thunderbolt is an open-source email client built by the Thunderbird team, leveraging modern web technologies for its user interface. Understanding the Vite build configuration is essential for contributors packaging the application for production or optimizing bundle sizes. The configuration is centralized in vite.config.ts and handles everything from dependency deduplication to conditional asset copying.
Core Production Settings in vite.config.ts
The production behavior is governed by the build property in the configuration object, which Vite applies only when running vite build or bun run build.
Source Map Management
Source maps are controlled by the ENABLE_SOURCEMAP environment variable. In vite.config.ts lines 22-24, the configuration checks this variable to set the sourcemap constant to either 'hidden' or false. When enabled, hidden source maps allow error tracking services like PostHog to map minified code back to source without exposing mappings publicly. This value is passed to build.sourcemap on lines 28-29.
Handling Native Dependencies
Native modules that cannot be bundled must be externalized. The configuration uses rollupOptions.external on lines 30-32 to mark bun:sqlite as external, preventing Rollup from attempting to bundle the native SQLite driver into the JavaScript bundle.
Path Aliases and Deduplication
To minimize bundle size and resolve imports consistently, the configuration defines several aliases in the resolve.alias array on lines 74-81. These map @ to src, @shared to shared, and provide an internal PowerSync alias required by the custom SharedWorker. Additionally, resolve.dedupe on lines 74-75 ensures only single instances of react and @powersync/* packages exist in the final bundle, preventing duplicate React copies that could cause hook errors.
Build Plugins and Asset Pipeline
The plugins array on lines 34-51 configures the transformation pipeline, with several plugins specifically impacting production output.
PowerSync Asset Copying
Before bundling begins, the copy-powersync-assets plugin executes powersync-web copy-assets --output public. This ensures PowerSync's WebAssembly and required static files are present in the public directory, which Vite copies verbatim to dist/ during the build.
Conditional Bundle Analysis
Bundle analysis is gated by the ANALYZE environment variable. When set to true, the configuration spreads a vite-bundle-analyzer plugin into the plugins array on lines 44-50, generating a static report of bundle composition and sizes. This is typically invoked via ANALYZE=true bun run build.
Dependency Optimization
During development, Vite pre-bundles dependencies to improve cold-start performance. However, for production, the optimizeDeps.exclude array on lines 18-20 prevents pre-bundling of heavy native modules like @journeyapps/wa-sqlite and @powersync/web, ensuring they are handled correctly by the build pipeline rather than optimized away.
Development vs. Production Mode
The configuration distinguishes between environments primarily through Vite's internal mode detection. The server block—which configures port 1420, HMR behavior, and file-system whitelisting—is only active during vite dev or when running the Tauri desktop workflow. When executing vite build, Vite ignores the server configuration entirely and outputs optimized static assets to the dist/ directory, ready for deployment via any HTTP server or integration into the Tauri binary.
Running Production Builds
Execute the following commands from the repository root to generate production bundles:
Standard production build:
bun run build
Build with bundle analysis:
ANALYZE=true bun run build
Build with source maps for error tracking:
ENABLE_SOURCEMAP=true bun run build
Verify PowerSync assets were copied:
ls public | grep powersync
Summary
- Thunderbolt uses a unified
vite.config.tsfor both development and production, with thebuildsection activating only duringvite build. - Source maps are controlled via
ENABLE_SOURCEMAP, defaulting to disabled for privacy but supporting hidden maps for CI error tracking. - Native modules like
bun:sqliteare externalized viarollupOptions.externalto prevent bundling errors. - The PowerSync asset plugin ensures WebAssembly files are copied to
public/before bundling. - Bundle analysis can be triggered with
ANALYZE=trueto audit bundle composition. - The configuration outputs static files to
dist/, suitable for web deployment or Tauri packaging.
Frequently Asked Questions
How do I enable source maps for production builds in Thunderbolt?
Set the ENABLE_SOURCEMAP environment variable to true before running the build. This configures Vite to generate hidden source maps according to the logic in vite.config.ts lines 22-29, allowing error tracking services to map stack traces without exposing source maps publicly.
Why is bun:sqlite marked as external in the Vite configuration?
bun:sqlite is a native module that provides SQLite functionality through Bun's native bindings. Marking it as external in rollupOptions.external (lines 30-32 of vite.config.ts) prevents Rollup from attempting to bundle this native code into the JavaScript bundle, which would cause build failures.
What triggers the bundle analyzer in Thunderbolt's build process?
The vite-bundle-analyzer plugin is conditionally injected when the ANALYZE environment variable equals true. This logic appears in lines 44-50 of vite.config.ts, allowing developers to generate a static bundle report by running ANALYZE=true bun run build.
How does Thunderbolt handle PowerSync assets during production builds?
Before Vite bundles the application, the copy-powersync-assets plugin executes a CLI command to copy PowerSync's WebAssembly and static files into the public directory. Since Vite copies public/ contents verbatim to dist/, these assets are available in the production bundle without being processed by the bundler.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →