facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
224.98k stars 45.87k forks source link

[React 19] React Compiler is stripping spaces #29099

Open Curetix opened 1 month ago

Curetix commented 1 month ago

Summary

I tested the React Compiler by starting with the Vite React TS Template, updating to React 19 and adding the compiler plugin as described in the docs. With the compiler enabled, the component is missing spaces in some strings (count is0 and Editsrc/App.tsx):

image

The relevant code is:

<div className="card">
  <button onClick={() => setCount((count) => count + 1)}>
    count is {count}
  </button>
  <p>
    Edit <code>src/App.tsx</code> and save to test HMR
  </p>
</div>

Stackblitz: https://stackblitz.com/edit/vitejs-vite-y8oj4e

HoseinKhanBeigi commented 1 month ago

i think To address the issue with the React Compiler stripping spaces, you might need to adjust the configuration of the React Compiler or update the compiler plugin settings. npm install @vitejs/plugin-react@latest

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
});
damianstasik commented 1 month ago

This could be unrelated but disabling Babel's retainLines option inside @vitejs/plugin-react fixes it for me. When the option is enabled (!isProduction && isJSX && opts.jsxRuntime !== 'classic') a simple component like this:

import { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);

  return (
    <div className="card">
      <button onClick={() => setCount((count) => count + 1)}>
        count is {count}
      </button>
      <p>
        Edit <code>src/App.tsx</code> and save to test HMR
      </p>
    </div>
  );
}

export default App;

... gets transformed into:

import { c as _c } from "react/compiler-runtime";

import { useState } from 'react';

function App() {const $ = _c(6);
  const [count, setCount] = useState(0);let t0;if ($[0] === Symbol.for("react.memo_cache_sentinel")) {

    t0 = () => setCount((count_0) => count_0 + 1);$[0] = t0;} else {t0 = $[0];}let t1;if ($[1] !== count) {t1 = <button onClick={t0}>count is
      {count}
    </button>;$[1] = count;$[2] = t1;} else {t1 = $[2];}let t2;if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
    t2 = <p>Edit
      <code>src/App.tsx</code> and save to test HMR
    </p>;$[3] = t2;} else {t2 = $[3];}let t3;if ($[4] !== t1) {t3 = <div className="card">{t1}{t2}
    </div>;$[4] = t1;$[5] = t3;} else {t3 = $[5];}return t3;}

export default App;

and then ESBuild transforms it and we lose whitespace due to how the above output is split into multiple lines:

// shortened for brevity
t1 = /* @__PURE__ */ jsxDEV("button", { onClick: t0, children: [
  "count is",
  count
] }, void 0, true, {
  fileName: "src/App.tsx",
  lineNumber: 13,
  columnNumber: 113
}, this);
abizek commented 1 month ago

Spaces are not stripped on build. The issue seems to be with ESBuild.

damianstasik commented 1 month ago

It happens before the step with ESBuild – it's something that Babel does when the retainLines option is enabled. I've checked running the code from the playground through ESBuild with Vite's internal config and the output was correct.

ArnaudBarre commented 1 month ago

Hi there. I think retains line doesn't make sense when the compiler is enabled, lines get move around too much. I'll publish a fix for that tomorrow.

josephsavona commented 1 month ago

Thanks for reporting this! It sounds like this is an issue with how React Compiler and other tools are interacting. You can see from the playground that the compiler is retaining the space: https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYhBABQCURwAOsUTAjrMRQ0V0QDwAmeAG5E4AGwCGYMADlxAWwREAvETog44mHzVEAfJ14AjKDhyEihAMKi8cANZLg1ZbqJgWl6JhwUKcLzg0Sq7+WDhEANREAIxUAL76jFyh3kR4YLQpOHEGPAD0xqaEiVw8AA4l3ACiAuE8-nwIumDweQCCZWUAdDhgAB75DU1E4ph8buKCimZEOAhg4QASALIASrl5FQz5AoK6VADcDHEgcUA

but we definitely want to make sure that it also just works with other tools. We’ll take a look!

Facug03 commented 1 month ago

how did you guys fix it? I tried disabling retainLines but it didnt work

damianstasik commented 1 month ago

@Facug03 if this lands retainLines will be disabled automatically if your Babel config includes babel-plugin-react-compiler.

ArnaudBarre commented 1 month ago

Just released in 4.3.0.

@josephsavona You probably want to remove this line too. I think this Babel option was made to avoid using source maps on light transformation, but I don't think it's enough robust to support AST re-ordering like the compiler is doing. I think this is fine to say that this is incompatible (maybe a warning could be logged when the option is enabled)