Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compiler: add verbose logging to react-compiler-healthcheck #29080

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Fausto95
Copy link

@Fausto95 Fausto95 commented May 15, 2024

Summary

This PR adds a verbose option to react-compiler-healthcheck CLI which logs all the compiled components/hooks names and files location.

Fixes: #29078

healthchekc

Test plan

Run the react-compiler-healthcheck CLI with the —-verbose flag inside a react app and you should be able to see the compiled components/hooks names or the files path printed in green.

If there are any files that failed to compile, they will be printed in red.

@Fausto95 Fausto95 force-pushed the compiler-healthcheck-verbose branch from d429825 to 4e30b93 Compare May 15, 2024 22:01
@react-sizebot
Copy link

react-sizebot commented May 15, 2024

Comparing: 5e11e7f...a33ece0

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.66 kB 6.66 kB = 1.82 kB 1.82 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 495.01 kB 495.01 kB = 88.67 kB 88.68 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.67 kB 6.67 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 499.81 kB 499.81 kB = 89.36 kB 89.36 kB
facebook-www/ReactDOM-prod.classic.js = 592.16 kB 592.16 kB = 104.15 kB 104.15 kB
facebook-www/ReactDOM-prod.modern.js = 568.39 kB 568.39 kB = 100.55 kB 100.55 kB
test_utils/ReactAllWarnings.js Deleted 64.26 kB 0.00 kB Deleted 16.02 kB 0.00 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
test_utils/ReactAllWarnings.js Deleted 64.26 kB 0.00 kB Deleted 16.02 kB 0.00 kB

Generated by 🚫 dangerJS against a33ece0

@Fausto95 Fausto95 force-pushed the compiler-healthcheck-verbose branch 2 times, most recently from ad2698e to 25e02cb Compare May 15, 2024 23:22
@Fausto95 Fausto95 force-pushed the compiler-healthcheck-verbose branch from 25e02cb to a33ece0 Compare May 15, 2024 23:25
@Fausto95
Copy link
Author

Fausto95 commented May 15, 2024

@poteto, @josephsavona would appreciate if you could review this

@Fausto95 Fausto95 changed the title feat: add a verbose option to react-compiler-healthcheck to log all c… compiler: add verbose logging to react-compiler-healthcheck May 16, 2024
@josephsavona
Copy link
Contributor

Can you explain more about how you would use this mode? The healthcheck command is intended as a lightweight way to get a general sense of how likely it is that your app will be compatible w the compiler.

@Fausto95
Copy link
Author

@josephsavona This mode would tell me the files that compile correctly, this would help me refactor those files and get rid of the manual useMemo & useCallbacks.

This would also help me figure out which files break the rules of React and understand the reason they failed compilation and further investigate.

@josephsavona
Copy link
Contributor

Thanks for the context, we'll discuss as a team about where we want to take the tool and whether this fits in. The original idea was just to give folks a quick way to check how easy it would be to adopt the compiler.

@Frenie8006
Copy link

Just accept the PR!

Copy link

@wojtekmaj wojtekmaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final code after applying all of my suggestions:

      for (const compilation of [...SucessfulCompilation, ...ActionableFailures, ...OtherFailures]) {
        const filename = compilation.fnLoc?.filename;

        switch (compilation.kind) {
          case "CompileSuccess": {
            const name = compilation.fnName;
            const isHook = name?.startsWith('use');

            if (name) {
              console.log(
                chalk.green(
                  `Successfully compiled ${isHook ? "hook" : "component" } [${name}](${filename})`
                )
              );
            } else {
              console.log(chalk.green(`Successfully compiled ${compilation.fnLoc?.filename}`));
            }
            break;
          }

          case "CompileError": {
            const { reason, severity, loc } = compilation.detail;

            const lnNo = loc.start?.line;
            const colNo = loc.start?.column;

            const isTodo = severity === ErrorSeverity.Todo;

            console.log(
              chalk[isTodo ? 'yellow' : 'red'](
                `Failed to compile ${
                  filename
                }${
                  lnNo !== undefined ? `:${lnNo}${
                    colNo !== undefined ? `:${colNo}` : ""
                  }` : ""
                }`
              ),
              reason? `\n  Reason: ${isTodo ? 'Unimplemented' : reason}` : ""
            );
            break;
          }
          default:
            break;
        }
      }

