Skip to content

Conversation

LukasTy
Copy link
Member

@LukasTy LukasTy commented Jun 27, 2025

Discovered this "can-of-worms" while checking #18562.

Due to legacy ESLint config overriding rules applied on the same files, this rule was being overridden and didn't take effect. 🙈
Previously, we had a build:rsc script taking care of adding use client; at the top of the file, but #16273 removed it in favor of this ESLint rule... 🙈

cc @brijeshb42

@LukasTy LukasTy requested a review from a team June 27, 2025 16:44
@LukasTy LukasTy self-assigned this Jun 27, 2025
@LukasTy LukasTy added type: bug It doesn't behave as expected. scope: code-infra Changes related to the core-infra product. labels Jun 27, 2025
@mui-bot
Copy link

mui-bot commented Jun 27, 2025

Deploy preview: https://deploy-preview-18570--material-ui-x.netlify.app/

Bundle size report

Total Size Change: 0B(0.00%) - Total Gzip Change: 0B(0.00%)
Files: 122 total (0 added, 0 removed, 0 changed)

Show details for 100 more bundles (22 more not shown)

@mui/x-chartsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-proparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/BarChartProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/ChartContainerProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/ChartDataProviderProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/ChartsToolbarProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/ChartZoomSliderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/FunnelChartparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/Heatmapparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/LineChartProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/PieChartProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/RadarChartProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts-pro/ScatterChartProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/BarChartparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartContainerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartDataProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsAxisparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsAxisHighlightparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsClipPathparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsGridparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsLabelparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsLegendparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsLocalizationProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsOverlayparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsReferenceLineparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsSurfaceparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsTextparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsTooltipparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsXAxisparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ChartsYAxisparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/Gaugeparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/LineChartparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/PieChartparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/RadarChartparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/ScatterChartparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/SparkLineChartparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-charts/Toolbarparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-data-gridparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-data-grid-premiumparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-data-grid-premium/DataGridPremiumparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-data-grid-proparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-data-grid-pro/DataGridProparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-data-grid/DataGridparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickersparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-proparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/AdapterDateFnsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/AdapterDateFnsJalaliparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/AdapterDayjsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/AdapterLuxonparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/AdapterMomentparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/AdapterMomentHijriparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/AdapterMomentJalaaliparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DateRangeCalendarparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DateRangePickerDayparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DateRangePickerDay2parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DateTimeRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DesktopDateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DesktopDateTimeRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/DesktopTimeRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/LocalizationProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/MobileDateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/MobileDateTimeRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/MobileTimeRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/MultiInputDateRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/MultiInputDateTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/MultiInputTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/PickersRangeCalendarHeaderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/SingleInputDateRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/SingleInputDateTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/SingleInputTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/StaticDateRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers-pro/TimeRangePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterDateFnsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterDateFnsBaseparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterDateFnsJalaliparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterDayjsparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterLuxonparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterMomentparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterMomentHijriparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/AdapterMomentJalaaliparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DateCalendarparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DateFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DatePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DateTimeFieldparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DayCalendarSkeletonparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DesktopDatePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DesktopDateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DesktopTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/DigitalClockparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/LocalizationProviderparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/MobileDatePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/MobileDateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/MobileTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/MonthCalendarparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/MultiSectionDigitalClockparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/PickerDay2parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/PickersActionBarparsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/x-date-pickers/PickersCalendarHeaderparsed: 0B(0.00%) gzip: 0B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against ae8c6ff

@Janpot
Copy link
Member

Janpot commented Jun 27, 2025

Due to legacy ESLint config overriding rules applied on the same files,

what is happening exactly? Isn't eslint merging all rule objects from overrides that apply for a file?

@LukasTy
Copy link
Member Author

LukasTy commented Jun 27, 2025

Due to legacy ESLint config overriding rules applied on the same files,

what is happening exactly? Isn't eslint merging all rule objects from overrides that apply for a file?

Core defines it like this:

'packages/*/src/*/*.?(c|m)[jt]s?(x)'

https://github.com/mui/material-ui/blob/2d5a0bc597fb9d954504221f21f521042be969fe/.eslintrc.js#L436-L447

And I suspect that the following rule overrides the above:

