mui-public
mui-public copied to clipboard
[code-infra] Add ESLint rules to enforce tree-shakeable production guards for dev-only functions
- [x] Understand the issue requirements
- [x] Set up development environment (Node 22, pnpm)
- [x] Install dependencies and build packages
- [x] Run existing tests to verify baseline (all pass)
- [x] Create new ESLint rule:
require-dev-wrapper - [x] Implement rule logic to check for production conditional wrapper
- [x] Create comprehensive test suite for the rule (14 tests)
- [x] Register the rule in the plugin index
- [x] Run all tests (1371 tests pass including 14 new ones)
- [x] Run TypeScript checks (pass)
- [x] Run ESLint (pass)
- [x] Run prettier (pass)
- [x] Add comprehensive documentation and examples
- [x] Address feedback: Update rule to accept both === and !== comparisons
- [x] Address feedback: Split into two separate rules
- [x] Address feedback: DRY up code with shared utilities
- [x] Address feedback: Fix else block handling
- [x] Address feedback: Simplify branch checking logic
- [x] Address feedback: Remove recursive check (binary comparisons only)
- [x] Address feedback: Refactor isNodeEnvComparison signature and logic
- [x] Address feedback: Move isNodeEnvComparison and simplify branch detection
- [x] Address feedback: Fix to only accept tree-shakeable patterns
- [x] Add test case for nested if statements in else block
- [x] Final validation complete
Implementation Summary
Created two ESLint rules to enforce production guards with shared utilities:
Shared Utilities (nodeEnvUtils.mjs)
-
isProcessEnvNodeEnv(node): Checks if a node isprocess.env.NODE_ENV -
isLiteral(node, value): Checks if a node is a Literal with specific value - Reduces code duplication between rules
1. material-ui/require-dev-wrapper
- Enforces that certain function calls (
warnOnce,warn,checkSlot) must be wrapped with tree-shakeable production checks -
Only accepts patterns that tree-shake in production:
- ✅
if (process.env.NODE_ENV !== 'production') { devCode() }- tree-shakes - ✅
if (process.env.NODE_ENV === 'development') { devCode() }- tree-shakes - ✅
if (process.env.NODE_ENV === 'production') {} else { devCode() }- tree-shakes - ❌
if (process.env.NODE_ENV === 'production') { devCode() }- does NOT tree-shake! - ❌
if (process.env.NODE_ENV !== 'test') { devCode() }- does NOT tree-shake reliably
- ✅
- Uses clean logic with
currentChildvariable for efficient branch detection - Properly handles nested if statements in else blocks
- Only validates binary comparisons (no recursive node traversal)
- Configurable via options to customize the list of function names
- 19 comprehensive tests (including nested scenarios)
2. material-ui/consistent-production-guard
- Enforces consistent patterns for ALL production guard checks using
process.env.NODE_ENV - Only allows comparison with the literal string
'production' - Rejects non-statically analyzable constructs (e.g., comparing with variables)
- Ensures
process.env.NODE_ENVis only used in binary comparisons with===or!== - Uses
checkGuardhelper to DRY up left/right comparison logic - 13 comprehensive tests
These two rules work together but can be enabled independently:
-
require-dev-wrapperensures critical dev functions are guarded -
consistent-production-guardensures all production guards follow best practices
The rules help prevent development-only utilities from adding weight to production bundles, addressing issue #207.
Original prompt
@mui/mui-public/issues/207
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.