React Doctor Framework-Specific Rules for Next.js, React Native, and Vite
React Doctor provides 15+ specialized lint rules for Next.js, 23+ rules for React Native, and currently relies on generic React rules for Vite projects.
React Doctor is an ESLint-style static analysis tool that automatically detects your project framework and applies targeted rules for safer, more performant code. The linter identifies frameworks in packages/react-doctor/src/utils/discover-project.ts and activates rules based on the requires field defined in packages/react-doctor/src/oxlint-config.ts.
How Framework Detection Works
The framework detection logic maps project signatures to specific rule sets. In packages/react-doctor/src/utils/discover-project.ts, the FRAMEWORK_MAP object recognizes Next.js, React Native, and Vite among others.
export const FRAMEWORK_MAP = {
nextjs: "Next.js",
"react-native": "React Native",
vite: "Vite",
// …other frameworks
};
Only rules whose requires array includes the detected framework are enabled. For example, rules in packages/react-doctor/src/plugin/rules/nextjs.ts specify requires: ["nextjs"], while React Native rules in packages/react-doctor/src/plugin/rules/react-native.ts use requires: ["react-native"].
Next.js Framework-Specific Rules
All Next.js rules reside in packages/react-doctor/src/plugin/rules/nextjs.ts and enforce App Router compatibility, image optimization, and proper data fetching patterns.
Image and Asset Optimization
nextjsNoImgElement disallows raw <img> tags in favor of the optimized next/image component.
// ❌ Triggers error
<img src="/logo.png" alt="logo" />
// ✅ Recommended fix
import Image from 'next/image';
<Image src="/logo.png" alt="logo" width={200} height={100} />
nextjsImageMissingSizes requires a sizes attribute when using fill mode to prevent layout shifts.
// ❌ Missing sizes
<Image src="/hero.jpg" fill />
// ✅ Correct usage
<Image src="/hero.jpg" fill sizes="(max-width: 600px) 100vw, 600px" />
nextjsNoNativeScript and nextjsInlineScriptMissingId enforce the use of next/script for external scripts and require IDs for inline scripts to ensure proper loading strategies.
// ❌ Raw script tags
<script src="/analytics.js" />
// ✅ Use next/script
import Script from 'next/script';
<Script src="/analytics.js" strategy="afterInteractive" />
App Router and Component Patterns
nextjsAsyncClientComponent flags async function components marked with "use client", as client components cannot be async functions.
'use client';
// ❌ Invalid: Client components cannot be async
export async function MyComp() { return <div />; }
nextjsNoUseSearchParamsWithoutSuspense ensures components using useSearchParams() are wrapped in <Suspense> boundaries to prevent server rendering issues.
// ❌ Missing Suspense boundary
const params = useSearchParams();
// ✅ Wrap in Suspense
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
Data Fetching and Navigation
nextjsNoClientFetchForServerData prohibits fetch calls inside useEffect on pages or layouts, encouraging server components or getServerSideProps instead.
nextjsNoClientSideRedirect and nextjsNoRedirectInTryCatch enforce server-side redirects using redirect() from next/navigation rather than client-side router pushes inside effects or try-catch blocks.
Metadata and SEO
nextjsMissingMetadata ensures pages export metadata or generateMetadata for SEO optimization in the App Router.
// ❌ Missing metadata export
export default function Page() { return <div />; }
// ✅ Add metadata
export const metadata = { title: "My Page" };
nextjsNoHeadImport disallows next/head usage in the App Router, directing developers to the Metadata API instead.
React Native Framework-Specific Rules
React Native rules in packages/react-doctor/src/plugin/rules/react-native.ts address native-specific pitfalls including raw text rendering, deprecated modules, and list performance.
Core Component Safety
rnNoRawText prevents crashes by disallowing raw text nodes outside <Text> components, which is a common error that causes runtime failures on native platforms.
// ❌ Crashes on native
<View>Hello World</View>
// ✅ Wrap in Text
<Text>Hello World</Text>
rnNoDeprecatedModules flags imports of removed React Native APIs and suggests replacements from the DEPRECATED_RN_MODULE_REPLACEMENTS mapping.
List Performance Optimization
rnNoInlineFlatlistRenderitem detects inline function definitions in renderItem props that break memoization and cause unnecessary re-renders.
// ❌ Inline function breaks memo
<FlatList data={items} renderItem={({item}) => <Item {...item} />} />
// ✅ Extract to stable reference
const renderItem = useCallback(({item}) => <Item {...item} />, []);
<FlatList data={items} renderItem={renderItem} />
rnNoScrollviewMappedList flags ScrollView with mapped children, suggesting virtualization via FlatList or FlashList for large datasets.
rnNoInlineObjectInListItem catches object literals in list item props that defeat React.memo optimizations.
Animation and Styling
rnPreferReanimated suggests react-native-reanimated over the legacy Animated API for smoother, thread-safe animations.
rnAnimateLayoutProperty warns against animating layout properties like height in useAnimatedStyle, which runs on the UI thread and can drop frames.
rnStylePreferBoxShadow and rnNoLegacyShadowStyles enforce modern boxShadow syntax over platform-specific shadow properties.
Navigation and Gestures
rnNoNonNativeNavigator prefers @react-navigation/native-stack over JavaScript-based stacks for better performance.
rnPressableSharedValueMutation flags direct mutations of Reanimated shared values inside Pressable handlers, recommending GestureDetector instead.
Vite Framework Support
Currently, React Doctor does not ship framework-specific rules for Vite. While the framework detector recognizes Vite projects (framework: "vite"), no rules in packages/react-doctor/src/oxlint-config.ts specify requires: ["vite"]. Vite projects receive the generic React rule set covering accessibility, performance, and design patterns applicable to any React codebase.
To add Vite-specific rules, developers can extend the configuration by creating a rule file and registering it with requires: ["vite"] in packages/react-doctor/src/oxlint-config.ts.
Enabling Framework-Specific Rules
Activate rules by specifying the framework when running React Doctor:
import { reactDoctor } from "react-doctor";
// Next.js project
reactDoctor.run({
cwd: "/path/to/next-app",
framework: "nextjs",
});
// React Native project
reactDoctor.run({
cwd: "/path/to/rn-app",
framework: "react-native",
});
Alternatively, import pre-configured rule sets directly:
import { configs } from "react-doctor";
reactDoctor.lint({ config: configs["next"] }); // Next.js rules
reactDoctor.lint({ config: configs["react-native"] }); // React Native rules
reactDoctor.lint({ config: configs["recommended"] }); // Generic rules only
Summary
-
Next.js receives 15+ specialized rules in
packages/react-doctor/src/plugin/rules/nextjs.tscovering image optimization (nextjsNoImgElement), App Router patterns (nextjsAsyncClientComponent), metadata requirements (nextjsMissingMetadata), and script loading (nextjsNoNativeScript). -
React Native benefits from 23+ rules in
packages/react-doctor/src/plugin/rules/react-native.tsaddressing native crashes (rnNoRawText), list performance (rnNoInlineFlatlistRenderitem), animation threading (rnPreferReanimated), and deprecated APIs (rnNoDeprecatedModules). -
Vite projects currently use only generic React rules; no Vite-specific lint rules exist in the current version of
millionco/react-doctor. -
Framework detection occurs automatically in
packages/react-doctor/src/utils/discover-project.ts, with rule activation controlled by therequiresfield inpackages/react-doctor/src/oxlint-config.ts.
Frequently Asked Questions
How does React Doctor detect which framework I'm using?
React Doctor scans your project dependencies and structure in packages/react-doctor/src/utils/discover-project.ts, mapping detected signatures to framework keys like "nextjs", "react-native", or "vite" via the FRAMEWORK_MAP constant. The detected framework key is then matched against the requires array in packages/react-doctor/src/oxlint-config.ts to determine which rules to enable.
Can I use Next.js rules in a React Native project?
No, framework-specific rules are isolated by their requires field. Rules defined in packages/react-doctor/src/plugin/rules/nextjs.ts specify requires: ["nextjs"], meaning they only activate when the detector identifies a Next.js project. Similarly, React Native rules require "react-native" in their requires array.
Why are there no Vite-specific rules available?
As implemented in millionco/react-doctor, the Vite framework detection exists in packages/react-doctor/src/utils/discover-project.ts, but no rules in packages/react-doctor/src/oxlint-config.ts currently specify requires: ["vite"]. The maintainers have focused on Next.js and React Native-specific optimizations, leaving Vite projects with the generic React rule set that applies to all React codebases.
How do I enable framework-specific rules in my CI pipeline?
Import the pre-built config for your target framework and pass it to the lint function:
import { reactDoctor, configs } from "react-doctor";
await reactDoctor.lint({
config: configs["next"], // or configs["react-native"]
cwd: process.cwd()
});
This ensures only the relevant framework-specific rules from packages/react-doctor/src/plugin/rules/nextjs.ts or packages/react-doctor/src/plugin/rules/react-native.ts are executed against your codebase.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →