-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Summary
10up-toolkit currently relies on three separate tools for code quality: ESLint (JavaScript linting), Prettier (formatting), and Stylelint (CSS linting). This requires managing multiple configurations, dependencies, and plugin ecosystems.
Modern alternatives like Biome offer a unified, significantly faster experience. This issue explores what it would take to migrate 10up-toolkit's linting and formatting infrastructure to Biome or similar modern tooling.
Current State
What 10up-toolkit Uses Today
@10up/eslint-config → ESLint + eslint-config-airbnb + plugins
@10up/stylelint-config → Stylelint + various plugins
Prettier → Integrated via eslint-plugin-prettier
Dependencies involved:
eslint+ ~15-20 plugins (React, JSX-a11y, import, WordPress, Jest, etc.)prettier+ eslint-plugin-prettier + eslint-config-prettierstylelint+ ~5-10 plugins (SCSS, order, etc.)
Total: 100+ transitive dependencies, complex version management
Pain Points
- Slow: ESLint with TypeScript type-checking can take 10-15+ seconds on large projects
- Complex configuration: Three separate config files, often conflicting
- Dependency hell: Plugin version conflicts, peer dependency warnings
- CI overhead: Linting often the slowest step in CI pipelines
- Maintenance burden: Keeping plugins updated across all three tools
Biome: The Leading Alternative
Biome is an all-in-one toolchain written in Rust that combines linting, formatting, and more into a single binary.
Key Features (as of Biome v2.0, June 2025)
| Feature | Details |
|---|---|
| Speed | 10-25x faster than ESLint + Prettier |
| Unified | Linter + Formatter + Import sorter in one tool |
| Languages | JavaScript, TypeScript, JSX, JSON, CSS, GraphQL |
| Rules | 425+ rules from ESLint, typescript-eslint, and other sources |
| Prettier compat | 97% formatting compatibility with Prettier |
| Type-aware | v2.0 introduced type-aware linting WITHOUT requiring TypeScript compiler |
| Zero deps | Single binary, no node_modules bloat |
| Domains | Auto-configures rules based on package.json dependencies (React, Next.js, etc.) |
Biome v2.0 Highlights
Biome v2—codename: Biotype—the first JavaScript and TypeScript linter
that provides type-aware linting rules that doesn't rely on the
TypeScript compiler!
- Type inference detects ~85% of floating promise cases at a fraction of the performance cost
- Linter plugins (limited scope, but growing)
- Domains auto-enable React/Next.js rules based on dependencies
- Biome Assist for import organizing, key sorting, attribute sorting
Performance Comparison
| Tool | Time (example project) |
|---|---|
| ESLint + Prettier | 10-15 seconds |
| Biome | < 1 second |
| Oxlint | < 0.5 seconds |
Alternative: Oxlint
Oxlint is another Rust-based linter from the Oxc project.
Oxlint v1.0 (August 2025)
| Feature | Details |
|---|---|
| Speed | 50-100x faster than ESLint (even faster than Biome) |
| Rules | 520+ ESLint rules supported |
| Zero config | Works out of the box |
| Limitations | Linting only (no formatting), no type-aware rules yet |
When to Choose Which
| Use Case | Recommendation |
|---|---|
| All-in-one replacement | Biome |
| Maximum speed, keep Prettier | Oxlint + Prettier |
| Need type-aware rules | Biome v2 |
| Heavy plugin ecosystem needs | Stay with ESLint (for now) |
Migration Analysis
What Can Be Migrated
| Current Tool | Biome Replacement | Coverage |
|---|---|---|
| ESLint core rules | ✅ Biome linter | ~90% |
| eslint-plugin-react | ✅ Built-in JSX rules | ~90% |
| eslint-plugin-jsx-a11y | ✅ Built-in a11y rules | ~80% |
| eslint-plugin-import | ✅ Import organizer | ~85% |
| typescript-eslint | ✅ Type-aware rules (v2) | ~85% |
| Prettier (JS/TS/JSON) | ✅ Biome formatter | 97% |
| Prettier (CSS) | ✅ Biome formatter | 97% |
| Stylelint | ~60% |
What Cannot Be Migrated (Yet)
| Tool/Plugin | Status |
|---|---|
@wordpress/eslint-plugin |
❌ No direct equivalent - WordPress-specific rules |
eslint-plugin-jest |
|
| SCSS linting | ❌ Biome doesn't support SCSS syntax |
| HTML/Markdown | ❌ Not yet supported |
| Vue/Svelte/Astro | |
| Custom ESLint plugins | ❌ Plugin system is limited |
WordPress-Specific Considerations
The @wordpress/eslint-plugin provides several WordPress-specific rules:
// Rules we'd lose or need alternatives for:
'@wordpress/no-unsafe-wp-apis'
'@wordpress/dependency-group'
'@wordpress/no-unused-vars-before-return'
'@wordpress/i18n-*' rules
// etc.Options:
- Run Biome + ESLint (just for WordPress rules) in parallel
- Contribute WordPress rules to Biome as plugins
- Accept some rule loss initially
WordPress Globals
Biome needs manual configuration for WordPress globals:
{
"javascript": {
"globals": ["wp", "jQuery", "Backbone", "JSON", "_"]
}
}The biome migrate eslint command won't automatically pick these up from @wordpress/eslint-plugin.
Proposed Migration Path
Phase 1: Formatter Migration (Low Risk)
Replace Prettier with Biome formatter only:
// 10up-toolkit.config.js
module.exports = {
formatter: 'biome', // Instead of 'prettier'
};Benefits:
- Immediate speed improvement for formatting
- No rule changes, just formatting
- Easy rollback if issues
Changes needed:
- Add
@biomejs/biomeas dependency - Update
lint-styleandformatcommands - Provide
biome.jsonwith Prettier-compatible settings
Phase 2: JavaScript/TypeScript Linting
Replace ESLint for JS/TS with Biome linter:
module.exports = {
linter: {
js: 'biome', // Instead of 'eslint'
css: 'stylelint' // Keep Stylelint for now
}
};Migration steps:
- Run
biome migrate eslint --writeto convert config - Add WordPress globals manually
- Identify and document any lost rules
- Provide
@10up/biome-configpreset
Phase 3: CSS Linting
Evaluate Biome CSS linting vs keeping Stylelint:
| Consideration | Biome | Stylelint |
|---|---|---|
| Speed | ✅ Much faster | ❌ Slower |
| SCSS support | ❌ None | ✅ Full |
| Rule coverage | ✅ Comprehensive | |
| Property order | ✅ Via assist | ✅ Via plugin |
Recommendation: Keep Stylelint for SCSS projects, use Biome for CSS-only projects.
Phase 4: Full Migration
For projects that can fully migrate:
{
"linter": "biome",
"formatter": "biome"
}Single biome.json replaces:
.eslintrc.js.prettierrc.stylelintrc.js
Configuration Design
New 10up-toolkit Config Options
// 10up-toolkit.config.js
module.exports = {
// Linting/formatting tool selection
codeQuality: {
// 'legacy' = ESLint + Prettier + Stylelint (current default)
// 'biome' = Biome for JS/TS/CSS, Stylelint for SCSS
// 'biome-full' = Biome only (no SCSS support)
preset: 'biome',
// Or granular control:
linter: {
js: 'biome', // 'eslint' | 'biome' | 'oxlint'
css: 'stylelint', // 'stylelint' | 'biome'
},
formatter: 'biome', // 'prettier' | 'biome'
}
};Biome Preset for 10up
{
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
"extends": ["@10up/biome-config"],
"javascript": {
"globals": ["wp", "jQuery", "ajaxurl", "wpApiSettings"]
},
"linter": {
"rules": {
"recommended": true,
"domains": {
"react": "all"
}
}
},
"formatter": {
"indentStyle": "tab",
"indentWidth": 4,
"lineWidth": 100
}
}CLI Changes
Current Commands
10up-toolkit lint-js [files]
10up-toolkit lint-style [files]
10up-toolkit format [files]Proposed Commands
# Smart routing based on config
10up-toolkit lint [files] # Runs appropriate linter(s)
10up-toolkit format [files] # Runs appropriate formatter
# Or explicit tool selection
10up-toolkit lint --tool=biome [files]
10up-toolkit lint --tool=eslint [files]
# Check mode (CI-friendly)
10up-toolkit check [files] # Lint + format check, no writesPackage Changes
New Packages
@10up/biome-config # Biome configuration preset
Modified Packages
10up-toolkit # Add Biome support, keep ESLint as fallback
@10up/eslint-config # Maintain for legacy/WordPress-specific needs
@10up/stylelint-config # Maintain for SCSS projects
Deprecated (Eventually)
@10up/eslint-config # Once Biome covers all use cases
Risks and Mitigations
| Risk | Mitigation |
|---|---|
| WordPress rule coverage gaps | Run Biome + minimal ESLint config for WP rules |
| SCSS not supported | Keep Stylelint for SCSS, or use CSS-only |
| Team unfamiliarity | Documentation, gradual rollout |
| Different formatting output | Run both tools in CI initially, compare |
| Plugin ecosystem | Biome plugins are maturing; wait or contribute |
Timeline Consideration
| Milestone | Estimated Timeframe |
|---|---|
| Biome formatter only | Ready now |
| JS/TS linting (non-WordPress) | Ready now |
| WordPress-aware config | Needs config work |
| Full SCSS support | Waiting on Biome |
| Complete ESLint replacement | 2026+ |
Questions to Consider
- Should we default new projects to Biome while keeping ESLint for existing projects?
- How do we handle the WordPress-specific ESLint rules gap?
- Should we support running Biome + ESLint in parallel for WordPress rules?
- What's our SCSS story - require CSS, or maintain Stylelint?
- Should we contribute WordPress-specific rules to Biome's plugin system?