microsoft / microsoft/typespec

Investigate migrating formatter from Prettier to oxfmt (oxc formatter)

Open
#11,350 1 comment 1 reaction 0 assignees View on GitHub
eng feature triaged:core
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.