From 6ba1f0dd2293cbb06b52da110024b9c587310465 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 24 May 2020 13:55:29 -0700 Subject: [PATCH] Implement `@babel/plugin-transform-react-pure-annotations` (#11428) The new plugin is also enabled in `@babel/preset-react` --- .../.npmignore | 3 + .../package.json | 25 ++++++ .../src/index.js | 79 +++++++++++++++++++ .../fixtures/react-dom/createPortal/input.js | 4 + .../react-dom/createPortal/options.json | 4 + .../react-dom/createPortal/output.mjs | 3 + .../test/fixtures/react/cloneElement/input.js | 3 + .../fixtures/react/cloneElement/options.json | 4 + .../fixtures/react/cloneElement/output.mjs | 4 + .../fixtures/react/createElement/input.js | 3 + .../fixtures/react/createElement/options.json | 4 + .../fixtures/react/createElement/output.mjs | 4 + .../fixtures/react/createFactory/input.js | 3 + .../fixtures/react/createFactory/options.json | 4 + .../fixtures/react/createFactory/output.mjs | 2 + .../test/fixtures/react/createRef/input.js | 3 + .../fixtures/react/createRef/options.json | 4 + .../test/fixtures/react/createRef/output.mjs | 4 + .../test/fixtures/react/forwardRef/input.js | 3 + .../fixtures/react/forwardRef/options.json | 4 + .../test/fixtures/react/forwardRef/output.mjs | 2 + .../fixtures/react/isValidElement/input.js | 3 + .../react/isValidElement/options.json | 4 + .../fixtures/react/isValidElement/output.mjs | 2 + .../test/fixtures/react/lazy/input.js | 3 + .../test/fixtures/react/lazy/options.json | 4 + .../test/fixtures/react/lazy/output.mjs | 2 + .../test/fixtures/react/memo/input.js | 3 + .../test/fixtures/react/memo/options.json | 4 + .../test/fixtures/react/memo/output.mjs | 2 + .../test/index.js | 3 + packages/babel-preset-react/package.json | 3 +- packages/babel-preset-react/src/index.js | 2 + .../preset-options/pure-false/input.js | 3 + .../preset-options/pure-false/options.json | 4 + .../preset-options/pure-false/output.mjs | 2 + .../fixtures/preset-options/pure/input.js | 3 + .../fixtures/preset-options/pure/options.json | 4 + .../fixtures/preset-options/pure/output.mjs | 2 + 39 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 packages/babel-plugin-transform-react-pure-annotations/.npmignore create mode 100644 packages/babel-plugin-transform-react-pure-annotations/package.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/src/index.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/input.js create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/options.json create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/output.mjs create mode 100644 packages/babel-plugin-transform-react-pure-annotations/test/index.js create mode 100644 packages/babel-preset-react/test/fixtures/preset-options/pure-false/input.js create mode 100644 packages/babel-preset-react/test/fixtures/preset-options/pure-false/options.json create mode 100644 packages/babel-preset-react/test/fixtures/preset-options/pure-false/output.mjs create mode 100644 packages/babel-preset-react/test/fixtures/preset-options/pure/input.js create mode 100644 packages/babel-preset-react/test/fixtures/preset-options/pure/options.json create mode 100644 packages/babel-preset-react/test/fixtures/preset-options/pure/output.mjs diff --git a/packages/babel-plugin-transform-react-pure-annotations/.npmignore b/packages/babel-plugin-transform-react-pure-annotations/.npmignore new file mode 100644 index 000000000000..f9806945836e --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-transform-react-pure-annotations/package.json b/packages/babel-plugin-transform-react-pure-annotations/package.json new file mode 100644 index 000000000000..d6a04c9163fc --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/package.json @@ -0,0 +1,25 @@ +{ + "name": "@babel/plugin-transform-react-pure-annotations", + "version": "7.9.4", + "description": "Mark top-level React method calls as pure for tree shaking", + "repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-pure", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "main": "lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "devDependencies": { + "@babel/core": "^7.9.0", + "@babel/helper-plugin-test-runner": "^7.8.3" + } +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/src/index.js b/packages/babel-plugin-transform-react-pure-annotations/src/index.js new file mode 100644 index 000000000000..14ed44c12708 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/src/index.js @@ -0,0 +1,79 @@ +import { declare } from "@babel/helper-plugin-utils"; +import annotateAsPure from "@babel/helper-annotate-as-pure"; +import { types as t } from "@babel/core"; + +// Mapping of React top-level methods that are pure. +// This plugin adds a /*#__PURE__#/ annotation to calls to these methods, +// so that terser and other minifiers can safely remove them during dead +// code elimination. +// See https://reactjs.org/docs/react-api.html +const PURE_CALLS = new Map([ + [ + "react", + [ + "cloneElement", + "createElement", + "createFactory", + "createRef", + "forwardRef", + "isValidElement", + "memo", + "lazy", + ], + ], + ["react-dom", ["createPortal"]], +]); + +export default declare(api => { + api.assertVersion(7); + + return { + name: "transform-react-pure-annotations", + visitor: { + CallExpression(path) { + if (isReactCall(path)) { + annotateAsPure(path); + } + }, + }, + }; +}); + +function isReactCall(path) { + // If the callee is not a member expression, then check if it matches + // a named import, e.g. `import {forwardRef} from 'react'`. + if (!t.isMemberExpression(path.node.callee)) { + const callee = path.get("callee"); + for (const [module, methods] of PURE_CALLS) { + for (const method of methods) { + if (callee.referencesImport(module, method)) { + return true; + } + } + } + + return false; + } + + // Otherwise, check if the member expression's object matches + // a default import (`import React from 'react'`) or namespace + // import (`import * as React from 'react'), and check if the + // property matches one of the pure methods. + for (const [module, methods] of PURE_CALLS) { + const object = path.get("callee.object"); + if ( + object.referencesImport(module, "default") || + object.referencesImport(module, "*") + ) { + for (const method of methods) { + if (t.isIdentifier(path.node.callee.property, { name: method })) { + return true; + } + } + + return false; + } + } + + return false; +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/input.js new file mode 100644 index 000000000000..fa90a3842765 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/input.js @@ -0,0 +1,4 @@ +import * as React from 'react'; +import ReactDOM from 'react-dom'; + +const Portal = ReactDOM.createPortal(React.createElement('div'), document.getElementById('test')); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/output.mjs new file mode 100644 index 000000000000..5ad84774772f --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react-dom/createPortal/output.mjs @@ -0,0 +1,3 @@ +import * as React from 'react'; +import ReactDOM from 'react-dom'; +const Portal = /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement('div'), document.getElementById('test')); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/input.js new file mode 100644 index 000000000000..2e023247d55c --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/input.js @@ -0,0 +1,3 @@ +import React from 'react'; + +React.cloneElement(React.createElement('div')); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/output.mjs new file mode 100644 index 000000000000..c05fd3e356d0 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/cloneElement/output.mjs @@ -0,0 +1,4 @@ +import React from 'react'; + +/*#__PURE__*/ +React.cloneElement( /*#__PURE__*/React.createElement('div')); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/input.js new file mode 100644 index 000000000000..70a1f8f2dfd1 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/input.js @@ -0,0 +1,3 @@ +import React from 'react'; + +React.createElement('div'); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/output.mjs new file mode 100644 index 000000000000..f65cf5f296b3 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createElement/output.mjs @@ -0,0 +1,4 @@ +import React from 'react'; + +/*#__PURE__*/ +React.createElement('div'); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/input.js new file mode 100644 index 000000000000..38bb1d1b998c --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/input.js @@ -0,0 +1,3 @@ +import {createFactory} from 'react'; + +const div = createFactory('div'); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/output.mjs new file mode 100644 index 000000000000..e6762916a0e8 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createFactory/output.mjs @@ -0,0 +1,2 @@ +import { createFactory } from 'react'; +const div = /*#__PURE__*/createFactory('div'); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/input.js new file mode 100644 index 000000000000..4ef3d45f6d30 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/input.js @@ -0,0 +1,3 @@ +import React from 'react'; + +React.createRef(); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/output.mjs new file mode 100644 index 000000000000..3fb443880a8e --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/createRef/output.mjs @@ -0,0 +1,4 @@ +import React from 'react'; + +/*#__PURE__*/ +React.createRef(); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/input.js new file mode 100644 index 000000000000..2002155083a7 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/input.js @@ -0,0 +1,3 @@ +import {forwardRef} from 'react'; + +const Comp = forwardRef((props, ref) => null); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/output.mjs new file mode 100644 index 000000000000..14378e97d6ad --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/forwardRef/output.mjs @@ -0,0 +1,2 @@ +import { forwardRef } from 'react'; +const Comp = /*#__PURE__*/forwardRef((props, ref) => null); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/input.js new file mode 100644 index 000000000000..61175d7878d2 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/input.js @@ -0,0 +1,3 @@ +import React from 'react'; + +const isElement = React.isValidElement(React.createElement('div')); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/output.mjs new file mode 100644 index 000000000000..b8a4817191af --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/isValidElement/output.mjs @@ -0,0 +1,2 @@ +import React from 'react'; +const isElement = /*#__PURE__*/React.isValidElement( /*#__PURE__*/React.createElement('div')); \ No newline at end of file diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/input.js new file mode 100644 index 000000000000..1f2379150c5f --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/input.js @@ -0,0 +1,3 @@ +import React from 'react'; + +const SomeComponent = React.lazy(() => import('./SomeComponent')); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/output.mjs new file mode 100644 index 000000000000..5c6cf1327179 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/lazy/output.mjs @@ -0,0 +1,2 @@ +import React from 'react'; +const SomeComponent = /*#__PURE__*/React.lazy(() => import('./SomeComponent')); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/input.js b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/input.js new file mode 100644 index 000000000000..c53d22c31a88 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/input.js @@ -0,0 +1,3 @@ +import React from 'react'; + +const Comp = React.memo((props) => null); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/options.json b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/options.json new file mode 100644 index 000000000000..d5601dabff95 --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["transform-react-pure-annotations"] +} diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/output.mjs b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/output.mjs new file mode 100644 index 000000000000..9364c2d6127d --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/fixtures/react/memo/output.mjs @@ -0,0 +1,2 @@ +import React from 'react'; +const Comp = /*#__PURE__*/React.memo(props => null); diff --git a/packages/babel-plugin-transform-react-pure-annotations/test/index.js b/packages/babel-plugin-transform-react-pure-annotations/test/index.js new file mode 100644 index 000000000000..1b534b8fc64a --- /dev/null +++ b/packages/babel-plugin-transform-react-pure-annotations/test/index.js @@ -0,0 +1,3 @@ +import runner from "@babel/helper-plugin-test-runner"; + +runner(__dirname); diff --git a/packages/babel-preset-react/package.json b/packages/babel-preset-react/package.json index 83ceffe03d3b..5639a6a1afe3 100644 --- a/packages/babel-preset-react/package.json +++ b/packages/babel-preset-react/package.json @@ -16,7 +16,8 @@ "@babel/plugin-transform-react-jsx": "^7.9.4", "@babel/plugin-transform-react-jsx-development": "^7.9.0", "@babel/plugin-transform-react-jsx-self": "^7.9.0", - "@babel/plugin-transform-react-jsx-source": "^7.9.0" + "@babel/plugin-transform-react-jsx-source": "^7.9.0", + "@babel/plugin-transform-react-pure-annotations": "^7.9.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" diff --git a/packages/babel-preset-react/src/index.js b/packages/babel-preset-react/src/index.js index 40f3e0e635d6..c57cc52ff580 100644 --- a/packages/babel-preset-react/src/index.js +++ b/packages/babel-preset-react/src/index.js @@ -4,6 +4,7 @@ import transformReactJSXDevelopment from "@babel/plugin-transform-react-jsx-deve import transformReactDisplayName from "@babel/plugin-transform-react-display-name"; import transformReactJSXSource from "@babel/plugin-transform-react-jsx-source"; import transformReactJSXSelf from "@babel/plugin-transform-react-jsx-self"; +import transformReactPure from "@babel/plugin-transform-react-pure-annotations"; export default declare((api, opts) => { api.assertVersion(7); @@ -55,6 +56,7 @@ export default declare((api, opts) => { }, ], transformReactDisplayName, + pure !== false && transformReactPure, development && runtime === "classic" && transformReactJSXSource, development && runtime === "classic" && transformReactJSXSelf, diff --git a/packages/babel-preset-react/test/fixtures/preset-options/pure-false/input.js b/packages/babel-preset-react/test/fixtures/preset-options/pure-false/input.js new file mode 100644 index 000000000000..2002155083a7 --- /dev/null +++ b/packages/babel-preset-react/test/fixtures/preset-options/pure-false/input.js @@ -0,0 +1,3 @@ +import {forwardRef} from 'react'; + +const Comp = forwardRef((props, ref) => null); diff --git a/packages/babel-preset-react/test/fixtures/preset-options/pure-false/options.json b/packages/babel-preset-react/test/fixtures/preset-options/pure-false/options.json new file mode 100644 index 000000000000..91c500e74d8b --- /dev/null +++ b/packages/babel-preset-react/test/fixtures/preset-options/pure-false/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "presets": [["react", {"pure": false}]] +} diff --git a/packages/babel-preset-react/test/fixtures/preset-options/pure-false/output.mjs b/packages/babel-preset-react/test/fixtures/preset-options/pure-false/output.mjs new file mode 100644 index 000000000000..10ae240e0d10 --- /dev/null +++ b/packages/babel-preset-react/test/fixtures/preset-options/pure-false/output.mjs @@ -0,0 +1,2 @@ +import { forwardRef } from 'react'; +const Comp = forwardRef((props, ref) => null); diff --git a/packages/babel-preset-react/test/fixtures/preset-options/pure/input.js b/packages/babel-preset-react/test/fixtures/preset-options/pure/input.js new file mode 100644 index 000000000000..2002155083a7 --- /dev/null +++ b/packages/babel-preset-react/test/fixtures/preset-options/pure/input.js @@ -0,0 +1,3 @@ +import {forwardRef} from 'react'; + +const Comp = forwardRef((props, ref) => null); diff --git a/packages/babel-preset-react/test/fixtures/preset-options/pure/options.json b/packages/babel-preset-react/test/fixtures/preset-options/pure/options.json new file mode 100644 index 000000000000..f3f20277d73d --- /dev/null +++ b/packages/babel-preset-react/test/fixtures/preset-options/pure/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "presets": ["react"] +} diff --git a/packages/babel-preset-react/test/fixtures/preset-options/pure/output.mjs b/packages/babel-preset-react/test/fixtures/preset-options/pure/output.mjs new file mode 100644 index 000000000000..14378e97d6ad --- /dev/null +++ b/packages/babel-preset-react/test/fixtures/preset-options/pure/output.mjs @@ -0,0 +1,2 @@ +import { forwardRef } from 'react'; +const Comp = /*#__PURE__*/forwardRef((props, ref) => null);