Vite and Turborepo can build multiple apps in a monorepo, but the build process isn’t as simple as just running vite build in each app’s directory.
Here’s how you can set up your monorepo to build multiple Vite applications using Turborepo for efficient orchestration.
First, let’s assume a monorepo structure like this:
my-monorepo/
├── apps/
│ ├── app1/
│ │ ├── src/
│ │ ├── index.html
│ │ ├── vite.config.js
│ │ └── package.json
│ └── app2/
│ ├── src/
│ ├── index.html
│ ├── vite.config.js
│ └── package.json
├── packages/
│ └── ui/
│ ├── src/
│ ├── package.json
├── turbo.json
└── package.json
You’ll need to install vite and turborepo as dev dependencies in your root package.json.
// package.json (root)
{
"name": "my-monorepo",
"private": true,
"version": "1.0.0",
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev"
},
"devDependencies": {
"turbo": "^1.10.3",
"vite": "^4.4.9"
}
}
Now, let’s configure turbo.json to manage the build tasks. Turborepo uses a turbo.json file at the root of your monorepo to define tasks and their dependencies.
// turbo.json
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
The build pipeline is set up to depend on any build tasks in its dependencies (^build). This means if packages/ui has a build script, apps/app1’s build will wait for packages/ui’s build to complete. The outputs field tells Turborepo where to find the build artifacts.
For each Vite app (e.g., apps/app1), you’ll need a package.json with a build script that invokes Vite.
// apps/app1/package.json
{
"name": "app1",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ui": "workspace:*" // Assuming 'ui' is in packages/ui
},
"devDependencies": {
"@vitejs/plugin-react": "^4.0.4",
"vite": "^4.4.9"
}
}
Notice the ui: "workspace:*" dependency. This allows your apps to directly reference packages within the monorepo. When you run turbo run build, Turborepo will:
- Identify buildable packages: It scans your monorepo for
package.jsonfiles containing abuildscript. - Resolve dependencies: It understands the dependency graph based on
package.jsondependenciesanddevDependencies(especiallyworkspace:*references). - Execute in parallel: It runs the
buildscripts for packages that have no outstanding dependencies first. - Cache results: For
buildtasks, Turborepo caches the output (dist/**) so subsequent builds are faster if nothing has changed. - Handle multiple apps: It will execute the
buildscript forapps/app1andapps/app2(and any other apps/packages with abuildscript) respecting their dependencies.
To build all your applications, you simply run:
turbo run build
Turborepo will intelligently determine the order of operations, build packages that are shared first, and then build the applications that depend on them.
If you have a shared UI library in packages/ui that app1 and app2 depend on, the build process will look something like this:
packages/uibuilds.apps/app1builds (which depends onpackages/ui).apps/app2builds (which also depends onpackages/ui).
Turborepo handles the dependency resolution and execution order automatically.
The dev script is often configured with cache: false and persistent: true in turbo.json because development servers are typically long-running and don’t produce cacheable artifacts. Running turbo run dev will start the development servers for all your apps.
turbo run dev
This command will start the Vite development server for app1 and app2 concurrently.
The truly surprising thing about this setup is how Turborepo’s caching mechanism works with Vite. It doesn’t just cache the final output of vite build; it caches the build artifacts at each level of the dependency graph. If you change a component in packages/ui and run turbo run build again, only packages/ui and the apps that directly depend on it will be rebuilt. Apps that don’t use packages/ui will be skipped entirely, making incremental builds incredibly fast.
The next concept you’ll want to explore is how to manage environment variables across your Vite apps within the monorepo, especially when using Turborepo to orchestrate builds.