A monorepo for all our frontend apps, designed to simplify sharing of code like components, styles, utils, and configs between different applications.
- Turborepo: For monorepo management and build tooling
- PNPM: Our package manager
- TypeScript: Our main language with shared, extendable config
- NextJS: The framework for all our frontend apps
- Tailwind CSS: For styling
- shadcn/ui: Our UI component base library to extend from
- Trunk CLI: Metalinter and formatter (ESLint, Prettier, Markdown, YAML, Shell, Commitlint)
- Changesets: For managing versions and generating changelogs
- Vercel: For deployments and turborepo build remote caching
- GitHub Actions: For CI/CD (with Turborepo caching for builds via Vercel)
frontend-monorepo/
├── apps/ # Frontend applications
│ ├── app.mento.org/ # Mento Exchange UI
│ ├── governance.mento.org/ # Governance UI
│ ├── minipay.mento.org/ # MiniPay DApp
│ ├── reserve.mento.org/ # Reserve UI
│ └── ui.mento.org/ # Component Library Showcase
│
├── packages/ # Shared packages
│ ├── eslint-config/ # Shared ESLint configuration
│ ├── typescript-config/ # Shared TypeScript configuration
│ ├── ui/ # Shared UI library with tailwind styles and shadcn/ui components
│ └── web3/ # Shared library with web3-specific components and hooks
│
├── .changeset/ # Changesets for versioning
├── .github/ # GitHub workflows
│ └── workflows/ # CI/CD workflows
├── .trunk/ # Trunk CLI configuration and cache
├── turbo.json # Turborepo configuration
└── pnpm-workspace.yaml # PNPM workspace configuration
- Node.js (v22 or later)
- PNPM (v10 or later)
- Trunk CLI (automatically installed during development)
-
Clone the repository:
git clone https://github.com/mento-protocol/frontend-monorepo && cd frontend-monorepo
-
Install dependencies:
pnpm install
-
Build all packages:
turbo build
-
Start the development server for all applications:
turbo dev
We use Trunk CLI as our universal linter and formatter. It combines ESLint, Prettier, Markdown linting, YAML linting, and more into a single, fast tool.
# Lint all files (comprehensive check)
pnpm lint
# Lint with auto-fix
pnpm lint:fix
# Format all files
pnpm format
# Check formatting without making changes
pnpm format:check
To lint a specific application:
cd apps/<app-name>
pnpm lint # Lints only this app
Or from the root directory:
trunk check apps/<app-name> # Direct Trunk usage
- JavaScript/TypeScript: ESLint with your existing rules
- Code Formatting: Prettier (including Tailwind CSS class sorting)
- Markdown: Documentation formatting and best practices
- YAML: Configuration file formatting
- Shell Scripts: shellcheck and shfmt
- Git: Pre-commit and pre-push hooks
The workspace is configured to use Trunk for:
- Auto-formatting on save for JS/TS files
- Lint-on-type feedback
- Code actions for quick fixes
To run a specific application:
cd apps/<app-name>
pnpm dev
Or from the root directory:
pnpm dev --filter <app-name>
# i.e. pnpm dev --filter ui.mento.org
To build a specific application:
pnpm build --filter <app-name>
The UI package is located in packages/ui/
and contains reusable components built with shadcn/ui.
shadcn/ui is our component base layer we extend from.
- Install the shadcn/ui component you need:
pnpm dlx shadcn@latest add button
- Customize it to your needs by simply editing
./packages/ui/src/components/ui/button.tsx
- Export the new component from the main barrel file
./packages/ui/src/index.ts
- Build the UI package:
pnpm build --filter @repo/ui
- Create a new component in
packages/ui/src/components
- Export it from
packages/ui/src/index.ts
- Build the UI package:
pnpm build --filter @repo/ui
Import components into an application:
// layout.tsx
import "@repo/ui/globals.css"; // Import once at the top of the app
import { Button } from "@repo/ui";
We use Conventional Commits for standardized commit messages. This helps with automated versioning and generating changelogs.
Each commit message should follow this format:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
Types include:
feat
: A new featurefix
: A bug fixdocs
: Documentation changesstyle
: Code style changes (formatting, etc.)refactor
: Code changes that neither fix bugs nor add featurestest
: Adding or fixing testschore
: Changes to the build process or auxiliary toolsperf
: Performance improvements
Example:
feat(ui): add new button component
Git Hooks: Trunk automatically manages git hooks that will:
- Pre-commit: Format and lint staged files
- Pre-push: Run comprehensive checks before pushing
- Commit-msg: Validate commit message format
This repository uses Changesets to manage versions and changelogs.
When you make changes that should be published:
pnpm changeset
Follow the prompts to specify the type of change (patch, minor, major) and describe the changes.
To update versions based on changesets:
pnpm version
To publish packages to the registry:
pnpm release
The repository is set up with GitHub Actions for CI/CD:
- CI: On every PR, it runs linting (via Trunk), type checking, and builds all packages
- CD: On merges to main, it deploys applications to Vercel
The CI pipeline uses the Trunk GitHub Action to:
- Install Trunk CLI in the CI environment
- Run the same linting and formatting checks as local development
- Ensure consistent code quality across all environments
This repo utilizes Turborepo's Remote Caching, to speed up local development and CI/CD runs. It works by storing the outputs (build artifacts, logs) of tasks (like build
, test
, lint
) in a shared remote cache on Vercel. Before running a task, Turborepo calculates a hash based on the input files, environment variables, and dependencies. If that hash exists in the remote cache, Turborepo downloads the stored output and logs instead of executing the task locally, saving a lot of time.
To connect your local machine to the remote cache:
-
Login to Vercel via Turbo CLI:
pnpm dlx turbo login
Follow the prompts to authenticate with your Vercel account.
-
Link the Repository:
pnpm dlx turbo link
This connects the local repository instance to your Vercel account/team's remote cache storage.
Once linked, turbo
commands (like pnpm build
, pnpm test
) will automatically attempt to use the remote cache. You generally don't need to set TURBO_TOKEN
or TURBO_TEAM
locally after linking, as turbo
stores the necessary credentials automatically.
The .github/workflows/ci.yml
workflow is configured to automatically leverage remote caching:
- It uses the
TURBO_TOKEN
(a Vercel Access Token) andTURBO_TEAM
(your Vercel team slug/ID) environment variables. - These variables must be configured in the GitHub repository settings under Settings > Secrets and variables > Actions:
TURBO_TOKEN
: As a Repository Secret.TURBO_TEAM
: As a Repository Variable.
- With these variables set, the CI runner can authenticate with Vercel to read from and write to the remote cache.
This repository has Signed Remote Caching enabled ("signature": true
in turbo.json
) for enhanced security. This prevents cache poisoning by ensuring only trusted sources can write to the cache.
- How it works: Artifacts uploaded to the cache are signed using a secret key. Artifacts downloaded are verified against this signature.
- CI Requirement: The signing key must be provided to the CI environment via the
TURBO_REMOTE_CACHE_SIGNATURE_KEY
environment variable. This should be configured as a Repository Secret in GitHub Actions settings. - Local Requirement: If you need to write to the cache locally (i.e., upload artifacts that weren't already there) with signing enabled, you would also need to set the
TURBO_REMOTE_CACHE_SIGNATURE_KEY
environment variable in your local shell. Reading from the cache generally doesn't require the key.
- Add syncpack for consistent dependency versions across all monorepo packages
- Finetune builds. There's probably ways to make the builds of both packages and apps smaller and/or more performant.
- Make VS Code's "Go To Definition" on a component jump to the actual TypeScript source file instead of the compiled JS file in ./dist
- Enable additional Trunk linters for production CI (security scanning, image optimization)