Building for Production
Relevant source files
The following files were used as context for generating this wiki page:
This document outlines the process for building the Adfluens application for a production environment. The project is a Turborepo monorepo, which orchestrates the build process across the frontend (web) and backend (api) applications. The goal is to produce an optimized, single deployable unit where the backend server also serves the static frontend assets.
The primary command to initiate a production build for all packages and applications is pnpm build. This command leverages Turborepo's task runner to efficiently build the entire project, respecting dependencies and caching artifacts.
Sources: README.md:58-62, package.json:7
Build Orchestration with Turborepo
The core of the build process is managed by Turborepo. The configuration in turbo.json defines how the build task is executed across the monorepo.
Sources: turbo.json
Build Task Configuration
The build task is defined in the tasks object within turbo.json.
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"env": ["NODE_ENV"]
},
// ... other tasks
}
}
Sources: turbo.json:1-10
This configuration has the following key properties:
| Property | Value | Description |
|---|---|---|
dependsOn | ["^build"] | This task depends on the build task of all its package dependencies. Turborepo will build dependencies first. |
outputs | ["dist/**", ".next/**", ...] | Specifies the directories where build artifacts are stored. This allows Turborepo to cache the output and skip future builds if inputs haven't changed. |
env | ["NODE_ENV"] | The NODE_ENV environment variable is considered part of the task's cache key. A change (e.g., from development to production) will trigger a new build. |
Sources: turbo.json:5-8
Build Execution Flow
The following diagram illustrates the high-level flow when pnpm build is executed.
This diagram shows how the root pnpm build command triggers Turborepo, which then builds all dependent packages before building the main applications.
Sources: package.json:7, turbo.json:4-8, README.md:10-29
Frontend Build: @repo/web
The frontend application is a React application built with Vite.
Build Script
The build is triggered by the build script in its package.json.
// apps/web/package.json
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
// ...
},
Sources: apps/web/package.json:6-8
The command tsc && vite build first performs a TypeScript type check and then uses Vite to bundle the application for production.
Vite Configuration
The build output is configured in apps/web/vite.config.ts.
| Option | Value | Description |
|---|---|---|
outDir | "dist" | The output directory for the bundled static assets. |
sourcemap | true | Generates source maps for easier debugging in production. |
// apps/web/vite.config.ts
export default defineConfig({
// ...
build: {
outDir: "dist",
sourcemap: true,
},
});
Sources: apps/web/vite.config.ts:28-32
After a successful build, the apps/web/dist directory will contain the static HTML, CSS, and JavaScript files ready to be served.
Backend and Production Serving: @repo/api
The backend is an Express server. In a production environment, it is responsible for both handling API requests and serving the static frontend files generated by the @repo/web build.
Production Server Logic
The server's entry point, apps/api/src/index.ts, contains logic that activates only in a production environment.
// apps/api/src/index.ts
const isDev = env.NODE_ENV !== "production";
// ...
// Serve static files in production
if (!isDev) {
const distPath = path.join(__dirname, "..", "..", "web", "dist");
app.use(express.static(distPath));
// Handle client-side routing
app.get("*", (req, res) => {
res.sendFile(path.join(distPath, "index.html"));
});
}
Sources: apps/api/src/index.ts:13, apps/api/src/index.ts:35-44
This logic performs two key functions:
- Static File Serving: It configures an
express.staticmiddleware to serve files from theapps/web/distdirectory. - Client-Side Routing: It includes a catch-all GET route (
*) that servesindex.html. This is crucial for single-page applications (SPAs) that use client-side routing, ensuring that refreshing the page on a route like/videos/some-idstill loads the React application.
Production Architecture
The following diagram shows how the Express server handles both API requests and serves the frontend in a production environment.
This diagram illustrates the unified deployment model where a single server process manages all incoming requests.
Sources: apps/api/src/index.ts:27-33, apps/api/src/index.ts:35-44
Summary
The production build process for the Adfluens app is a streamlined workflow orchestrated by Turborepo. It compiles all necessary packages and applications, resulting in a static frontend build in apps/web/dist and a Node.js server build. In production, the Express server from apps/api is configured to serve these static assets directly, creating a simple, self-contained deployment unit. This architecture simplifies deployment and hosting by not requiring a separate static file server.