mui-x/.eslintrc.js

Lines 265 to 270 in 782eaa3

files: ['packages/*/src/**/*.?(c|m)[jt]s?(x)'],
excludedFiles: ['*.d.ts', '*.spec.*'],
rules: {
'material-ui/mui-name-matches-component-name': [
'error',
{

@LukasTy LukasTy merged commit 5cef610 into mui:master Jun 27, 2025
26 checks passed
@LukasTy LukasTy deleted the fix-eslint-disallow-react-api-in-server-components-rule branch June 27, 2025 17:20
@Janpot
Copy link
Member

Janpot commented Jun 28, 2025

And I suspect that the following rule overrides the above:

🤔 As far as I understand all rules objects in all overrides that apply to a certain file are merged together. So I don't see how the material-ui/mui-name-matches-component-name rule can override material-ui/disallow-react-api-in-server-components even if the files are the same.

@LukasTy
Copy link
Member Author

LukasTy commented Jun 30, 2025

And I suspect that the following rule overrides the above:

🤔 As far as I understand all rules objects in all overrides that apply to a certain file are merged together. So I don't see how the material-ui/mui-name-matches-component-name rule can override material-ui/disallow-react-api-in-server-components even if the files are the same.

Are you referring to the flat config, or the old one? 🤔
On the flat config this is correct, but in the current config, it's not.
I wanted to avoid bloating the ESLint migration PR with extra noise.

@Janpot
Copy link
Member

Janpot commented Jun 30, 2025

Are you referring to the flat config, or the old one? 🤔

The old one.

On the flat config this is correct, but in the current config, it's not.

Are you saying that if I do

{
  "rules": {
    "quotes": ["error", "double"],
    "indent": ["error", 2]
  },

  "overrides": [
    {
      "files": ["*.js"],
      "rules": {
        "quotes": ["error", "single"]
      }
    },
    {
      "files": ["*.js"],
      "rules": {
        "indent": ["error", 4]
      }
    }
  ]
}

the resolved rules for a js file wouldn't be

{
  "quotes": ["error", "single"],
  "indent": ["error", 4]
}

but

{
  "quotes": ["error", "double"],
  "indent": ["error", 4]
}

as the first override would be completely ignored?

@Janpot
Copy link
Member

Janpot commented Jun 30, 2025

Checked it with

pnpm dlx eslint@8 --print-config somefile.js

and I get

// ...
  "rules": {
    "indent": [
      "error",
      4
    ],
    "quotes": [
      "error",
      "single"
    ]
  },
  "settings": {},
// ...

@LukasTy
Copy link
Member Author

LukasTy commented Jun 30, 2025

Checked it with

pnpm dlx eslint@8 --print-config somefile.js

and I get

// ...
  "rules": {
    "indent": [
      "error",
      4
    ],
    "quotes": [
      "error",
      "single"
    ]
  },
  "settings": {},
// ...

I assumed that it works as in this comment (#18570 (comment)), but I didn't check the resolved config. 🤔
In this case, I'm no longer sure why the overrides were not being merged...
Maybe it's because files in combination with ignores was the problem?
Or even higher probability - material-ui rule prefix, which mui-x overrides with it's own rule, hence, rules from monorepo might not have been working. 🙈 🤷

@Janpot
Copy link
Member

Janpot commented Jun 30, 2025

Ah, I see what's going on. The core rule

    {
      files: ['packages/*/src/*/*.?(c|m)[jt]s?(x)'],
      excludedFiles: ['*.spec.*', '*.test.*', '**/mui-joy/**/*', '**/mui-docs/**/*'],
      rules: {
        'material-ui/disallow-react-api-in-server-components': 'error',
      },
    },

is deliberately only targeting one level deep in the src folder as it's meant for entrypoints only (notice the single *). The goal is not to add 'use client' to every file, just to the client boundaries. edit: we can't actually add it to the index files due to a bug in next.js.

@LukasTy
Copy link
Member Author

LukasTy commented Jun 30, 2025

Good observation! 🙌
I missed the difference between ** and *.
However, I think that the rule on mui-x is safer, since we sometimes re-export a file from deeper path on 2nd level, which would be missed by such a static rule. 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
scope: code-infra Changes related to the core-infra product. type: bug It doesn't behave as expected.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants