Code Quality
Linting, formatting, testing, and monorepo task orchestration in Local.ts.
Local.ts comes with a complete code quality setup using modern, fast tooling. This guide covers linting, formatting, testing, and the monorepo task runner.
Ultracite
Ultracite is a zero-configuration linter and formatter preset designed to enforce high code quality standards.
It can unify linting and formatting using different engines, such as Biome, Prettier with ESLint, or the oxlint and oxfmt tools.
In this project, we use the oxlint + oxfmt combo for fast, modern linting and formatting.
Why Ultracite?
- Fast — Rust-based engine runs in milliseconds
- Zero-config — Sensible defaults out of the box
- Unified — Linting and formatting in one tool
- Auto-fix — Most issues are automatically fixable
Commands
# Format and fix all issues
pnpm dlx ultracite fix
# Check for issues without fixing
pnpm dlx ultracite check
# Diagnose setup issues
pnpm dlx ultracite doctorOr using Turborepo:
turbo format # Fix issues
turbo lint # Check issuesConfiguration
Ultracite works with oxlint under the hood. The configuration is in .oxlintrc.json:
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"extends": ["ultracite/oxlint/core", "ultracite/oxlint/react"]
}The presets include rules for:
- TypeScript best practices
- React hooks and accessibility
- Modern JavaScript patterns
- Security and performance
Pre-commit Hooks
Local.ts uses Lefthook to run Ultracite on staged files before each commit:
# lefthook.yml
pre-commit:
jobs:
- run: pnpm dlx ultracite fix
glob:
- "*.js"
- "*.jsx"
- "*.ts"
- "*.tsx"
- "*.json"
- "*.jsonc"
- "*.css"
stage_fixed: trueThis ensures all committed code passes linting and formatting checks.
Testing with Vitest
Local.ts uses Vitest for testing. Vitest is a fast, Vite-native test runner with a Jest-compatible API.
Running Tests
# Run tests once
turbo test
# Watch mode for development
turbo test:watch
# Generate coverage report
turbo test:coverage
# Open the UI test runner
turbo test:uiConfiguration
Testing is configured in vite.config.ts:
export default defineConfig({
// ... other config
test: {
coverage: {
provider: "v8",
reporter: ["text", "html"],
},
},
});Writing Tests
Create test files with the .test.ts or .test.tsx extension:
import { describe, it, expect } from "vitest";
describe("myFunction", () => {
it("should return the correct value", () => {
expect(myFunction(2)).toBe(4);
});
});Coverage Reports
Coverage reports are generated in the coverage/ directory:
coverage/index.html— Interactive HTML report- Terminal output shows summary
Turborepo
Turborepo orchestrates tasks across the monorepo, handling both the frontend (Vite) and backend (Tauri/Rust) with unified commands and intelligent caching.
Monorepo Structure
Local.ts is structured as a pnpm workspace with two packages:
# pnpm-workspace.yaml
packages:
- . # Frontend (React/Vite)
- ./src-tauri # Backend (Rust/Tauri)This allows Turborepo to run tasks across both packages with a single command.
Task Configuration
Tasks are defined in turbo.json:
{
"$schema": "https://turborepo.com/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [
"dist/**",
"src-tauri/target/release/**",
"src-tauri/target/debug/**"
]
},
"check": {
"dependsOn": ["^check"]
},
"dev": {
"persistent": true,
"cache": false
},
"lint": {
"dependsOn": ["^lint"]
},
"test": {
"dependsOn": ["^build"]
},
"validate": {
"dependsOn": ["build", "check", "lint", "test"]
}
}
}Key Concepts
| Concept | Description |
|---|---|
dependsOn | Run dependencies first (e.g., ^build runs build in all deps) |
outputs | Files to cache for faster subsequent runs |
persistent | Keep running (for dev servers) |
cache | Whether to cache task outputs |
Caching
Turborepo caches task outputs based on file inputs. When you run a task:
- Turborepo hashes relevant source files
- If the hash matches a previous run, it replays cached output
- If not, it runs the task and caches the result
This dramatically speeds up CI pipelines and repeated local builds.
Available Commands
| Command | Description |
|---|---|
turbo dev | Start Vite dev server |
turbo tauri -- dev | Start full Tauri app with hot reload |
turbo tauri -- build | Build production app |
turbo build | Build frontend |
turbo check | TypeScript type checking |
turbo lint | Run Ultracite linter |
turbo format | Format code with Ultracite |
turbo test | Run Vitest tests |
turbo test:coverage | Generate coverage report |
turbo validate | Run all checks (build, check, lint, test) |
The Validate Command
The validate task runs all quality checks in the correct order:
{
"validate": {
"dependsOn": ["build", "check", "lint", "test"]
}
}Use it before committing or in CI:
turbo validateThis ensures your code:
- Builds successfully
- Passes TypeScript checks
- Passes linting rules
- Passes all tests
Cargo
Local.ts includes a Rust backend in src-tauri/ with comprehensive tooling for code quality.
The Rust toolchain provides native tools for formatting, linting, type checking, testing, and coverage.
Available Cargo Commands
| Command | Description |
|---|---|
cargo fmt | Format Rust code with rustfmt |
cargo clippy | Lint Rust code with Clippy |
cargo check | Type check without building |
cargo test | Run Rust unit and integration tests |
cargo tarpaulin | Generate code coverage reports |
Turborepo Integration
The src-tauri/ directory includes a package.json that bridges Cargo commands to the Turborepo workflow. This allows unified commands across both TypeScript and Rust codebases.
Here is a simplified example:
{
"scripts": {
"format": "cargo fmt",
"lint": "cargo clippy",
"check": "cargo check",
"test": "cargo test"
}
}Now you can run Cargo commands through Turborepo alongside your TypeScript tasks:
# Format both TypeScript and Rust code
turbo format
# Lint both codebases
turbo lint
# Type check TypeScript and Rust
turbo check
# Run tests for both frontend and backend
turbo testCargo-specific Workflows
For Rust-specific tasks, navigate to src-tauri/ and use Cargo directly:
cd src-tauri
# Watch tests during development
cargo watch -x test
# Run tests with output
cargo test -- --nocapture
# Generate coverage report
cargo tarpaulin --out Html
# Fix clippy warnings automatically
cargo clippy --fixTarpaulin Coverage
Cargo Tarpaulin generates code coverage for Rust tests:
# Install tarpaulin
cargo install cargo-tarpaulin
# Generate HTML coverage report
cargo tarpaulin --out Html
# View in browser
open tarpaulin-report.htmlCoverage reports help identify untested code paths in your Rust backend.
CI Integration
Local.ts includes GitHub Actions workflows that run on every pull request to ensure code quality across the monorepo.
Existing Workflows
| Workflow | File | Description |
|---|---|---|
| Check | check.yml | Type checks TypeScript and Rust code |
| Lint | lint.yml | Runs oxlint linter on the monorepo |
| Test | test.yml | Executes all test suites |
| Build | build.yml | Builds the entire monorepo |
Workflow Triggers
All workflows:
- Run on pull requests
- Execute in parallel for faster feedback
- Use pnpm for dependency management
Leveraging Turborepo in CI
Turborepo caches build artifacts between runs, significantly reducing CI times after the first build:
# Your CI pipeline benefits from Turborepo's cache
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Validate
run: pnpm turbo run validateRemote Caching
For team environments, enable Turborepo Remote Caching to share cache across machines:
turbo login
turbo linkThis allows team members and CI runners to benefit from each other's cached builds, dramatically speeding up workflows.
Last updated on