Reviewed-on: eigen/fe-monorepo-template#12
Frontend Monorepo Template
A scalable, enterprise-ready Web & Desktop monorepo built with Turborepo, pnpm, Vite, and Electron. This repository is designed for long-term maintainability, featuring:
- Shared logic and UI libraries
- Centralized tooling configuration
- Turbo-powered task orchestration and caching
- Native desktop distribution with auto-updates
- Dedicated documentation & component playground using Storybook
π Repository Structure
The monorepo is organized into Apps (deployable applications) and Packages (shared libraries).
.
βββ apps/
β βββ web/ # Main React Application (Vite + TypeScript)
β βββ landing/ # Public Promotional SPA (Vite + TypeScript)
β βββ desktop/ # Electron Desktop Wrapper (electron-vite)
β βββ docs-dev/ # Component Documentation & Playground (Storybook)
β
βββ packages/
β βββ core-api/ # Shared HTTP Client, Observability & Data Services Engine
β βββ core-storage/ # Enterprise Storage Engine (IndexedDB/localStorage + Encryption)
β βββ core-i18n/ # Enterprise Internationalization Architecture
β βββ ui/ # Shared UI Component Library
β βββ utils/ # Shared Utilities (Date, Encryption, Core Logic, etc)
β βββ configs/ # Shared Tooling Configurations
β βββ eslint/ # Shared ESLint rules
β βββ typescript/ # Shared TypeScript (tsconfig) bases
β
βββ package.json # Root scripts and dependencies
βββ pnpm-workspace.yaml # pnpm workspace definition
βββ turbo.json # Turborepo pipeline configuration
π Getting Started
Prerequisites
Ensure your local environment matches the following versions to avoid compatibility issues:
- Node.js:
v20+(tested withv24.11.1) β required for the--import tsxflag used by the desktop prebuild script - pnpm:
v8.15.6(Enforced via thepackageManagerfield inpackage.json)
Installation
Install all dependencies from the root directory:
pnpm install
π Usage & Scripts
This repository uses Turborepo to orchestrate tasks efficiently. All commands are executed from the root.
Development
| Command | Description |
|---|---|
pnpm dev |
Start all applications (web and docs-dev) in parallel |
pnpm dev:web |
Start only the Main Web App (strictly at http://localhost:5173) |
pnpm dev:landing |
Start the Public Landing App (strictly at http://localhost:3000) |
pnpm dev:docs-dev |
Start Storybook for UI development (strictly at http://localhost:6006) |
pnpm dev:desktop |
Start the Web App + Electron in parallel for desktop development |
Note
Port Topology:
electron-vitedynamically allocates a background port (usually5174) for its internal renderer shell duringpnpm dev:desktop. We strictly isolateweb(5173) andlanding(3000) onto separate port ranges to prevent race conditions during parallel execution.
Building & Quality
| Command | Description |
|---|---|
pnpm build |
Build all apps and packages using Turbo cache |
pnpm build:web |
Build only the web application |
pnpm build:landing |
Build only the landing page |
pnpm build:docs-dev |
Build only the docs-dev application |
pnpm build:desktop |
Build the web app, then compile the Electron app |
pnpm test |
Run unit tests (Vitest) across all packages |
pnpm lint |
Run ESLint across the workspace |
pnpm format |
Format code using Prettier |
π Desktop Packaging & Distribution
To package the application into a production-ready installer, use the following commands from the root directory:
| Command | Platform | Output Artifact |
|---|---|---|
pnpm package:desktop |
Current OS | Detects host OS and builds accordingly |
pnpm package:mac |
macOS | .dmg and .zip (supports x64 & arm64) |
pnpm package:win |
Windows | .exe (NSIS Installer) |
pnpm package:linux |
Linux | .AppImage |
Important
Build Sequence: All
package:*commands execute the following pipeline automatically:
turbo run build --filter=webβ Compiles the React SPA intoapps/web/dist/.prebuildhook β Runsnode --import tsx scripts/copy-web-dist.ts, which copiesapps/web/dist/βapps/desktop/web-dist/.electron-builderβ Bundlesweb-dist/into the packaged app via thefilesandextraResourcesblocks inelectron-builder.yml.You do not need to run these steps manually β they are chained via npm scripts.
Warning
macOS Code Signing: To build a distributable macOS app with Auto-Update support, you must have an Apple Developer Certificate and provide
CSC_LINKandCSC_KEY_PASSWORDin your environment. Without code signing, macOS Gatekeeper will block the app and auto-updates will fail. See AUTO_UPDATER.md for details.
Note
Cross-Compilation: It is highly recommended to build for Windows on a Windows machine and for macOS on a Mac. Cross-compilation (e.g., building
.dmgon Linux) may fail due to platform-specific toolchain dependencies. Use a CI matrix strategy (e.g., GitHub Actions withruns-on: [macos-latest, windows-latest, ubuntu-latest]) for multi-platform releases.
π¦ Packages Overview
1. apps/web
The main consumer-facing application.
- Imports business logic from
@repo/utils - Uses shared UI components from
@repo/ui
Tech Stack:
- React
- Vite
- TypeScript
- Tailwind CSS
2. apps/desktop
The Electron desktop wrapper that embeds apps/web for native desktop experiences.
- In development: loads the Vite dev server with full hot reload
- In production: serves the static web build via a secure custom
app://protocol - Configurable target app via
.env(can wrapapps/web,apps/docs-dev, or any future app)
Tech Stack:
- Electron 33.x
- electron-vite
- electron-builder
- electron-updater
Key Capabilities:
| Feature | Description |
|---|---|
| π¨οΈ Native Printing | Silent and direct printing via secure IPC bridge |
| π Auto-Updates | Background downloads via GitHub Releases (switchable to S3) |
| π Secure IPC Bridge | contextIsolation: true, nodeIntegration: false, sandbox: true |
| π Custom Protocol | app:// serves static files with SPA routing fallback to index.html |
| π‘οΈ CORS Bypass | Transparent Origin header rewriting for cloud API calls |
Desktop Documentation:
| Document | Contents |
|---|---|
| CONFIGURATION.md | Target app switching, app:// protocol internals, HashRouter fallback |
| AUTO_UPDATER.md | Release workflow, CI/CD variables, provider switching, code signing |
| IPC_ARCHITECTURE.md | Security model, Three-Step Bridge pattern, extending native features |
3. apps/landing
The public promotional website β a standalone SPA for the company profile and marketing pages.
- Deployed independently to the web (e.g., Vercel) β no interaction with Electron
- Consumes shared UI components from
@repo/uiand utilities from@repo/utils - Locked to port 3000 (
strictPort: true) β evacuated from the517xrange to avoidelectron-viteport collisions
Tech Stack:
- React
- Vite
- TypeScript
- Tailwind CSS v4
4. apps/docs-dev (Storybook)
An isolated environment for developing and documenting UI components.
- Ensures components in
@repo/uiare built and tested independently - Acts as a living design system and playground
5. packages/core-api
The platform-agnostic API engine for the monorepo. Provides an isolated HTTP client factory, a unified observability pipeline (Grafana Faro + OpenTelemetry), and a generic data services engine.
- Consumed by
apps/web,apps/landing, and any future workspace - Centralizes all
@grafana/faro-*and@opentelemetry/*dependencies - Provides plug-and-play telemetry via
initTelemetry()+faroAdapter
Tech Stack:
- Axios (isolated instances, zero singleton pollution)
- Grafana Faro (RUM, Logs, Error tracking)
- OpenTelemetry (custom spans, distributed tracing)
- TypeScript (strict types, module augmentation)
Key Capabilities:
| Feature | Description |
|---|---|
| π HTTP Client Factory | createHttpClient() β per-app isolated Axios instances with interceptor hooks |
| π‘ Faro/Loki Baseline | Every request automatically pushes structured logs with module.key and module.action |
| π― Custom Spans (Opt-In) | telemetryContext.customSpanName creates explicit OTel spans visible in Grafana Tempo |
| π‘οΈ Error Normalization | ApiError.fromAxiosError() β structured, serializable error codes for all failure modes |
| π¦ Data Services Engine | CommonRemoteDataServices β full CRUD + lifecycle operations with zero boilerplate |
Documentation:
| Document | Contents |
|---|---|
| README.md | Architecture, HTTP client setup, observability strategy, data services, app integration guide |
6. packages/core-storage
The Enterprise-grade storage engine for the monorepo.
Provides a unified, Promise-based interface for interacting with browser storage (localStorage and IndexedDB). Enforces strict type safety, prevents key collisions via a centralized registry, and automatically provides AES encryption at rest for sensitive payloads using @repo/utils.
Documentation: README.md
7. packages/core-i18n
The Enterprise Internationalization Architecture for the monorepo.
Provides a Hybrid Namespace Architecture combining a centralized i18n engine with decentralized, lazy-loaded feature dictionaries. Features strict TypeScript typings (including nested keys), optional backend synchronization with automatic error rollbacks, and a deep-merge mechanism for dynamic tenant-specific vocabulary overrides.
Key Capabilities:
| Feature | Description |
|---|---|
| π Hybrid Namespaces | Centralized common corpus + lazy-loaded feature dictionaries. |
| π‘οΈ Strict Typings | Native TS autocomplete for nested paths (e.g., header.title) via module augmentation. |
| π Safe Backend Sync | changeLanguage accepts a syncCallback with built-in rollback if the API fails. |
| π’ Tenant Overrides | applyTenantOverrides performs a partial deep-merge to selectively override terminology. |
Documentation: README.md
8. packages/core-events
The decoupled Nervous System for the monorepo.
Provides a highly performant, strictly typed Event Bus (Pub/Sub) powered by mitt. It allows independent modules to communicate seamlessly without tightly coupling their codebases or triggering expensive global React tree re-renders.
Key Capabilities:
| Feature | Description |
|---|---|
| π§© Zero Coupling | Publishers and subscribers interact via blind events, eliminating direct module imports and circular dependencies. |
| β‘ Extreme Performance | Enables targeted DOM updates for high-frequency data streams (e.g., WebSockets) without re-rendering parent components. |
| π§Ή Memory Safety | Native useAppEvent hook automatically unsubscribes on component unmount, preventing SPA memory leaks. |
| π‘οΈ Strict Contracts | Centralized events.registry.ts enforces payload shapes via TypeScript, ensuring cross-module data safety. |
Documentation: README.md
9. packages/utils
Shared business logic and reusable utility modules that can be consumed across multiple applications. Fully tested using Vitest.
This package is intended to hold non-UI, cross-cutting logic such as date/time handling, security helpers, and other common utilities. It is designed to be framework-agnostic, predictable, and easy to extend as the system evolves.
10. packages/ui
Shared UI component library (Buttons, Inputs, Cards, Layouts).
- Ensures consistent design across all applications
- Designed to be consumed by both web apps and Storybook
11. packages/configs
Single source of truth for tooling configuration.
- eslint-config: Shared ESLint rules (React, libraries, Storybook)
- typescript-config: Shared
tsconfig.jsonbase configurations
βοΈ Configuration & Environment
Turborepo Caching
This repository uses Turborepo caching for builds, tests, and other artifacts.
To fully clean the workspace (dependencies, build outputs, and Turbo cache):
rm -rf node_modules **/*/node_modules .turbo **/*/.turbo dist **/*/dist out **/*/out web-dist **/*/web-dist release **/*/release
π License
This project is private and proprietary.