Skip to content

Commit df4cc8d

Browse files
docs(linter): update missing linter rule documentation (oxc-project#11190)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent b70c51e commit df4cc8d

File tree

6 files changed

+244
-7
lines changed

6 files changed

+244
-7
lines changed

crates/oxc_linter/src/rules/nextjs/inline_script_id.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,71 @@ pub struct InlineScriptId;
2323
declare_oxc_lint!(
2424
/// ### What it does
2525
///
26+
/// Enforces that all `next/script` components with inline content or `dangerouslySetInnerHTML` must have an `id` prop.
2627
///
2728
/// ### Why is this bad?
2829
///
30+
/// Next.js requires a unique `id` prop for inline scripts to properly deduplicate them during page renders.
31+
/// Without an `id`, the same inline script might be executed multiple times, leading to unexpected behavior
32+
/// or performance issues. This is particularly important for scripts that modify global state or perform
33+
/// one-time initializations.
2934
///
3035
/// ### Examples
3136
///
3237
/// Examples of **incorrect** code for this rule:
3338
/// ```javascript
39+
/// import Script from 'next/script';
40+
///
41+
/// export default function Page() {
42+
/// return (
43+
/// <Script>
44+
/// {`console.log('Hello world');`}
45+
/// </Script>
46+
/// );
47+
/// }
48+
///
49+
/// // Also incorrect with dangerouslySetInnerHTML
50+
/// export default function Page() {
51+
/// return (
52+
/// <Script
53+
/// dangerouslySetInnerHTML={{
54+
/// __html: `console.log('Hello world');`
55+
/// }}
56+
/// />
57+
/// );
58+
/// }
3459
/// ```
3560
///
3661
/// Examples of **correct** code for this rule:
3762
/// ```javascript
63+
/// import Script from 'next/script';
64+
///
65+
/// export default function Page() {
66+
/// return (
67+
/// <Script id="my-script">
68+
/// {`console.log('Hello world');`}
69+
/// </Script>
70+
/// );
71+
/// }
72+
///
73+
/// // Correct with dangerouslySetInnerHTML
74+
/// export default function Page() {
75+
/// return (
76+
/// <Script
77+
/// id="my-script"
78+
/// dangerouslySetInnerHTML={{
79+
/// __html: `console.log('Hello world');`
80+
/// }}
81+
/// />
82+
/// );
83+
/// }
84+
///
85+
/// // No id required for external scripts
86+
/// export default function Page() {
87+
/// return (
88+
/// <Script src="https://example.com/script.js" />
89+
/// );
90+
/// }
3891
/// ```
3992
InlineScriptId,
4093
nextjs,

crates/oxc_linter/src/rules/nextjs/next_script_for_ga.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,53 @@ pub struct NextScriptForGa;
3030
declare_oxc_lint!(
3131
/// ### What it does
3232
///
33+
/// Enforces the use of the `next/script` component when implementing Google Analytics in Next.js applications,
34+
/// instead of using regular `<script>` tags.
3335
///
3436
/// ### Why is this bad?
3537
///
38+
/// Using regular `<script>` tags for Google Analytics can lead to several issues:
39+
/// - Scripts may load in a blocking manner, impacting page performance
40+
/// - No built-in optimization or loading strategies
41+
/// - Lack of automatic resource handling that Next.js provides
3642
///
3743
/// ### Examples
3844
///
3945
/// Examples of **incorrect** code for this rule:
40-
/// ```javascript
46+
/// ```jsx
47+
/// // Using regular script tag with GA source
48+
/// <script src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
49+
///
50+
/// // Using inline script for GA initialization
51+
/// <script dangerouslySetInnerHTML={{
52+
/// __html: `
53+
/// window.dataLayer = window.dataLayer || [];
54+
/// function gtag(){dataLayer.push(arguments);}
55+
/// gtag('js', new Date());
56+
/// gtag('config', 'GA_MEASUREMENT_ID');
57+
/// `
58+
/// }} />
4159
/// ```
4260
///
4361
/// Examples of **correct** code for this rule:
44-
/// ```javascript
62+
/// ```jsx
63+
/// import Script from 'next/script'
64+
///
65+
/// // Using next/script for GA source
66+
/// <Script
67+
/// src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
68+
/// strategy="lazyOnload"
69+
/// />
70+
///
71+
/// // Using next/script for GA initialization
72+
/// <Script id="google-analytics">
73+
/// {`
74+
/// window.dataLayer = window.dataLayer || [];
75+
/// function gtag(){dataLayer.push(arguments);}
76+
/// gtag('js', new Date());
77+
/// gtag('config', 'GA_MEASUREMENT_ID');
78+
/// `}
79+
/// </Script>
4580
/// ```
4681
NextScriptForGa,
4782
nextjs,

crates/oxc_linter/src/rules/nextjs/no_assign_module_variable.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,43 @@ pub struct NoAssignModuleVariable;
1717
declare_oxc_lint!(
1818
/// ### What it does
1919
///
20+
/// Prevents the assignment or declaration of variables named `module` in Next.js applications.
2021
///
2122
/// ### Why is this bad?
2223
///
24+
/// The variable name `module` is reserved in Next.js for internal use and module system
25+
/// functionality. Declaring your own `module` variable can conflict with Next.js's internal
26+
/// module system, lead to unexpected behavior in your application, and cause issues with code
27+
/// splitting and hot module replacement.
2328
///
2429
/// ### Examples
2530
///
2631
/// Examples of **incorrect** code for this rule:
2732
/// ```javascript
33+
/// // Declaring module variable
34+
/// let module = {};
35+
///
36+
/// // Using module in variable declaration
37+
/// const module = {
38+
/// exports: {}
39+
/// };
40+
///
41+
/// // Assigning to module
42+
/// module = { id: 'my-module' };
2843
/// ```
2944
///
3045
/// Examples of **correct** code for this rule:
3146
/// ```javascript
47+
/// // Use a different variable name
48+
/// let myModule = {};
49+
///
50+
/// // Use a more descriptive name
51+
/// const customModule = {
52+
/// exports: {}
53+
/// };
54+
///
55+
/// // Access actual module object (when available)
56+
/// console.log(module.exports);
3257
/// ```
3358
NoAssignModuleVariable,
3459
nextjs,

crates/oxc_linter/src/rules/nextjs/no_async_client_component.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,68 @@ pub struct NoAsyncClientComponent;
2020
declare_oxc_lint!(
2121
/// ### What it does
2222
///
23+
/// Prevents the use of async functions for client components in Next.js applications.
24+
/// This rule checks for any async function that:
25+
/// - Is marked with "use client" directive
26+
/// - Has a name starting with an uppercase letter (indicating it's a component)
27+
/// - Is either exported as default or assigned to a variable
2328
///
2429
/// ### Why is this bad?
2530
///
31+
/// Using async functions for client components can cause hydration mismatches between server and client,
32+
/// can break component rendering lifecycle, and can lead to unexpected behavior with React's concurrent features.
2633
///
2734
/// ### Examples
2835
///
2936
/// Examples of **incorrect** code for this rule:
3037
/// ```javascript
38+
/// "use client"
39+
///
40+
/// // Async component with default export
41+
/// export default async function MyComponent() {
42+
/// return <></>
43+
/// }
44+
///
45+
/// // Async component with named export
46+
/// async function MyComponent() {
47+
/// return <></>
48+
/// }
49+
/// export default MyComponent
50+
///
51+
/// // Async arrow function component
52+
/// const MyComponent = async () => {
53+
/// return <></>
54+
/// }
55+
/// export default MyComponent
3156
/// ```
3257
///
3358
/// Examples of **correct** code for this rule:
3459
/// ```javascript
60+
/// "use client"
61+
///
62+
/// // Regular synchronous component
63+
/// export default function MyComponent() {
64+
/// return <></>
65+
/// }
66+
///
67+
/// // Handling async operations in effects
68+
/// export default function MyComponent() {
69+
/// useEffect(() => {
70+
/// async function fetchData() {
71+
/// // async operations here
72+
/// }
73+
/// fetchData();
74+
/// }, []);
75+
/// return <></>
76+
/// }
77+
///
78+
/// // Async operations in event handlers
79+
/// export default function MyComponent() {
80+
/// const handleClick = async () => {
81+
/// // async operations here
82+
/// }
83+
/// return <button onClick={handleClick}>Click me</button>
84+
/// }
3585
/// ```
3686
NoAsyncClientComponent,
3787
nextjs,

crates/oxc_linter/src/rules/nextjs/no_before_interactive_script_outside_document.rs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,63 @@ pub struct NoBeforeInteractiveScriptOutsideDocument;
2525
declare_oxc_lint!(
2626
/// ### What it does
2727
///
28-
/// Prevent usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`.
28+
/// Prevents the usage of `next/script`'s `beforeInteractive` strategy outside of `pages/_document.js`.
29+
/// This rule ensures that scripts with the `beforeInteractive` loading strategy are only used in the
30+
/// document component where they are most effective.
2931
///
3032
/// ### Why is this bad?
3133
///
34+
/// The `beforeInteractive` strategy is specifically designed to load scripts before any page hydration
35+
/// occurs, which is only guaranteed to work correctly when placed in `pages/_document.js`. Using it elsewhere:
36+
/// - May not achieve the intended early loading behavior
37+
/// - Can lead to inconsistent script loading timing
38+
/// - Might cause hydration mismatches or other runtime issues
39+
/// - Could impact the application's performance optimization
3240
///
3341
/// ### Examples
3442
///
3543
/// Examples of **incorrect** code for this rule:
36-
/// ```javascript
44+
/// ```jsx
45+
/// // pages/index.js
46+
/// import Script from 'next/script'
47+
///
48+
/// export default function HomePage() {
49+
/// return (
50+
/// <div>
51+
/// <Script
52+
/// src="https://example.com/script.js"
53+
/// strategy="beforeInteractive" // ❌ Wrong placement
54+
/// />
55+
/// </div>
56+
/// )
57+
/// }
3758
/// ```
3859
///
3960
/// Examples of **correct** code for this rule:
40-
/// ```javascript
61+
/// ```jsx
62+
/// // pages/_document.js
63+
/// import Document, { Html, Head, Main, NextScript } from 'next/document'
64+
/// import Script from 'next/script'
65+
///
66+
/// class MyDocument extends Document {
67+
/// render() {
68+
/// return (
69+
/// <Html>
70+
/// <Head />
71+
/// <body>
72+
/// <Script
73+
/// src="https://example.com/script.js"
74+
/// strategy="beforeInteractive" // ✅ Correct placement
75+
/// />
76+
/// <Main />
77+
/// <NextScript />
78+
/// </body>
79+
/// </Html>
80+
/// )
81+
/// }
82+
/// }
83+
///
84+
/// export default MyDocument
4185
/// ```
4286
NoBeforeInteractiveScriptOutsideDocument,
4387
nextjs,

crates/oxc_linter/src/rules/nextjs/no_css_tags.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,48 @@ pub struct NoCssTags;
2020
declare_oxc_lint!(
2121
/// ### What it does
2222
///
23+
/// Prevents manual inclusion of stylesheets using `<link>` tags in Next.js applications.
24+
/// This rule checks for `<link>` tags with `rel="stylesheet"` that reference local CSS files.
2325
///
2426
/// ### Why is this bad?
2527
///
28+
/// Next.js handles CSS imports automatically through its built-in CSS support.
29+
/// Manual stylesheet inclusion bypasses Next.js's built-in CSS optimization,
30+
/// prevents proper code splitting and optimization of styles, and may cause
31+
/// Flash of Unstyled Content (FOUC). This also breaks automatic CSS hot reloading
32+
/// during development.
2633
///
2734
/// ### Examples
2835
///
2936
/// Examples of **incorrect** code for this rule:
30-
/// ```javascript
37+
/// ```jsx
38+
/// // Manually including local CSS file
39+
/// <link href="/_next/static/css/styles.css" rel="stylesheet" />
40+
///
41+
/// // In pages/_document.js
42+
/// <Head>
43+
/// <link href="css/my-styles.css" rel="stylesheet" />
44+
/// </Head>
3145
/// ```
3246
///
3347
/// Examples of **correct** code for this rule:
34-
/// ```javascript
48+
/// ```jsx
49+
/// // Importing CSS file directly
50+
/// import '../styles/global.css'
51+
///
52+
/// // Using CSS Modules
53+
/// import styles from './Button.module.css'
54+
///
55+
/// // Using external stylesheets (allowed)
56+
/// <link
57+
/// href="https://fonts.googleapis.com/css?family=Open+Sans"
58+
/// rel="stylesheet"
59+
/// />
60+
///
61+
/// // Using styled-jsx
62+
/// <style jsx>{`
63+
/// .button { color: blue; }
64+
/// `}</style>
3565
/// ```
3666
NoCssTags,
3767
nextjs,

0 commit comments

Comments
 (0)