@@ -111,7 +111,7 @@ export default {
}
},

report(): void {
report(verbose: boolean): void {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make future options easier to implement, consider

Suggested change
report(verbose: boolean): void {
report({ verbose }: { verbose: boolean }): void {

}

if (compilation.kind === "CompileError") {
const reason = compilation.detail.description;
Copy link

@wojtekmaj wojtekmaj May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found description to be null in most cases. For example:

{
  kind: 'CompileError',
  fnLoc: {
    start: { line: 34, column: 15, index: 993 },
    end: { line: 68, column: 1, index: 1956 },
    filename: 'src/components/StationFinder/components/StationsMarkers.tsx',
    identifierName: undefined
  },
  detail: {
    reason: 'React Compiler has skipped optimizing this component because the existing manual memoization could not be preserved. This value may be mutated later, which could cause the value to change unexpectedly',
    description: null,
    severity: 'CannotPreserveMemoization',
    suggestions: null,
    loc: {
      start: [Object],
      end: [Object],
      filename: 'src/components/StationFinder/components/StationsMarkers.tsx',
      identifierName: undefined
    }
  }
}

Also, adding exact error location would be nice.

So something like this could work better:

            const { reason, severity, loc } = compilation.detail;

            const lnNo = loc.start?.line;
            const colNo = loc.start?.column;

            const isTodo = severity === ErrorSeverity.Todo;

            console.log(
              chalk[isTodo ? 'yellow' : 'red'](
                `Failed to compile ${
                  filename
                }${
                  lnNo !== undefined ? `:${lnNo}${
                    colNo !== undefined ? `:${colNo}` : ""
                  }` : ""
                }`
              ),
              reason? `\n  Reason: ${isTodo ? 'Unimplemented' : reason}` : ""
            );

for (const compilation of [...SucessfulCompilation, ...ActionableFailures, ...OtherFailures]) {
const filename = compilation.fnLoc?.filename;

if (compilation.kind === "CompileSuccess") {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be a switch()

}
}

if (compilation.kind === "CompileError") {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Certain errors have severity ErrorSeverity.Todo. I don't think it's worth making it all red, but I don't think we should skip this information either. So perhaps make it a different color or something?

@guillaumebrunerie
Copy link

This would also help me figure out which files break the rules of React and understand the reason they failed compilation and further investigate.

I think that’s what the ESLint plugin is for, rather than the healthcheck tool.

@wojtekmaj
Copy link

ESLint plugin is nowhere near as informative. It doesn't tell you when React Compiler bails out because of TODOs on RC side, or manual memoization.

@PinkaminaDianePie
Copy link

Thanks for the context, we'll discuss as a team about where we want to take the tool and whether this fits in. The original idea was just to give folks a quick way to check how easy it would be to adopt the compiler.

how easy

That's why we need a detailed list of files with the exact issues they have. When this tool tells me "issue in 100 components out of 1000" - it gives me no info, I still have 0 clue on how easy will it be to integrate anything. So I have to install eslint plugin, run the scan over my codebase, and eslint tells me that I have an issue not with 100 files, but with 6. What kind of conclusion may I have? Probably only 1 - react compiler is not even close to being production-ready, so I need to wait until the tooling around it becomes more useful. Currently, it feels like this utility is not just useless, but misleading. And until there will be no clear way to check it (like having a path to problematic file, with an eslint error there), people won't trust this tool

@Fausto95
Copy link
Author

@wojtekmaj I appreciate the suggestions.
Will apply some of them if the team decides to go with this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

request: [compiler] react-compiler-healthcheck display the list of compiled files.
8 participants