From f239431f3a44c1945217cbc4270fecf2596a4ae6 Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Thu, 22 Oct 2020 16:33:38 -0600 Subject: [PATCH 1/5] Add a flag to opt out of using the new jsx runtime --- packages/babel-preset-react-app/create.js | 13 +++---------- packages/eslint-config-react-app/base.js | 11 ++--------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/packages/babel-preset-react-app/create.js b/packages/babel-preset-react-app/create.js index 50ad64e6950..0e3d25a7d08 100644 --- a/packages/babel-preset-react-app/create.js +++ b/packages/babel-preset-react-app/create.js @@ -8,14 +8,7 @@ const path = require('path'); -const hasJsxRuntime = (() => { - try { - require.resolve('react/jsx-runtime.js'); - return true; - } catch (e) { - return false; - } -})(); +const useJsxRuntime = process.env.DISABLE_NEW_JSX_TRANSFORM !== 'true'; const validateBoolOption = (name, value, defaultValue) => { if (typeof value === 'undefined') { @@ -104,8 +97,8 @@ module.exports = function (api, opts, env) { development: isEnvDevelopment || isEnvTest, // Will use the native built-in instead of trying to polyfill // behavior for any plugins that require one. - ...(!hasJsxRuntime ? { useBuiltIns: true } : {}), - runtime: hasJsxRuntime ? 'automatic' : 'classic', + ...(!useJsxRuntime ? { useBuiltIns: true } : {}), + runtime: useJsxRuntime ? 'automatic' : 'classic', }, ], isTypeScriptEnabled && [require('@babel/preset-typescript').default], diff --git a/packages/eslint-config-react-app/base.js b/packages/eslint-config-react-app/base.js index bea4f87b36f..53716de1a8e 100644 --- a/packages/eslint-config-react-app/base.js +++ b/packages/eslint-config-react-app/base.js @@ -11,14 +11,7 @@ // React App support, and is used as the `baseConfig` for `eslint-loader` // to ensure that user-provided configs don't need this boilerplate. -const hasJsxRuntime = (() => { - try { - require.resolve('react/jsx-runtime.js'); - return true; - } catch (e) { - return false; - } -})(); +const useJsxRuntime = process.env.DISABLE_NEW_JSX_RUNTIME !== 'true'; module.exports = { root: true, @@ -52,7 +45,7 @@ module.exports = { rules: { 'react/jsx-uses-vars': 'warn', 'react/jsx-uses-react': 'warn', - ...(!hasJsxRuntime && { + ...(!useJsxRuntime && { 'react/react-in-jsx-scope': 'error', }), }, From 23848c4c71de7c59af4fa6816dc4ab911516a006 Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Thu, 22 Oct 2020 16:38:27 -0600 Subject: [PATCH 2/5] Update docs --- docusaurus/docs/advanced-configuration.md | 39 ++++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/docusaurus/docs/advanced-configuration.md b/docusaurus/docs/advanced-configuration.md index 6da2ad174e0..7f0189c6fc2 100644 --- a/docusaurus/docs/advanced-configuration.md +++ b/docusaurus/docs/advanced-configuration.md @@ -7,22 +7,23 @@ You can adjust various development and production settings by setting environmen > Note: You do not need to declare `REACT_APP_` before the below variables as you would with custom environment variables. -| Variable | Development | Production | Usage | -| :---------------------- | :---------: | :--------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| BROWSER | βœ… Used | 🚫 Ignored | By default, Create React App will open the default system browser, favoring Chrome on macOS. Specify a [browser](https://github.com/sindresorhus/open#app) to override this behavior, or set it to `none` to disable it completely. If you need to customize the way the browser is launched, you can specify a node script instead. Any arguments passed to `npm start` will also be passed to this script, and the url where your app is served will be the last argument. Your script's file name must have the `.js` extension. | -| BROWSER_ARGS | βœ… Used | 🚫 Ignored | When the `BROWSER` environment variable is specified, any arguments that you set to this environment variable will be passed to the browser instance. Multiple arguments are supported as a space separated list. By default, no arguments are passed through to browsers. | -| HOST | βœ… Used | 🚫 Ignored | By default, the development web server binds to all hostnames on the device (`localhost`, LAN network address, etc.). You may use this variable to specify a different host. | -| PORT | βœ… Used | 🚫 Ignored | By default, the development web server will attempt to listen on port 3000 or prompt you to attempt the next available port. You may use this variable to specify a different port. | -| HTTPS | βœ… Used | 🚫 Ignored | When set to `true`, Create React App will run the development server in `https` mode. | -| WDS_SOCKET_HOST | βœ… Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket hostname for hot module reloading. Normally, `webpack-dev-server` defaults to `window.location.hostname` for the SockJS hostname. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockhost) for more details. | -| WDS_SOCKET_PATH | βœ… Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket path for hot module reloading. Normally, `webpack-dev-server` defaults to `/sockjs-node` for the SockJS pathname. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockpath) for more details. | -| WDS_SOCKET_PORT | βœ… Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket port for hot module reloading. Normally, `webpack-dev-server` defaults to `window.location.port` for the SockJS port. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockport) for more details. | -| PUBLIC_URL | βœ… Used | βœ… Used | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](deployment#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application. | -| CI | βœ… Used | βœ… Used | When set to `true`, Create React App treats warnings as failures in the build. It also makes the test runner non-watching. Most CIs set this flag by default. | -| REACT_EDITOR | βœ… Used | 🚫 Ignored | When an app crashes in development, you will see an error overlay with clickable stack trace. When you click on it, Create React App will try to determine the editor you are using based on currently running processes, and open the relevant source file. You can [send a pull request to detect your editor of choice](https://github.com/facebook/create-react-app/issues/2636). Setting this environment variable overrides the automatic detection. If you do it, make sure your systems [PATH]() environment variable points to your editor’s bin folder. You can also set it to `none` to disable it completely. | -| CHOKIDAR_USEPOLLING | βœ… Used | 🚫 Ignored | When set to `true`, the watcher runs in polling mode, as necessary inside a VM. Use this option if `npm start` isn't detecting changes. | -| GENERATE_SOURCEMAP | 🚫 Ignored | βœ… Used | When set to `false`, source maps are not generated for a production build. This solves out of memory (OOM) issues on some smaller machines. | -| INLINE_RUNTIME_CHUNK | 🚫 Ignored | βœ… Used | By default, Create React App will embed the runtime script into `index.html` during the production build. When set to `false`, the script will not be embedded and will be imported as usual. This is normally required when dealing with CSP. | -| IMAGE_INLINE_SIZE_LIMIT | 🚫 Ignored | βœ… Used | By default, images smaller than 10,000 bytes are encoded as a data URI in base64 and inlined in the CSS or JS build artifact. Set this to control the size limit in bytes. Setting it to 0 will disable the inlining of images. | -| FAST_REFRESH | βœ… Used | 🚫 Ignored | When set to `false`, disables experimental support for Fast Refresh to allow you to tweak your components in real time without reloading the page. | -| TSC_COMPILE_ON_ERROR | βœ… Used | βœ… Used | When set to `true`, you can run and properly build TypeScript projects even if there are TypeScript type check errors. These errors are printed as warnings in the terminal and/or browser console. | +| Variable | Development | Production | Usage | +| :------------------------ | :---------: | :--------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| BROWSER | βœ… Used | 🚫 Ignored | By default, Create React App will open the default system browser, favoring Chrome on macOS. Specify a [browser](https://github.com/sindresorhus/open#app) to override this behavior, or set it to `none` to disable it completely. If you need to customize the way the browser is launched, you can specify a node script instead. Any arguments passed to `npm start` will also be passed to this script, and the url where your app is served will be the last argument. Your script's file name must have the `.js` extension. | +| BROWSER_ARGS | βœ… Used | 🚫 Ignored | When the `BROWSER` environment variable is specified, any arguments that you set to this environment variable will be passed to the browser instance. Multiple arguments are supported as a space separated list. By default, no arguments are passed through to browsers. | +| HOST | βœ… Used | 🚫 Ignored | By default, the development web server binds to all hostnames on the device (`localhost`, LAN network address, etc.). You may use this variable to specify a different host. | +| PORT | βœ… Used | 🚫 Ignored | By default, the development web server will attempt to listen on port 3000 or prompt you to attempt the next available port. You may use this variable to specify a different port. | +| HTTPS | βœ… Used | 🚫 Ignored | When set to `true`, Create React App will run the development server in `https` mode. | +| WDS_SOCKET_HOST | βœ… Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket hostname for hot module reloading. Normally, `webpack-dev-server` defaults to `window.location.hostname` for the SockJS hostname. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockhost) for more details. | +| WDS_SOCKET_PATH | βœ… Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket path for hot module reloading. Normally, `webpack-dev-server` defaults to `/sockjs-node` for the SockJS pathname. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockpath) for more details. | +| WDS_SOCKET_PORT | βœ… Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket port for hot module reloading. Normally, `webpack-dev-server` defaults to `window.location.port` for the SockJS port. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockport) for more details. | +| PUBLIC_URL | βœ… Used | βœ… Used | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](deployment#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application. | +| CI | βœ… Used | βœ… Used | When set to `true`, Create React App treats warnings as failures in the build. It also makes the test runner non-watching. Most CIs set this flag by default. | +| REACT_EDITOR | βœ… Used | 🚫 Ignored | When an app crashes in development, you will see an error overlay with clickable stack trace. When you click on it, Create React App will try to determine the editor you are using based on currently running processes, and open the relevant source file. You can [send a pull request to detect your editor of choice](https://github.com/facebook/create-react-app/issues/2636). Setting this environment variable overrides the automatic detection. If you do it, make sure your systems [PATH]() environment variable points to your editor’s bin folder. You can also set it to `none` to disable it completely. | +| CHOKIDAR_USEPOLLING | βœ… Used | 🚫 Ignored | When set to `true`, the watcher runs in polling mode, as necessary inside a VM. Use this option if `npm start` isn't detecting changes. | +| GENERATE_SOURCEMAP | 🚫 Ignored | βœ… Used | When set to `false`, source maps are not generated for a production build. This solves out of memory (OOM) issues on some smaller machines. | +| INLINE_RUNTIME_CHUNK | 🚫 Ignored | βœ… Used | By default, Create React App will embed the runtime script into `index.html` during the production build. When set to `false`, the script will not be embedded and will be imported as usual. This is normally required when dealing with CSP. | +| IMAGE_INLINE_SIZE_LIMIT | 🚫 Ignored | βœ… Used | By default, images smaller than 10,000 bytes are encoded as a data URI in base64 and inlined in the CSS or JS build artifact. Set this to control the size limit in bytes. Setting it to 0 will disable the inlining of images. | +| FAST_REFRESH | βœ… Used | 🚫 Ignored | When set to `false`, disables experimental support for Fast Refresh to allow you to tweak your components in real time without reloading the page. | +| TSC_COMPILE_ON_ERROR | βœ… Used | βœ… Used | When set to `true`, you can run and properly build TypeScript projects even if there are TypeScript type check errors. These errors are printed as warnings in the terminal and/or browser console. | +| DISABLE_NEW_JSX_TRANSFORM | βœ… Used | βœ… Used | When set to `true`, disables the [new JSX transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) introduced in React 17 and backported to React 16.14.0, 15.7.0, and 0.14.10. New projects will use a version of React that supports this by default but you may need to disable it in existing projects if you can't upgrade React. | From b70cb5dfef257033ed00f1ed98966d565f9d5ac7 Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Thu, 22 Oct 2020 16:39:52 -0600 Subject: [PATCH 3/5] Fix flag naming --- packages/babel-preset-react-app/create.js | 6 +++--- packages/eslint-config-react-app/base.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/babel-preset-react-app/create.js b/packages/babel-preset-react-app/create.js index 0e3d25a7d08..699d5229161 100644 --- a/packages/babel-preset-react-app/create.js +++ b/packages/babel-preset-react-app/create.js @@ -8,7 +8,7 @@ const path = require('path'); -const useJsxRuntime = process.env.DISABLE_NEW_JSX_TRANSFORM !== 'true'; +const useJsxTransform = process.env.DISABLE_NEW_JSX_TRANSFORM !== 'true'; const validateBoolOption = (name, value, defaultValue) => { if (typeof value === 'undefined') { @@ -97,8 +97,8 @@ module.exports = function (api, opts, env) { development: isEnvDevelopment || isEnvTest, // Will use the native built-in instead of trying to polyfill // behavior for any plugins that require one. - ...(!useJsxRuntime ? { useBuiltIns: true } : {}), - runtime: useJsxRuntime ? 'automatic' : 'classic', + ...(!useJsxTransform ? { useBuiltIns: true } : {}), + runtime: useJsxTransform ? 'automatic' : 'classic', }, ], isTypeScriptEnabled && [require('@babel/preset-typescript').default], diff --git a/packages/eslint-config-react-app/base.js b/packages/eslint-config-react-app/base.js index 53716de1a8e..65229b150dd 100644 --- a/packages/eslint-config-react-app/base.js +++ b/packages/eslint-config-react-app/base.js @@ -11,7 +11,7 @@ // React App support, and is used as the `baseConfig` for `eslint-loader` // to ensure that user-provided configs don't need this boilerplate. -const useJsxRuntime = process.env.DISABLE_NEW_JSX_RUNTIME !== 'true'; +const useJsxTransform = process.env.DISABLE_NEW_JSX_TRANSFORM !== 'true'; module.exports = { root: true, @@ -45,7 +45,7 @@ module.exports = { rules: { 'react/jsx-uses-vars': 'warn', 'react/jsx-uses-react': 'warn', - ...(!useJsxRuntime && { + ...(!useJsxTransform && { 'react/react-in-jsx-scope': 'error', }), }, From 1af9e97421ed8f4b07cfdd5a0f1f92230945dd3c Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Thu, 22 Oct 2020 17:42:14 -0600 Subject: [PATCH 4/5] Attempt to add back jsx transform detection --- packages/babel-preset-react-app/create.js | 10 ++++--- packages/eslint-config-react-app/base.js | 5 ---- .../react-scripts/config/webpack.config.js | 27 ++++++++++++++++++- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/babel-preset-react-app/create.js b/packages/babel-preset-react-app/create.js index 699d5229161..df2ec31338f 100644 --- a/packages/babel-preset-react-app/create.js +++ b/packages/babel-preset-react-app/create.js @@ -8,8 +8,6 @@ const path = require('path'); -const useJsxTransform = process.env.DISABLE_NEW_JSX_TRANSFORM !== 'true'; - const validateBoolOption = (name, value, defaultValue) => { if (typeof value === 'undefined') { value = defaultValue; @@ -56,6 +54,10 @@ module.exports = function (api, opts, env) { ); } + var hasJsxRuntime = Boolean( + api.caller(caller => !!caller && caller.hasJsxRuntime) + ); + if (!isEnvDevelopment && !isEnvProduction && !isEnvTest) { throw new Error( 'Using `babel-preset-react-app` requires that you specify `NODE_ENV` or ' + @@ -97,8 +99,8 @@ module.exports = function (api, opts, env) { development: isEnvDevelopment || isEnvTest, // Will use the native built-in instead of trying to polyfill // behavior for any plugins that require one. - ...(!useJsxTransform ? { useBuiltIns: true } : {}), - runtime: useJsxTransform ? 'automatic' : 'classic', + ...(!hasJsxRuntime ? { useBuiltIns: true } : {}), + runtime: hasJsxRuntime ? 'automatic' : 'classic', }, ], isTypeScriptEnabled && [require('@babel/preset-typescript').default], diff --git a/packages/eslint-config-react-app/base.js b/packages/eslint-config-react-app/base.js index 65229b150dd..4b6bcd6f8ef 100644 --- a/packages/eslint-config-react-app/base.js +++ b/packages/eslint-config-react-app/base.js @@ -11,8 +11,6 @@ // React App support, and is used as the `baseConfig` for `eslint-loader` // to ensure that user-provided configs don't need this boilerplate. -const useJsxTransform = process.env.DISABLE_NEW_JSX_TRANSFORM !== 'true'; - module.exports = { root: true, @@ -45,8 +43,5 @@ module.exports = { rules: { 'react/jsx-uses-vars': 'warn', 'react/jsx-uses-react': 'warn', - ...(!useJsxTransform && { - 'react/react-in-jsx-scope': 'error', - }), }, }; diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index a33a814b472..80c6ac27aca 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -71,6 +71,19 @@ const cssModuleRegex = /\.module\.css$/; const sassRegex = /\.(scss|sass)$/; const sassModuleRegex = /\.module\.(scss|sass)$/; +const hasJsxRuntime = (() => { + if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { + return false; + } + + try { + require.resolve('react/jsx-runtime'); + return true; + } catch (e) { + return false; + } +})(); + // This is the production and development configuration. // It is focused on developer experience, fast rebuilds, and a minimal bundle. module.exports = function (webpackEnv) { @@ -396,7 +409,14 @@ module.exports = function (webpackEnv) { // @remove-on-eject-begin babelrc: false, configFile: false, - presets: [require.resolve('babel-preset-react-app')], + presets: [ + [ + require.resolve('babel-preset-react-app'), + { + runtime: hasJsxRuntime ? 'automatic' : 'classic', + }, + ], + ], // Make sure we have a unique cache identifier, erring on the // side of caution. // We remove this when the user ejects because the default @@ -737,6 +757,11 @@ module.exports = function (webpackEnv) { resolvePluginsRelativeTo: __dirname, baseConfig: { extends: [require.resolve('eslint-config-react-app/base')], + rules: { + ...(!hasJsxRuntime && { + 'react/react-in-jsx-scope': 'error', + }), + }, }, }), ].filter(Boolean), From 090d5b4522fcd8c0377c09edd7b84ae9b3f81cd3 Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Thu, 22 Oct 2020 18:07:07 -0600 Subject: [PATCH 5/5] Fix runtime detection in babel preset --- packages/babel-preset-react-app/create.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/babel-preset-react-app/create.js b/packages/babel-preset-react-app/create.js index df2ec31338f..99a930ba470 100644 --- a/packages/babel-preset-react-app/create.js +++ b/packages/babel-preset-react-app/create.js @@ -54,10 +54,6 @@ module.exports = function (api, opts, env) { ); } - var hasJsxRuntime = Boolean( - api.caller(caller => !!caller && caller.hasJsxRuntime) - ); - if (!isEnvDevelopment && !isEnvProduction && !isEnvTest) { throw new Error( 'Using `babel-preset-react-app` requires that you specify `NODE_ENV` or ' + @@ -99,8 +95,8 @@ module.exports = function (api, opts, env) { development: isEnvDevelopment || isEnvTest, // Will use the native built-in instead of trying to polyfill // behavior for any plugins that require one. - ...(!hasJsxRuntime ? { useBuiltIns: true } : {}), - runtime: hasJsxRuntime ? 'automatic' : 'classic', + ...(opts.runtime !== 'automatic' ? { useBuiltIns: true } : {}), + runtime: opts.runtime || 'classic', }, ], isTypeScriptEnabled && [require('@babel/preset-typescript').default],