microsoft / microsoft/typespec
Investigate migrating formatter from Prettier to oxfmt (oxc formatter)
- Dominant language
- Java
- Stars
- 5.9k
- Forks
- 394
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 104
Description
## Summary
Proof-of-concept investigation into replacing **Prettier** with **oxfmt** (the oxc formatter) for the monorepo. Result: **large speed win with low churn** for the JS/TS/JSON bulk. oxfmt can't format a few file types, so the proposal is a hybrid where oxfmt owns the bulk, `tsp format` owns `.tsp`, and Prettier is kept only for `.astro` + shell.
Tested with **oxfmt 0.59.0** (npm hybrid build).
## Key results
- **~30× faster** on the JS/TS/JSON bulk: `oxfmt --check` = **~2.7s on 2947 files** vs Prettier `format:check` = **~80–100s**.
- **Low churn**: only **55 / 2947 files (1.9%)** differ — genuine formatting deltas (union-type line-breaking, arrow-arg wrapping), **not** import reordering.
- **No JSON / YAML / CSS churn** — byte-identical to Prettier.
- `.prettierrc` migrated cleanly via `oxfmt --migrate=prettier` (all core options + every `.prettierignore` pattern). Only the 4 plugins are dropped (expected).
## Coverage
oxfmt natively handles: **JS/TS/TSX, JSON, YAML, Markdown, CSS, GraphQL, TOML**.
Gaps (must live elsewhere):
| File type | Count | Plan |
|---|---|---|
| `.tsp` | 356 | `tsp format` (compiler's own formatter; the prettier plugin just wraps it) |
| `.astro` | 47 | **Unsupported** in 0.59 → residual Prettier |
| `.sh` | 1 (`packages/standalone/install.sh`) | No shell support → residual Prettier |
## Benchmarks (M-series mac, 10 threads)
| Step | Files | Wall time |
|---|---|---|
| Prettier `format:check` (current) | ~all | ~80–100s |
| **oxfmt `--check .`** | 2947 | **~2.7s** |
| `tsp format --check` | 324 | ~1.8s |
| Prettier residual (`*.{astro,sh}`) | 48 | ~4.1s |
| **Proposed combined pipeline** | — | **~9s** |
## Churn detail (the 55 files)
26 `.ts`, 25 `.tsx`, 4 `.md`. Representative diffs:
- Union types that fit within `printWidth` are broken to one member per line with a leading `|` by oxfmt, where Prettier 3.9.5 keeps them on one wrapped line.
- `arr.map((x): T => ({...}))` — oxfmt wraps the callback argument differently.
One-time reformats; the resulting style is stable and self-consistent.
⚠️ **Do NOT enable `sortImports`**: it re-sorts with the perfectionist algorithm (≠ `prettier-plugin-organize-imports` order) and churn jumps to **1337 files (45%)**.
## Import organizing — behavioral gap
- Current `prettier-plugin-organize-imports` **sorts** + **removes unused** imports.
- oxfmt `sortImports` is off by default; when on it only **sorts** (different order), never removes unused.
- oxlint already has `no-unused-vars: error`, which flags unused imports (blocks CI) but does not auto-remove them on `--fix`.
- Recommendation: keep `sortImports` **off**. Either (a) drop import-organizing and rely on oxlint, or (b) keep `prettier-plugin-organize-imports` as a residual TS/JS step. (a) is cleaner; (b) preserves exact current behavior.
## Proposed end-state
- **oxfmt** owns: JS/TS/TSX/MJS, JSON, YAML, Markdown, CSS, GraphQL, TOML.
- **`tsp format`** owns: `.tsp`.
- **Prettier (residual)** owns only: `.astro` + `.sh` (slim config, astro+sh plugins only).
## Editor / CI follow-ups (not yet applied)
- **VS Code**: install the oxc extension (`oxc.oxc-vscode`, oxfmt via LSP); set per-language `editor.defaultFormatter` (oxfmt for JS/TS/JSON/CSS/MD/YAML, TypeSpec ext for `.tsp`, Prettier for `.astro`/shell). Current shared `.vscode/settings.json` hardcodes `esbenp.prettier-vscode`.
- **CI** (`.github/workflows/consistency.yml`): replace the prettier-plugin build + `pnpm run format:check` with the oxfmt/tsp/residual pipeline (oxfmt needs no build; `tsp format` still needs the compiler built).
## Risks / open items
1. One-time 55-file reformat lands a slightly different (but stable) JS/TS style vs Prettier.
2. Loss of automatic unused-import removal (mitigated by oxlint `no-unused-vars`).
3. `.astro` unsupported today — track oxc Tier-4 progress to eventually drop the Prettier residual.
4. oxfmt is Beta (Feb 2026); pin the version and re-verify churn on upgrades.
5. `tsp format` requires the compiler to be built before running (same as today's prettier-plugin build step).
---
_Findings from a hands-on PoC that wired oxfmt/`tsp format`/residual-Prettier scripts side-by-side with the existing Prettier scripts (no repo-wide reformat performed)._
Contributor guide
Research direction
Start by reviewing the existing Prettier scripts, .github/workflows/consistency.yml, and .vscode/settings.json, then run the documented oxfmt, tsp format, and residual-Prettier checks to verify their current behavior. Done means the proposed hybrid pipeline, editor formatter settings, and CI checks are implemented while preserving the stated file coverage and validating formatting churn.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, javascript, shell, typescript, vscode
- Domain
- build-system, ci-cd, developer-experience, tooling
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100