diff --git a/Cargo.lock b/Cargo.lock index f5315370205..9d90633abfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2182,9 +2182,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", diff --git a/crates/swc_ecma_transforms_compat/tests/classes/create-super-1/output.js b/crates/swc_ecma_transforms_compat/tests/classes/create-super-1/output.js index 4e378d87436..a6cd0d3cd7a 100644 --- a/crates/swc_ecma_transforms_compat/tests/classes/create-super-1/output.js +++ b/crates/swc_ecma_transforms_compat/tests/classes/create-super-1/output.js @@ -1,4 +1,4 @@ -let Foo = function(UnknownNativeClass) { +let Foo = /*#__PURE__*/ function(UnknownNativeClass) { "use strict"; _inherits(Foo, UnknownNativeClass); var _super = _createSuper(Foo); diff --git a/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties-loose/output.js b/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties-loose/output.js index 7b2c467b995..9d54fd5be5c 100644 --- a/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties-loose/output.js +++ b/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties-loose/output.js @@ -9,18 +9,23 @@ class Foo { var _class; this.Bar = (_class = class { constructor(){ - this.q = void 0; + this.q = void 0 // should not replace + ; } }, _class.p = void 0, _class.p1 = class { constructor(){ new.target; } - }, _class.p2 = new function _target() { + } // should not replace + , _class.p2 = new function _target() { this.constructor; - }, _class.p3 = function() { + } // should not replace + , _class.p3 = function() { void 0; - }, _class.p4 = function _target() { + } // should replace + , _class.p4 = function _target() { this.constructor; - }, _class); + } // should not replace + , _class); } } diff --git a/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties/output.js b/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties/output.js index d1d3fb65810..178c170ef8c 100644 --- a/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties/output.js +++ b/crates/swc_ecma_transforms_compat/tests/new-target/general/class-properties/output.js @@ -9,18 +9,23 @@ class Foo { var _class; this.Bar = (_class = class { constructor(){ - _defineProperty(this, "q", void 0); + _defineProperty(this, "q", void 0 // should not replace + ); } }, _defineProperty(_class, "p", void 0), _defineProperty(_class, "p1", class { constructor(){ new.target; } - }), _defineProperty(_class, "p2", new function _target() { + } // should not replace + ), _defineProperty(_class, "p2", new function _target() { this.constructor; - }), _defineProperty(_class, "p3", function() { + } // should not replace + ), _defineProperty(_class, "p3", function() { void 0; - }), _defineProperty(_class, "p4", function _target() { + } // should replace + ), _defineProperty(_class, "p4", function _target() { this.constructor; - }), _class); + } // should not replace + ), _class); } } diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/accessor/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/accessor/output.js index 2bebb622308..d51c98cd953 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/accessor/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/accessor/output.js @@ -1,5 +1,5 @@ var _foo = new WeakMap(); -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/field/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/field/output.js index 2957f9cf338..44674fce169 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/field/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/field/output.js @@ -1,5 +1,5 @@ var _foo = new WeakMap(); -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/method/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/method/output.js index ca6da6284ac..337342c9fb4 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/method/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/method/output.js @@ -1,5 +1,5 @@ var _foo = new WeakSet(); -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-other-redeclared/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-other-redeclared/output.js index cf8b0e49079..d88b42ec2d0 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-other-redeclared/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-other-redeclared/output.js @@ -1,5 +1,5 @@ var _foo = new WeakMap(), _bar = new WeakMap(); -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); @@ -17,7 +17,7 @@ let Foo = function() { key: "test", value: function test() { var _bar1 = new WeakMap(); - let Nested = function() { + let Nested = /*#__PURE__*/ function() { function Nested() { _classCallCheck(this, Nested); _classPrivateFieldInit(this, _bar1, { diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-redeclared/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-redeclared/output.js index b5ed319541f..fa3a8cdb82f 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-redeclared/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class-redeclared/output.js @@ -1,5 +1,5 @@ var _foo = new WeakMap(); -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); @@ -13,7 +13,7 @@ let Foo = function() { key: "test", value: function test() { var _foo1 = new WeakMap(); - let Nested = function() { + let Nested = /*#__PURE__*/ function() { function Nested() { _classCallCheck(this, Nested); _classPrivateFieldInit(this, _foo1, { diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class/output.js index d234f4651da..6359dfb277a 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/nested-class/output.js @@ -1,5 +1,5 @@ var _foo = new WeakMap(); -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); @@ -12,7 +12,7 @@ let Foo = function() { { key: "test", value: function test() { - let Nested = function() { + let Nested = /*#__PURE__*/ function() { function Nested() { _classCallCheck(this, Nested); } diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-accessor/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-accessor/output.js index 29bbbe1955b..5d2cfaa7e94 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-accessor/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-accessor/output.js @@ -1,4 +1,4 @@ -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-field/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-field/output.js index 121706eca64..37ee5d254ab 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-field/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-field/output.js @@ -1,4 +1,4 @@ -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); diff --git a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-method/output.js b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-method/output.js index ad67bc487a0..5473f73dfef 100644 --- a/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-method/output.js +++ b/crates/swc_ecma_transforms_compat/tests/private-in-object/private/static-method/output.js @@ -1,4 +1,4 @@ -let Foo = function() { +let Foo = /*#__PURE__*/ function() { "use strict"; function Foo() { _classCallCheck(this, Foo); @@ -13,5 +13,4 @@ let Foo = function() { ]); return Foo; }(); -function foo() { -} +function foo() {} diff --git a/crates/swc_ecma_transforms_optimization/tests/expr-simplifier/issue-3816/output.js b/crates/swc_ecma_transforms_optimization/tests/expr-simplifier/issue-3816/output.js index ab4caa6e354..99baa3ebe5d 100644 --- a/crates/swc_ecma_transforms_optimization/tests/expr-simplifier/issue-3816/output.js +++ b/crates/swc_ecma_transforms_optimization/tests/expr-simplifier/issue-3816/output.js @@ -1,4 +1,11 @@ -"use strict"; +/** @license React v17.0.2 + * react-jsx-runtime.profiling.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ "use strict"; require("object-assign"); var f = require("react"), g = 60103; exports.Fragment = 60107; diff --git a/crates/swc_ecma_transforms_react/src/jsx/tests.rs b/crates/swc_ecma_transforms_react/src/jsx/tests.rs index be1a4541a09..0101ed3991f 100644 --- a/crates/swc_ecma_transforms_react/src/jsx/tests.rs +++ b/crates/swc_ecma_transforms_react/src/jsx/tests.rs @@ -13,7 +13,7 @@ use swc_ecma_transforms_module::common_js::common_js; use swc_ecma_transforms_testing::{parse_options, test, test_fixture_allowing_error, Tester}; use super::*; -use crate::{display_name, react}; +use crate::{display_name, pure_annotations, react}; fn tr(t: &mut Tester, options: Options, top_level_mark: Mark) -> impl Fold { chain!( @@ -72,6 +72,7 @@ fn fixture_tr(t: &mut Tester, mut options: FixtureOptions) -> impl Fold { top_level_mark ), display_name(), + pure_annotations(Some(t.comments.clone())) ) } diff --git a/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-dev-transform/output.mjs b/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-dev-transform/output.mjs index 437967648c3..e7616d191ca 100644 --- a/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-dev-transform/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-dev-transform/output.mjs @@ -1,14 +1,13 @@ import { jsxDEV as _jsxDEV, Fragment as _Fragment } from "react/jsx-dev-runtime"; -const App = _jsxDEV("div", { +const App = /*#__PURE__*/ _jsxDEV("div", { children: [ - _jsxDEV("div", { - }, void 0, false, { + /*#__PURE__*/ _jsxDEV("div", {}, void 0, false, { fileName: "input.js", lineNumber: 3, columnNumber: 9 }, this), - _jsxDEV(_Fragment, { - children: _jsxDEV("div", { + /*#__PURE__*/ _jsxDEV(_Fragment, { + children: /*#__PURE__*/ _jsxDEV("div", { children: "hoge" }, 1, false, { fileName: "input.js", @@ -21,4 +20,4 @@ const App = _jsxDEV("div", { fileName: "input.js", lineNumber: 2, columnNumber: 5 -}, this); \ No newline at end of file +}, this); diff --git a/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-transform/output.mjs b/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-transform/output.mjs index 131d1761b91..a83bb24093b 100644 --- a/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-transform/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/integration/fixture/jsx-transform/output.mjs @@ -1,12 +1,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; -const App = _jsxs("div", { +const App = /*#__PURE__*/ _jsxs("div", { children: [ - _jsx("div", { - }), - _jsx(_Fragment, { - children: _jsx("div", { + /*#__PURE__*/ _jsx("div", {}), + /*#__PURE__*/ _jsx(_Fragment, { + children: /*#__PURE__*/ _jsx("div", { children: "hoge" }, 1) }) ] -}); \ No newline at end of file +}); diff --git a/crates/swc_ecma_transforms_react/tests/integration/fixture/with-pragma/output.mjs b/crates/swc_ecma_transforms_react/tests/integration/fixture/with-pragma/output.mjs index 70a7b0630a2..5c573db33fc 100644 --- a/crates/swc_ecma_transforms_react/tests/integration/fixture/with-pragma/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/integration/fixture/with-pragma/output.mjs @@ -1,14 +1,13 @@ import { jsxDEV as _jsxDEV, Fragment as _Fragment } from "react/jsx-dev-runtime"; -const App = _jsxDEV("div", { +/**@jsxRuntime automatic */ const App = /*#__PURE__*/ _jsxDEV("div", { children: [ - _jsxDEV("div", { - }, void 0, false, { + /*#__PURE__*/ _jsxDEV("div", {}, void 0, false, { fileName: "input.js", lineNumber: 4, columnNumber: 9 }, this), - _jsxDEV(_Fragment, { - children: _jsxDEV("div", { + /*#__PURE__*/ _jsxDEV(_Fragment, { + children: /*#__PURE__*/ _jsxDEV("div", { children: "hoge" }, void 0, false, { fileName: "input.js", @@ -21,4 +20,4 @@ const App = _jsxDEV("div", { fileName: "input.js", lineNumber: 3, columnNumber: 5 -}, this); \ No newline at end of file +}, this); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/complicated-scope-module/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/complicated-scope-module/output.mjs index 8aa70983ae7..35dcda8ccca 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/complicated-scope-module/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/complicated-scope-module/output.mjs @@ -8,12 +8,10 @@ const Bar = ()=>{ var c = _react5(); var jsx = 1; var _jsx1 = 2; - return _jsx("div", { - }); + return(/*#__PURE__*/ _jsx("div", {})); } ; - return _jsx("span", { - }); + return(/*#__PURE__*/ _jsx("span", {})); }; }; }; diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source-pragma/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source-pragma/output.mjs index 0049c235923..d8918853cd5 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source-pragma/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source-pragma/output.mjs @@ -1,6 +1,4 @@ import { jsx as _jsx } from "baz/jsx-runtime"; - -/** @jsxImportSource baz */ -var x = _jsx("div", { - children: _jsx("span", {}) +/** @jsxImportSource baz */ var x = /*#__PURE__*/ _jsx("div", { + children: /*#__PURE__*/ _jsx("span", {}) }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source/output.mjs index 05dafe98f54..0467f1aef2e 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/import-source/output.mjs @@ -1,5 +1,4 @@ import { jsx as _jsx } from "foo/jsx-runtime"; - -var x = _jsx("div", { - children: _jsx("span", {}) +var x = /*#__PURE__*/ _jsx("div", { + children: /*#__PURE__*/ _jsx("span", {}) }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/react-defined/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/react-defined/output.mjs index 3af4950ef64..9e20184aba0 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/react-defined/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/autoImport/react-defined/output.mjs @@ -1,19 +1,17 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { createElement as _createElement } from "react"; import * as react from "react"; -var y = react.createElement("div", { +var y = /*#__PURE__*/ react.createElement("div", { foo: 1 }); -var x = _jsxs("div", { +var x = /*#__PURE__*/ _jsxs("div", { children: [ - _jsx("div", { - }, "1"), - _jsx("div", { + /*#__PURE__*/ _jsx("div", {}, "1"), + /*#__PURE__*/ _jsx("div", { meow: "wolf" }, "2"), - _jsx("div", { - }, "3"), - _createElement("div", { + /*#__PURE__*/ _jsx("div", {}, "3"), + /*#__PURE__*/ _createElement("div", { ...props, key: "4" }) diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/cmt/1/input.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/cmt/1/input.js new file mode 100644 index 00000000000..92bd07d7bbf --- /dev/null +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/cmt/1/input.js @@ -0,0 +1,2 @@ +import React from 'react'; +React.createElement('div'); \ No newline at end of file diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/cmt/1/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/cmt/1/output.mjs new file mode 100644 index 00000000000..8dcaa0ad246 --- /dev/null +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/cmt/1/output.mjs @@ -0,0 +1,2 @@ +import React from "react"; +/*#__PURE__*/ React.createElement("div"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1446/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1446/output.mjs index b25161ea4a4..fcab1c6049b 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1446/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1446/output.mjs @@ -1 +1 @@ -React.createElement(React.Fragment, null, React.createElement("span", null, "Hello something long to not trigger line break"), "\xa0"); +/*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("span", null, "Hello something long to not trigger line break"), "\xa0"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1799/case1/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1799/case1/output.mjs index 3657fb2be44..1805ccf4ae6 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1799/case1/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-1799/case1/output.mjs @@ -1,9 +1,10 @@ +// Foo.jsx import React from "react"; export default function Foo() { - return React.createElement("div", { + return(/*#__PURE__*/ React.createElement("div", { onClick: async (e)=>{ await doSomething(); } - }); + })); }; Foo.displayName = "Foo"; diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-2177/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-2177/output.mjs index fe9ea7307bf..4b277cab11b 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-2177/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-2177/output.mjs @@ -1,8 +1,8 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; export var App = function() { - return _jsx(_Fragment, { - children: _jsx("div", { + return(/*#__PURE__*/ _jsx(_Fragment, { + children: /*#__PURE__*/ _jsx("div", { children: "1" }) - }); + })); }; diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/1/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/1/output.mjs index 904444a8d54..0d0c9a12355 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/1/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/1/output.mjs @@ -1,3 +1,3 @@ -React.createElement(Page, { +/*#__PURE__*/ React.createElement(Page, { num: "\\\\ " }, "ABC"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/2/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/2/output.mjs index 8eebeec6799..def25207364 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/2/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/issue-299/2/output.mjs @@ -1,3 +1,3 @@ -React.createElement(Page, { +/*#__PURE__*/ React.createElement(Page, { num: "\\\\\\\\" }, "ABC"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-default-pragma-classic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-default-pragma-classic-runtime/output.js index 3cd05d5f9f2..33ec0c22bfb 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-default-pragma-classic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-default-pragma-classic-runtime/output.js @@ -1 +1 @@ -React.createElement("div", null); +/*#__PURE__*/ React.createElement("div", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-automatic-runtime/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-automatic-runtime/output.mjs index e93ee3babc6..9a39be3a3fb 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-automatic-runtime/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-automatic-runtime/output.mjs @@ -1,3 +1,2 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx("div", { -}); +/* @jsx h */ /*#__PURE__*/ _jsx("div", {}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-classic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-classic-runtime/output.js index 6dc3b55a8a6..3de125177e1 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-classic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-comment-classic-runtime/output.js @@ -1,2 +1 @@ -/* @jsx h */ -h("div", null); +/* @jsx h */ /*#__PURE__*/ h("div", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-option-classic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-option-classic-runtime/output.js index 5b745cd1b86..3ef169ffe17 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-option-classic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/false-pragma-option-classic-runtime/output.js @@ -1 +1 @@ -h("div", null); +/*#__PURE__*/ h("div", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-default-pragma-automatic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-default-pragma-automatic-runtime/output.js index e93ee3babc6..38170f4525c 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-default-pragma-automatic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-default-pragma-automatic-runtime/output.js @@ -1,3 +1,2 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx("div", { -}); +/*#__PURE__*/ _jsx("div", {}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-pragma-comment-automatic-runtime/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-pragma-comment-automatic-runtime/output.mjs index e93ee3babc6..9a39be3a3fb 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-pragma-comment-automatic-runtime/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/true-pragma-comment-automatic-runtime/output.mjs @@ -1,3 +1,2 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx("div", { -}); +/* @jsx h */ /*#__PURE__*/ _jsx("div", {}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-default-pragma-automatic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-default-pragma-automatic-runtime/output.js index e93ee3babc6..38170f4525c 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-default-pragma-automatic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-default-pragma-automatic-runtime/output.js @@ -1,3 +1,2 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx("div", { -}); +/*#__PURE__*/ _jsx("div", {}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-automatic-runtime/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-automatic-runtime/output.mjs index e93ee3babc6..9a39be3a3fb 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-automatic-runtime/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-automatic-runtime/output.mjs @@ -1,3 +1,2 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx("div", { -}); +/* @jsx h */ /*#__PURE__*/ _jsx("div", {}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-classic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-classic-runtime/output.js index 6dc3b55a8a6..3de125177e1 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-classic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-comment-classic-runtime/output.js @@ -1,2 +1 @@ -/* @jsx h */ -h("div", null); +/* @jsx h */ /*#__PURE__*/ h("div", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-option-classic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-option-classic-runtime/output.js index 5b745cd1b86..3ef169ffe17 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-option-classic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/pure/unset-pragma-option-classic-runtime/output.js @@ -1 +1 @@ -h("div", null); +/*#__PURE__*/ h("div", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/adds-appropriate-newlines-when-using-spread-attribute/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/adds-appropriate-newlines-when-using-spread-attribute/output.mjs index dda0abe4fb9..2c17d2341bb 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/adds-appropriate-newlines-when-using-spread-attribute/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/adds-appropriate-newlines-when-using-spread-attribute/output.mjs @@ -1,5 +1,5 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx(Component, { +/*#__PURE__*/ _jsx(Component, { ...props, sound: "moo" }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/assignment/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/assignment/output.mjs index 1819ffb3b36..77317bd836f 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/assignment/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/assignment/output.mjs @@ -1,5 +1,5 @@ import { jsx as _jsx } from "react/jsx-runtime"; -var div = _jsx(Component, { +var div = /*#__PURE__*/ _jsx(Component, { ...props, foo: "bar" }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/concatenates-adjacent-string-literals/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/concatenates-adjacent-string-literals/output.mjs index 75eb66eca69..c6d88fbcc21 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/concatenates-adjacent-string-literals/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/concatenates-adjacent-string-literals/output.mjs @@ -1,10 +1,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; -var x = _jsxs("div", { +var x = /*#__PURE__*/ _jsxs("div", { children: [ "foo", "bar", "baz", - _jsx("div", { + /*#__PURE__*/ _jsx("div", { children: "buz bang" }), "qux", diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/dont-coerce-expression-containers/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/dont-coerce-expression-containers/output.mjs index a90dd947316..a7ee82fc5c6 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/dont-coerce-expression-containers/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/dont-coerce-expression-containers/output.mjs @@ -1,5 +1,5 @@ import { jsxs as _jsxs } from "react/jsx-runtime"; -_jsxs(Text, { +/*#__PURE__*/ _jsxs(Text, { children: [ "To get started, edit index.ios.js!!!", "\n", diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-key/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-key/output.mjs index de660254616..da486b95a3c 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-key/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-key/output.mjs @@ -1,4 +1,3 @@ import { jsx as _jsx } from "react/jsx-runtime"; import * as React from "react"; -var x = _jsx(React.Fragment, { -}, "foo"); +var x = /*#__PURE__*/ _jsx(React.Fragment, {}, "foo"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-no-children/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-no-children/output.mjs index 34e75ad17bf..fe95523260c 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-no-children/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments-with-no-children/output.mjs @@ -1,3 +1,2 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; -var x = _jsx(_Fragment, { -}); +var x = /*#__PURE__*/ _jsx(_Fragment, {}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments/output.mjs index 2cf656ff50e..cd61417ff6e 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-fragments/output.mjs @@ -1,5 +1,4 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime"; -var x = _jsx(_Fragment, { - children: _jsx("div", { - }) +var x = /*#__PURE__*/ _jsx(_Fragment, { + children: /*#__PURE__*/ _jsx("div", {}) }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-static-children/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-static-children/output.mjs index 8d312c416fb..3858d2129f4 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-static-children/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/handle-static-children/output.mjs @@ -1,13 +1,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; -var x = _jsxs("div", { +var x = /*#__PURE__*/ _jsxs("div", { children: [ - _jsx("span", { - }), + /*#__PURE__*/ _jsx("span", {}), [ - _jsx("span", { - }, "0"), - _jsx("span", { - }, "1") + /*#__PURE__*/ _jsx("span", {}, "0"), + /*#__PURE__*/ _jsx("span", {}, "1") ] ] }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/pragma-works-with-no-space-at-the-end/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/pragma-works-with-no-space-at-the-end/output.mjs index 7f8eea819da..65ac7812c26 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/pragma-works-with-no-space-at-the-end/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/pragma-works-with-no-space-at-the-end/output.mjs @@ -1,6 +1,4 @@ import { jsx as _jsx } from "foo/jsx-runtime"; - -/* @jsxImportSource foo*/ -_jsx("div", { - children: "Hi" +/* @jsxImportSource foo*/ /*#__PURE__*/ _jsx("div", { + children: "Hi" }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-spread-children/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-spread-children/output.mjs index 3cd05d5f9f2..33ec0c22bfb 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-spread-children/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-spread-children/output.mjs @@ -1 +1 @@ -React.createElement("div", null); +/*#__PURE__*/ React.createElement("div", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-xml-namespacing/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-xml-namespacing/output.mjs index 9df43c229dc..555ef8ee0d1 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-xml-namespacing/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-disallow-xml-namespacing/output.mjs @@ -1 +1 @@ -React.createElement("Namespace:Component", null); +/*#__PURE__*/ React.createElement("Namespace:Component", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxattribute/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxattribute/output.mjs index f92c390aa11..f1b001816a6 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxattribute/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxattribute/output.mjs @@ -1,10 +1,10 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx("div", { +/*#__PURE__*/ _jsx("div", { id: "w\xf4w" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { id: "\\w" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { id: "w < w" }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxtext/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxtext/output.mjs index ee681cec070..c196394fea4 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxtext/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-escape-xhtml-jsxtext/output.mjs @@ -1,31 +1,31 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "wow" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "w\xf4w" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "w & w" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "w & w" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "w \xa0 w" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "this should not parse as unicode: \\u00a0" }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "this should parse as nbsp: \xa0 " }); -_jsxs("div", { +/*#__PURE__*/ _jsxs("div", { children: [ "this should parse as unicode: ", "\xa0\xa0" ] }); -_jsx("div", { +/*#__PURE__*/ _jsx("div", { children: "w < w" }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-properly-handle-comments-between-props/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-properly-handle-comments-between-props/output.mjs index 7b0923e0964..132c7fc7540 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-properly-handle-comments-between-props/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-properly-handle-comments-between-props/output.mjs @@ -1,11 +1,9 @@ import { jsx as _jsx } from "react/jsx-runtime"; - -var x = /*#__PURE__*/_jsx("div", { - /* a multi-line - comment */ - attr1: "foo", - children: /*#__PURE__*/_jsx("span", { - // a double-slash comment - attr2: "bar" - }) +var x = /*#__PURE__*/ _jsx("div", { + /* a multi-line + comment */ attr1: "foo", + children: /*#__PURE__*/ _jsx("span" // a double-slash comment + , { + attr2: "bar" + }) }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-throw-error-namespaces-if-not-flag/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-throw-error-namespaces-if-not-flag/output.mjs index a6e5deaac61..6ef920b087a 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-throw-error-namespaces-if-not-flag/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/should-throw-error-namespaces-if-not-flag/output.mjs @@ -1,3 +1,2 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx("f:image", { -}); +/*#__PURE__*/ _jsx("f:image", {}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/wraps-props-in-react-spread-for-middle-spread-attributes/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/wraps-props-in-react-spread-for-middle-spread-attributes/output.mjs index d12860cb8f1..356437d5415 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/wraps-props-in-react-spread-for-middle-spread-attributes/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react-automatic/wraps-props-in-react-spread-for-middle-spread-attributes/output.mjs @@ -1,5 +1,5 @@ import { jsx as _jsx } from "react/jsx-runtime"; -_jsx(Component, { +/*#__PURE__*/ _jsx(Component, { y: 2, ...x, z: true diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment-if-jsx-pragma-option-set/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment-if-jsx-pragma-option-set/output.js index 1e933b06807..19393033e6d 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment-if-jsx-pragma-option-set/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment-if-jsx-pragma-option-set/output.js @@ -1,6 +1,8 @@ -/** @jsx dom */ -dom(Foo, null); -var profile = dom("div", null, dom("img", { - src: "avatar.png", - className: "profile" -}), dom("h3", null, [user.firstName, user.lastName].join(" "))); +/** @jsx dom */ /*#__PURE__*/ dom(Foo, null); +var profile = /*#__PURE__*/ dom("div", null, /*#__PURE__*/ dom("img", { + src: "avatar.png", + className: "profile" +}), /*#__PURE__*/ dom("h3", null, [ + user.firstName, + user.lastName +].join(" "))); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment/output.js index 1e933b06807..19393033e6d 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-comment/output.js @@ -1,6 +1,8 @@ -/** @jsx dom */ -dom(Foo, null); -var profile = dom("div", null, dom("img", { - src: "avatar.png", - className: "profile" -}), dom("h3", null, [user.firstName, user.lastName].join(" "))); +/** @jsx dom */ /*#__PURE__*/ dom(Foo, null); +var profile = /*#__PURE__*/ dom("div", null, /*#__PURE__*/ dom("img", { + src: "avatar.png", + className: "profile" +}), /*#__PURE__*/ dom("h3", null, [ + user.firstName, + user.lastName +].join(" "))); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-pragma-option/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-pragma-option/output.js index f74131189c0..f1c6d818050 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-pragma-option/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/honor-custom-jsx-pragma-option/output.js @@ -1,5 +1,8 @@ -dom(Foo, null); -var profile = dom("div", null, dom("img", { - src: "avatar.png", - className: "profile" -}), dom("h3", null, [user.firstName, user.lastName].join(" "))); +/*#__PURE__*/ dom(Foo, null); +var profile = /*#__PURE__*/ dom("div", null, /*#__PURE__*/ dom("img", { + src: "avatar.png", + className: "profile" +}), /*#__PURE__*/ dom("h3", null, [ + user.firstName, + user.lastName +].join(" "))); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/pragma-works-with-no-space-at-the-end/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/pragma-works-with-no-space-at-the-end/output.js index 31b6fe25a48..769dfa2f675 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/pragma-works-with-no-space-at-the-end/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/pragma-works-with-no-space-at-the-end/output.js @@ -1,2 +1 @@ -/* @jsx foo*/ -foo("div", null, "Hi"); +/* @jsx foo*/ /*#__PURE__*/ foo("div", null, "Hi"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-multiple-pragmas-per-line/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-multiple-pragmas-per-line/output.js index 60c731b4ffa..43538ef2560 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-multiple-pragmas-per-line/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-multiple-pragmas-per-line/output.js @@ -1,5 +1,4 @@ -/* @jsxRuntime automatic @jsxImportSource react */ import { jsx as _jsx } from "preact/jsx-runtime"; -var div = _jsx("div", { +/* @jsxRuntime automatic @jsxImportSource preact */ var div = /*#__PURE__*/ _jsx("div", { children: "test" -}); \ No newline at end of file +}); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-no-pragmafrag-if-frag-unused/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-no-pragmafrag-if-frag-unused/output.js index bac7ff4042d..b63e7dfa531 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-no-pragmafrag-if-frag-unused/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-no-pragmafrag-if-frag-unused/output.js @@ -1,2 +1 @@ -/** @jsx dom */ -dom("div", null, "no fragment is used"); +/** @jsx dom */ /*#__PURE__*/ dom("div", null, "no fragment is used"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-pragmafrag-and-frag/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-pragmafrag-and-frag/output.js index d5a2a9bac23..3efc0a3ae3b 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-pragmafrag-and-frag/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-allow-pragmafrag-and-frag/output.js @@ -1,4 +1 @@ -/** @jsx dom */ - -/** @jsxFrag DomFrag */ -dom(DomFrag, null); +/** @jsx dom */ /** @jsxFrag DomFrag */ /*#__PURE__*/ dom(DomFrag, null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-spread-children/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-spread-children/output.mjs index 3cd05d5f9f2..33ec0c22bfb 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-spread-children/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-spread-children/output.mjs @@ -1 +1 @@ -React.createElement("div", null); +/*#__PURE__*/ React.createElement("div", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-xml-namespacing/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-xml-namespacing/output.mjs index 9df43c229dc..555ef8ee0d1 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-xml-namespacing/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-disallow-xml-namespacing/output.mjs @@ -1 +1 @@ -React.createElement("Namespace:Component", null); +/*#__PURE__*/ React.createElement("Namespace:Component", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-escape-xhtml-jsxattribute-babel-7/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-escape-xhtml-jsxattribute-babel-7/output.js index ce62cc76d08..70070ae84ac 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-escape-xhtml-jsxattribute-babel-7/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-escape-xhtml-jsxattribute-babel-7/output.js @@ -1,9 +1,9 @@ -React.createElement("div", { +/*#__PURE__*/ React.createElement("div", { id: "w\xf4w" }); -React.createElement("div", { +/*#__PURE__*/ React.createElement("div", { id: "\\w" }); -React.createElement("div", { +/*#__PURE__*/ React.createElement("div", { id: "w < w" }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-handle-attributed-elements/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-handle-attributed-elements/output.js index e958d0cd577..c2a155451f2 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-handle-attributed-elements/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-handle-attributed-elements/output.js @@ -1,9 +1,9 @@ var HelloMessage = React.createClass({ render: function() { - return React.createElement("div", null, "Hello ", this.props.name); + return(/*#__PURE__*/ React.createElement("div", null, "Hello ", this.props.name)); }, displayName: "HelloMessage" }); -React.render(React.createElement(HelloMessage, { - name: React.createElement("span", null, "Sebastian") +React.render(/*#__PURE__*/ React.createElement(HelloMessage, { + name: /*#__PURE__*/ React.createElement("span", null, "Sebastian") }), mountNode); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-properly-handle-comments-between-props/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-properly-handle-comments-between-props/output.js index fbe9b6dd684..7984167df4e 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-properly-handle-comments-between-props/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-properly-handle-comments-between-props/output.js @@ -1,8 +1,7 @@ -var x = /*#__PURE__*/React.createElement("div", { - /* a multi-line - comment */ - attr1: "foo" -}, /*#__PURE__*/React.createElement("span", { - // a double-slash comment - attr2: "bar" +var x = /*#__PURE__*/ React.createElement("div", { + /* a multi-line + comment */ attr1: "foo" +}, /*#__PURE__*/ React.createElement("span" // a double-slash comment +, { + attr2: "bar" })); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-support-xml-namespaces-if-flag/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-support-xml-namespaces-if-flag/output.js index 24a57b8f231..b7102d11f7c 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-support-xml-namespaces-if-flag/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-support-xml-namespaces-if-flag/output.js @@ -1,3 +1,3 @@ -h("f:image", { - "n:attr": true +/*#__PURE__*/ h("f:image", { + "n:attr": true }); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-throw-error-namespaces-if-not-flag/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-throw-error-namespaces-if-not-flag/output.mjs index 84038ebb972..f06979a2081 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-throw-error-namespaces-if-not-flag/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/react/should-throw-error-namespaces-if-not-flag/output.mjs @@ -1 +1 @@ -h("f:image", null); +/*#__PURE__*/ h("f:image", null); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/regression/pragma-frag-set-default-classic-runtime/output.js b/crates/swc_ecma_transforms_react/tests/jsx/fixture/regression/pragma-frag-set-default-classic-runtime/output.js index 8a621e8a457..86fbfba0b66 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/regression/pragma-frag-set-default-classic-runtime/output.js +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/regression/pragma-frag-set-default-classic-runtime/output.js @@ -1,4 +1 @@ -/* @jsxFrag React.Fragment */ - -/* @jsx h */ -h(React.Fragment, null, "Test"); +/* @jsxFrag React.Fragment */ /* @jsx h */ /*#__PURE__*/ h(React.Fragment, null, "Test"); diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/1/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/1/output.mjs index 7e6b1788355..6d260ba40c4 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/1/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/1/output.mjs @@ -1,4 +1,4 @@ -export default React.createElement(A, { +export default /*#__PURE__*/ React.createElement(A, { className: b, header: "C", subheader: "D E" diff --git a/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/2/output.mjs b/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/2/output.mjs index fe965c5bfe3..a72cb884542 100644 --- a/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/2/output.mjs +++ b/crates/swc_ecma_transforms_react/tests/jsx/fixture/vercel/2/output.mjs @@ -1,5 +1,5 @@ export default (()=>{ - return React.createElement(Input, { + return(/*#__PURE__*/ React.createElement(Input, { pattern: ".*\\S+.*" - }); + })); }); diff --git a/crates/swc_ecma_transforms_testing/src/lib.rs b/crates/swc_ecma_transforms_testing/src/lib.rs index 4a903c2e598..168a1b8a140 100644 --- a/crates/swc_ecma_transforms_testing/src/lib.rs +++ b/crates/swc_ecma_transforms_testing/src/lib.rs @@ -1,4 +1,6 @@ #![deny(clippy::all)] +#![deny(clippy::all)] +#![deny(unused)] #![allow(clippy::result_unit_err)] use std::{ @@ -31,8 +33,9 @@ use swc_ecma_transforms_base::{ fixer, helpers::{inject_helpers, HELPERS}, hygiene, + pass::noop, }; -use swc_ecma_utils::{quote_ident, quote_str, DropSpan, ExprFactory}; +use swc_ecma_utils::{quote_ident, quote_str, ExprFactory}; use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, FoldWith, VisitMut, VisitMutWith}; use tempfile::tempdir_in; use testing::{assert_eq, find_executable, NormalizedOutput}; @@ -164,9 +167,6 @@ impl<'a> Tester<'a> { let module = module .fold_with(&mut tr) - .fold_with(&mut as_folder(DropSpan { - preserve_ctxt: true, - })) .fold_with(&mut as_folder(Normalizer)); Ok(module) @@ -289,6 +289,9 @@ pub fn test_transform( } let actual = actual + .fold_with(&mut as_folder(::swc_ecma_utils::DropSpan { + preserve_ctxt: true, + })) .fold_with(&mut hygiene::hygiene()) .fold_with(&mut fixer::fixer(Some(&tester.comments))); @@ -682,14 +685,7 @@ fn test_fixture_inner

( let expected = expected.unwrap_or_default(); let expected_src = Tester::run(|tester| { - let expected_module = tester.apply_transform( - as_folder(::swc_ecma_utils::DropSpan { - preserve_ctxt: true, - }), - "expected.js", - syntax, - &expected, - )?; + let expected_module = tester.apply_transform(noop(), "expected.js", syntax, &expected)?; let expected_src = tester.print(&expected_module, &tester.comments.clone()); @@ -730,10 +726,7 @@ fn test_fixture_inner

( let actual = actual .fold_with(&mut crate::hygiene::hygiene()) - .fold_with(&mut crate::fixer::fixer(Some(&tester.comments))) - .fold_with(&mut as_folder(DropSpan { - preserve_ctxt: false, - })); + .fold_with(&mut crate::fixer::fixer(Some(&tester.comments))); let actual_src = tester.print(&actual, &tester.comments.clone()); diff --git a/crates/swc_ecma_transforms_typescript/tests/fixture/issue-3001/2/output.js b/crates/swc_ecma_transforms_typescript/tests/fixture/issue-3001/2/output.js index ae4458f6b6e..57ec067166d 100644 --- a/crates/swc_ecma_transforms_typescript/tests/fixture/issue-3001/2/output.js +++ b/crates/swc_ecma_transforms_typescript/tests/fixture/issue-3001/2/output.js @@ -5,20 +5,18 @@ var Foo; Foo[Foo["b"] = 10] = "b"; Foo[Foo["c"] = Foo.b + x] = "c"; Foo[Foo["d"] = Foo.c] = "d"; -})(Foo || (Foo = { -})); +})(Foo || (Foo = {})); var Bar; (function(Bar) { Bar[Bar["a"] = 1] = "a"; Bar[Bar["b"] = Foo.a] = "b"; Bar[Bar["E"] = Bar.b] = "E"; Bar[Bar["F"] = Math.E] = "F"; -})(Bar || (Bar = { -})); +})(Bar || (Bar = {})); var Baz; (function(Baz) { Baz[Baz["a"] = 0] = "a"; Baz[Baz["b"] = 1] = "b"; - Baz[Baz["x"] = Baz.a.toString()] = "x"; -})(Baz || (Baz = { -})); + Baz[Baz[// @ts-ignore + "x"] = Baz.a.toString()] = "x"; +})(Baz || (Baz = {})); diff --git a/crates/swc_ecma_transforms_typescript/tests/fixture/next/server/render/1/output.js b/crates/swc_ecma_transforms_typescript/tests/fixture/next/server/render/1/output.js index 689f63a2543..9e5b4c17578 100644 --- a/crates/swc_ecma_transforms_typescript/tests/fixture/next/server/render/1/output.js +++ b/crates/swc_ecma_transforms_typescript/tests/fixture/next/server/render/1/output.js @@ -63,6 +63,7 @@ class ServerRouter { } } function enhanceComponents(options, App, Component) { + // For backwards compatibility if (typeof options === "function") { return { App, @@ -88,7 +89,7 @@ function checkRedirectValues(redirect, req, method) { errors.push(`\`permanent\` must be \`true\` or \`false\``); } else if (hasStatusCode && !allowedStatusCodes.has(statusCode)) { errors.push(`\`statusCode\` must undefined or one of ${[ - ...allowedStatusCodes + ...allowedStatusCodes, ].join(", ")}`); } const destinationType = typeof destination; @@ -104,9 +105,13 @@ function checkRedirectValues(redirect, req, method) { } } export async function renderToHTML(req, res, pathname, query, renderOpts) { + // In dev we invalidate the cache by appending a timestamp to the resource URL. + // This is a workaround to fix https://github.com/vercel/next.js/issues/5860 + // TODO: remove this workaround when https://bugs.webkit.org/show_bug.cgi?id=187726 is fixed. renderOpts.devOnlyCacheBusterQueryString = renderOpts.dev ? renderOpts.devOnlyCacheBusterQueryString || `?ts=${Date.now()}` : ""; + // don't modify original query object query = Object.assign({}, query); - const { err , dev =false , ampPath ="" , App , Document , pageConfig ={} , Component , buildManifest , fontManifest , reactLoadableManifest , ErrorDebug , getStaticProps , getStaticPaths , getServerSideProps , isDataReq , params , previewProps , basePath , devOnlyCacheBusterQueryString , supportsDynamicHTML , concurrentFeatures } = renderOpts; + const { err , dev =false , ampPath ="" , App , Document , pageConfig ={} , Component , buildManifest , fontManifest , reactLoadableManifest , ErrorDebug , getStaticProps , getStaticPaths , getServerSideProps , isDataReq , params , previewProps , basePath , devOnlyCacheBusterQueryString , supportsDynamicHTML , concurrentFeatures , } = renderOpts; const getFontDefinition = (url)=>{ if (fontManifest) { return getFontDefinitionFromManifest(url, fontManifest); @@ -147,7 +152,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { for (const methodName of [ "getStaticProps", "getServerSideProps", - "getStaticPaths" + "getStaticPaths", ]){ if (Component[methodName]) { throw new Error(`page ${pathname} ${methodName} ${GSSP_COMPONENT_MEMBER_ERROR}`); @@ -184,12 +189,14 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { throw new Error(`The default export is not a React Component in page: "/_document"`); } if (isAutoExport || isFallback) { + // remove query values except ones that will be set during export query = { ...query.amp ? { amp: query.amp } : {} }; - asPath = `${pathname}${req.url.endsWith("/") && pathname !== "/" && !pageIsDynamic ? "/" : ""}`; + asPath = `${pathname}${// ensure trailing slash is present for non-dynamic auto-export pages + req.url.endsWith("/") && pathname !== "/" && !pageIsDynamic ? "/" : ""}`; req.url = pathname; } if (pathname === "/404" && (hasPageGetInitialProps || getServerSideProps)) { @@ -199,13 +206,17 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { throw new Error(`\`pages${pathname}\` ${STATIC_STATUS_PAGE_GET_INITIAL_PROPS_ERROR}`); } } - await Loadable.preloadAll(); + await Loadable.preloadAll(); // Make sure all dynamic imports are loaded let isPreview; let previewData; if ((isSSG || getServerSideProps) && !isFallback) { + // Reads of this are cached on the `req` object, so this should resolve + // instantly. There's no need to pass this data down from a previous + // invoke, where we'd have to consider server & serverless. previewData = tryGetPreviewData(req, res, previewProps); isPreview = previewData !== false; } + // url will always be set const routerIsReady = !!(getServerSideProps || hasPageGetInitialProps || !defaultAppGetInitialProps && !isSSG); const router = new ServerRouter(pathname, query, asPath, { isFallback: isFallback @@ -315,6 +326,8 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { defaultLocale: renderOpts.defaultLocale }); } catch (staticPropsError) { + // remove not found error code to prevent triggering legacy + // 404 rendering if (staticPropsError && staticPropsError.code === "ENOENT") { delete staticPropsError.code; } @@ -357,6 +370,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { renderOpts.isRedirect = true; } if ((dev || isBuildTimeSSG) && !renderOpts.isNotFound && !isSerializableProps(pathname, "getStaticProps", data.props)) { + // this fn should throw an error instead of ever returning `false` throw new Error("invariant: getStaticProps did not return valid props. Please report this."); } if ("revalidate" in data) { @@ -366,21 +380,30 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { } else if (data.revalidate <= 0) { throw new Error(`A page's revalidate option can not be less than or equal to zero for ${req.url}. A revalidate option of zero means to revalidate after _every_ request, and implies stale data cannot be tolerated.` + `\n\nTo never revalidate, you can set revalidate to \`false\` (only ran once at build-time).` + `\nTo revalidate as soon as possible, you can set the value to \`1\`.`); } else if (data.revalidate > 31536000) { + // if it's greater than a year for some reason error console.warn(`Warning: A page's revalidate option was set to more than a year for ${req.url}. This may have been done in error.` + `\nTo only run getStaticProps at build-time and not revalidate at runtime, you can set \`revalidate\` to \`false\`!`); } } else if (data.revalidate === true) { + // When enabled, revalidate after 1 second. This value is optimal for + // the most up-to-date page possible, but without a 1-to-1 + // request-refresh ratio. data.revalidate = 1; } else if (data.revalidate === false || typeof data.revalidate === "undefined") { + // By default, we never revalidate. data.revalidate = false; } else { throw new Error(`A page's revalidate option must be seconds expressed as a natural number. Mixed numbers and strings cannot be used. Received '${JSON.stringify(data.revalidate)}' for ${req.url}`); } } else { - data.revalidate = false; + // By default, we never revalidate. + (data).revalidate = false; } props1.pageProps = Object.assign({}, props1.pageProps, "props" in data ? data.props : undefined); - renderOpts.revalidate = "revalidate" in data ? data.revalidate : undefined; + // pass up revalidate and props for export + // TODO: change this to a different passing mechanism + (renderOpts).revalidate = "revalidate" in data ? data.revalidate : undefined; renderOpts.pageData = props1; + // this must come after revalidate is added to renderOpts if (renderOpts.isNotFound) { return null; } @@ -421,6 +444,8 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { }); canAccessRes = false; } catch (serverSidePropsError) { + // remove not found error code to prevent triggering legacy + // 404 rendering if (isError(serverSidePropsError) && serverSidePropsError.code === "ENOENT") { delete serverSidePropsError.code; } @@ -462,6 +487,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { data.props = await data.props; } if ((dev || isBuildTimeSSG) && !isSerializableProps(pathname, "getServerSideProps", data.props)) { + // this fn should throw an error instead of ever returning `false` throw new Error("invariant: getServerSideProps did not return valid props. Please report this."); } props1.pageProps = Object.assign({}, props1.pageProps, data.props); @@ -470,16 +496,26 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { if (!isSSG && !getServerSideProps && process.env.NODE_ENV !== "production" && Object.keys(props1?.pageProps || {}).includes("url")) { console.warn(`The prop \`url\` is a reserved prop in Next.js for legacy reasons and will be overridden on page ${pathname}\n` + `See more info here: https://nextjs.org/docs/messages/reserved-page-prop`); } + // Avoid rendering page un-necessarily for getServerSideProps data request + // and getServerSideProps/getStaticProps redirects if (isDataReq && !isSSG || renderOpts.isRedirect) { return RenderResult.fromStatic(JSON.stringify(props1)); } + // We don't call getStaticProps or getServerSideProps while generating + // the fallback so make sure to set pageProps to an empty object if (isFallback) { props1.pageProps = {}; } + // the response might be finished on the getInitialProps call if (isResSent(res) && !isSSG) return null; + // we preload the buildManifest for auto-export dynamic pages + // to speed up hydrating query values let filteredBuildManifest = buildManifest; if (isAutoExport && pageIsDynamic) { const page = denormalizePagePath(normalizePagePath(pathname)); + // This code would be much cleaner using `immer` and directly pushing into + // the result from `getPageFiles`, we could maybe consider that in the + // future. if (page in filteredBuildManifest.pages) { filteredBuildManifest = { ...filteredBuildManifest, @@ -488,7 +524,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { [page]: [ ...filteredBuildManifest.pages[page], ...filteredBuildManifest.lowPriorityFiles.filter((f)=>f.includes("_buildManifest") - ) + ), ] }, lowPriorityFiles: filteredBuildManifest.lowPriorityFiles.filter((f)=>!f.includes("_buildManifest") @@ -496,7 +532,19 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { }; } } - const generateStaticHTML = supportsDynamicHTML !== true; + /** + * Rules of Static & Dynamic HTML: + * + * 1.) We must generate static HTML unless the caller explicitly opts + * in to dynamic HTML support. + * + * 2.) If dynamic HTML support is requested, we must honor that request + * or throw an error. It is the sole responsibility of the caller to + * ensure they aren't e.g. requesting dynamic HTML for an AMP page. + * + * These rules help ensure that other existing features like request caching, + * coalescing, and ISR continue working as intended. + */ const generateStaticHTML = supportsDynamicHTML !== true; const renderDocument = async ()=>{ if (Document.getInitialProps) { const renderPage = (options = {})=>{ @@ -526,6 +574,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { renderPage }; const docProps = await loadGetInitialProps(Document, documentCtx); + // the response might be finished on the getInitialProps call if (isResSent(res) && !isSSG) return null; if (!docProps || typeof docProps.html !== "string") { const message = `"${getDisplayName(Document)}.getInitialProps()" should resolve to an object with a "html" prop set with a valid html string`; @@ -577,7 +626,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { } const hybridAmp = ampState.hybrid; const docComponentsRendered = {}; - const { assetPrefix , buildId , customServer , defaultLocale , disableOptimizedLoading , domainLocales , locale , locales , runtimeConfig } = renderOpts; + const { assetPrefix , buildId , customServer , defaultLocale , disableOptimizedLoading , domainLocales , locale , locales , runtimeConfig , } = renderOpts; const htmlProps1 = { __NEXT_DATA__: { props: props1, @@ -612,6 +661,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { hybridAmp, dynamicImports: Array.from(dynamicImports), assetPrefix, + // Only enabled in production as development mode has features relying on HMR (style injection for example) unstable_runtimeJS: process.env.NODE_ENV === "production" ? pageConfig.unstable_runtimeJS : undefined, unstable_JsPreload: pageConfig.unstable_JsPreload, devOnlyCacheBusterQueryString, @@ -663,8 +713,8 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { piperFromArray(prefix), documentResult.bodyResult, piperFromArray([ - documentHTML.substring(renderTargetIdx + BODY_RENDER_TARGET.length) - ]) + documentHTML.substring(renderTargetIdx + BODY_RENDER_TARGET.length), + ]), ]; const postProcessors = (generateStaticHTML ? [ inAmpMode ? async (html)=>{ @@ -683,6 +733,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { }); } : null, renderOpts.optimizeCss ? async (html)=>{ + // eslint-disable-next-line import/no-extraneous-dependencies const Critters = require("critters"); const cssOptimizer = new Critters({ ssrMode: true, @@ -697,7 +748,7 @@ export async function renderToHTML(req, res, pathname, query, renderOpts) { } : null, inAmpMode || hybridAmp ? async (html)=>{ return html.replace(/&amp=1/g, "&=1"); - } : null + } : null, ] : []).filter(Boolean); if (generateStaticHTML || postProcessors.length > 0) { let html = await piperToString(chainPipers(pipers)); @@ -732,6 +783,7 @@ function renderToStream(element, generateStaticHTML) { return new Promise((resolve, reject)=>{ let underlyingStream = null; const stream = new Writable({ + // Use the buffer from the underlying stream highWaterMark: 0, write (chunk, encoding, callback) { if (!underlyingStream) { @@ -757,6 +809,9 @@ function renderToStream(element, generateStaticHTML) { } underlyingStream.resolve(err); }); + // React uses `flush` to prevent stream middleware like gzip from buffering to the + // point of harming streaming performance, so we make sure to expose it and forward it. + // See: https://github.com/reactwg/react-18/discussions/91 Object.defineProperty(stream, "flush", { value: ()=>{ if (!underlyingStream) { diff --git a/crates/swc_webpack_ast/tests/fixture/css-escape/1/output.js b/crates/swc_webpack_ast/tests/fixture/css-escape/1/output.js index c045cb3a7a5..f1b4f1b7cbb 100644 --- a/crates/swc_webpack_ast/tests/fixture/css-escape/1/output.js +++ b/crates/swc_webpack_ast/tests/fixture/css-escape/1/output.js @@ -1,5 +1,8 @@ -if (exports) module.exports = null; +// https://github.com/umdjs/umd/blob/master/returnExports.js +if (exports) // For Node.js. +module.exports = null; else { define, define.amd; + // For AMD. Register as an anonymous module. define([], factory.bind(root, root)); } diff --git a/crates/swc_webpack_ast/tests/fixture/issue/1/output.js b/crates/swc_webpack_ast/tests/fixture/issue/1/output.js index d9e9f381463..3999d703060 100644 --- a/crates/swc_webpack_ast/tests/fixture/issue/1/output.js +++ b/crates/swc_webpack_ast/tests/fixture/issue/1/output.js @@ -22,7 +22,7 @@ var source; var key; const data = null; export const version = process.env.__NEXT_VERSION; -const looseToArray = null, { props: hydrateProps , err: hydrateErr , page , query , buildId , assetPrefix , runtimeConfig , dynamicIds , isFallback , locale , locales , domainLocales , isPreview , rsc } = null; +const looseToArray = null, { props: hydrateProps , err: hydrateErr , page , query , buildId , assetPrefix , runtimeConfig , dynamicIds , isFallback , locale , locales , domainLocales , isPreview , rsc , } = null; let { defaultLocale } = null; const prefix = null; setConfig(null); @@ -104,7 +104,7 @@ const wrapApp = ()=>{ let RSCComponent; if (process.env.__NEXT_RSC) { const rscCache = null, RSCWrapper = ()=>{ - const { createFromFetch } = require("next/dist/compiled/react-server-dom-webpack"); + const { createFromFetch , } = require("next/dist/compiled/react-server-dom-webpack"); let response; (()=>{ const t = null; @@ -136,12 +136,10 @@ const elem = React.createElement(React.Fragment, null, React.createElement(null, let referenceNode; ()=>{ const targetTag = null; - }, ()=>{ - }; + }, ()=>{}; }), React.createElement(null, null, React.createElement(null, null), React.createElement(Portal, "next-route-announcer", React.createElement(RouteAnnouncer, null)))); React.createElement(React.createElement(React.StrictMode, null, null)); -React.useLayoutEffect(null, null), React.useEffect(()=>{ -}, null), React.useEffect(()=>{ +React.useLayoutEffect(null, null), React.useEffect(()=>{}, null), React.useEffect(()=>{ measureWebVitals(null); }, null); React.useLayoutEffect(null, null); diff --git a/crates/swc_webpack_ast/tests/fixture/next/client/index/output.js b/crates/swc_webpack_ast/tests/fixture/next/client/index/output.js index b901efd7c6d..841ec32c36c 100644 --- a/crates/swc_webpack_ast/tests/fixture/next/client/index/output.js +++ b/crates/swc_webpack_ast/tests/fixture/next/client/index/output.js @@ -40,7 +40,7 @@ const data = null; const version = null; exports.version = null; const looseToArray = null; -const { props: hydrateProps , err: hydrateErr , page , query , buildId , assetPrefix , runtimeConfig , dynamicIds , isFallback , locale , locales , domainLocales , isPreview , rsc } = null; +const { props: hydrateProps , err: hydrateErr , page , query , buildId , assetPrefix , runtimeConfig , dynamicIds , isFallback , locale , locales , domainLocales , isPreview , rsc , } = null; let { defaultLocale } = null; const prefix = null; let asPath; @@ -51,6 +51,7 @@ if (process.env.__NEXT_I18N_SUPPORT) { const { formatUrl } = require("../shared/lib/router/utils/format-url"); const parsedAs = null; const localePathResult = null; + // attempt detecting default locale based on hostname const detectedDomain = null; } const { initScriptLoader } = require("./script"); @@ -84,11 +85,13 @@ let CachedComponent; const { component: app , exports: mod } = null; const exportedReportWebVitals = null; ()=>{ + // Combines timestamp with random number for unique ID const uniqueID = null; let perfStartEntry; const webVitals = null; }; - const pageEntrypoint = null; + const pageEntrypoint = // error, so we need to skip waiting for the entrypoint. + null; if (process.env.NODE_ENV !== "production") { const { isValidElementType } = require("react-is"); } @@ -109,10 +112,14 @@ const { App , err } = null; (()=>{ import("../pages/_error")(null); })(()=>{ + // In production we do a normal render with the `ErrorComponent` as component. + // If we've gotten here upon initial render, we can use the props from the server. + // Otherwise, we need to call `getInitialProps` on `App` before mounting. const AppTree = null; const appCtx = null; }); let reactRoot; +// On initial render a hydrate should always happen let shouldHydrate; const reactEl = null; const navStartEntries = null; @@ -123,7 +130,7 @@ let RSCComponent; if (process.env.__NEXT_RSC) { const rscCache = null; const RSCWrapper = ()=>{ - const { createFromFetch } = require("next/dist/compiled/react-server-dom-webpack"); + const { createFromFetch , } = require("next/dist/compiled/react-server-dom-webpack"); let response; (()=>{ const t = null; @@ -160,8 +167,9 @@ const nonce = null; const desiredHrefs = null; const currentStyleTags1 = null; const currentHrefs1 = null; +// Reorder styles into intended order: let referenceNode; ()=>{ const targetTag = null; }; -const elem = null; +const elem = /*#__PURE__*/ null; diff --git a/crates/swc_webpack_ast/tests/fixture/process-shim/1/output.js b/crates/swc_webpack_ast/tests/fixture/process-shim/1/output.js index f1778571052..e9487eed953 100644 --- a/crates/swc_webpack_ast/tests/fixture/process-shim/1/output.js +++ b/crates/swc_webpack_ast/tests/fixture/process-shim/1/output.js @@ -1,4 +1,9 @@ +// shim for using process in browser var process = module.exports = null; +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; var queue; @@ -14,7 +19,7 @@ process.title = null; process.browser = null; process.env = null; process.argv = null; -process.version = null; +process.version = null; // empty string to avoid regexp issues process.versions = null; process.on = null; process.addListener = null; diff --git a/crates/swc_webpack_ast/tests/fixture/react-dom/dev-cjs/output.js b/crates/swc_webpack_ast/tests/fixture/react-dom/dev-cjs/output.js index 736407da3cd..e218fe05211 100644 --- a/crates/swc_webpack_ast/tests/fixture/react-dom/dev-cjs/output.js +++ b/crates/swc_webpack_ast/tests/fixture/react-dom/dev-cjs/output.js @@ -6,12 +6,12 @@ if (process.env.NODE_ENV !== "production") { var ReactSharedInternals; var ReactDebugCurrentFrame; var stack; - var argsWithFormat; + var argsWithFormat; // Careful: RN currently depends on this prefix var FunctionComponent; var ClassComponent; - var IndeterminateComponent; - var HostRoot; - var HostPortal; + var IndeterminateComponent; // Before we know whether it is function or class + var HostRoot; // Root of a host tree. Could be nested inside another node. + var HostPortal; // A subtree. Could be an entry point to a different renderer. var HostComponent; var HostText; var Fragment; @@ -32,24 +32,45 @@ if (process.env.NODE_ENV !== "production") { var Block; var OffscreenComponent; var LegacyHiddenComponent; - var enableProfilerTimer; - var enableFundamentalAPI; - var enableNewReconciler; + // Filter certain DOM attributes (e.g. src, href) if their values are empty strings. + var enableProfilerTimer; // Record durations for commit and passive effects phases. + var enableFundamentalAPI; // Experimental Scope support. + var enableNewReconciler; // Errors that are thrown while unmounting (or after in the case of passive effects) var warnAboutStringRefs; var allNativeEvents; - var registrationNameDependencies; - var possibleRegistrationNames; + /** + * Mapping from registration name to event name + */ var registrationNameDependencies; + /** + * Mapping from lowercase registration names to the properly cased version, + * used to warn in the case of missing event handlers. Available + * only in true. + * @type {Object} + */ var possibleRegistrationNames; // Trust the developer to only use possibleRegistrationNames in true var lowerCasedName; var canUseDOM = !!(typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"); - var RESERVED; - var STRING; - var BOOLEANISH_STRING; - var BOOLEAN; - var OVERLOADED_BOOLEAN; - var NUMERIC; + // A reserved attribute. + // It is handled by React separately and shouldn't be written to the DOM. + var RESERVED; // A simple string attribute. + // Attributes that aren't in the filter are presumed to have this type. + var STRING; // A string attribute that accepts booleans in React. In HTML, these are called + // "enumerated" attributes with "true" and "false" as possible values. + // When true, it should be set to a "true" string. + // When false, it should be set to a "false" string. + var BOOLEANISH_STRING; // A real boolean attribute. + // When true, it should be present (set either to an empty string or its name). + // When false, it should be omitted. + var BOOLEAN; // An attribute that can be used as a flag as well as with a value. + // When true, it should be present (set either to an empty string or its name). + // When false, it should be omitted. + // For any other value, should be present with that value. + var OVERLOADED_BOOLEAN; // An attribute that must be numeric or parse as a numeric. + // When falsy, it should be removed. + var NUMERIC; // An attribute that must be positive numeric or parse as a positive numeric. + // When falsy, it should be removed. var POSITIVE_NUMERIC; - var ATTRIBUTE_NAME_START_CHAR; - var ATTRIBUTE_NAME_CHAR; + /* eslint-disable max-len */ var ATTRIBUTE_NAME_START_CHAR; + /* eslint-enable max-len */ var ATTRIBUTE_NAME_CHAR; var ROOT_ATTRIBUTE_NAME; var VALID_ATTRIBUTE_NAME_REGEX; var hasOwnProperty; @@ -59,24 +80,34 @@ if (process.env.NODE_ENV !== "production") { case "boolean": var prefix; } - var properties; + // the `possibleStandardNames` module to ensure casing and incorrect + // name warnings. + var properties; // These props are reserved by React. They shouldn't be written to the DOM. var reservedProps; (function() { var name, attributeName; - }); + }); // These are "enumerated" HTML attributes that accept "true" and "false". var CAMELIZE; - var capitalize; + var capitalize; // This is a list of all SVG attributes that need special casing, namespacing, (function() { var name; - }); + }); // String SVG attributes with the xlink namespace. (function() { var name; - }); + }); // String SVG attributes with the xml namespace. (function() { var name; - }); + }); // These attribute exists both in HTML and SVG. + // These will also need to accept Trusted Types object in the future. var xlinkHref; - var isJavaScriptProtocol; + // and any newline or tab are filtered out as if they're not part of the URL. + // https://url.spec.whatwg.org/#url-parsing + // Tab or newline are defined as \r\n\t: + // https://infra.spec.whatwg.org/#ascii-tab-or-newline + // A C0 control is a code point in the range \u0000 NULL to \u001F + // INFORMATION SEPARATOR ONE, inclusive: + // https://infra.spec.whatwg.org/#c0-control-or-space + /* eslint-disable max-len */ var isJavaScriptProtocol; var didWarn; var propertyName; var attributeName; @@ -91,6 +122,11 @@ if (process.env.NODE_ENV !== "production") { var attributeName1, attributeNamespace; var _type; var attributeValue; + // ATTENTION + // When adding new symbols to this file, + // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols' + // The Symbol used to tag the ReactElement-like types. If there is no native Symbol + // nor polyfill, then a plain number is used for performance. var REACT_ELEMENT_TYPE; var REACT_PORTAL_TYPE; var REACT_FRAGMENT_TYPE; @@ -115,6 +151,10 @@ if (process.env.NODE_ENV !== "production") { var MAYBE_ITERATOR_SYMBOL; var FAUX_ITERATOR_SYMBOL; var maybeIterator; + // Helpers to patch console.logs to avoid logging during side-effect free + // replaying on render function. This currently only patches the object + // lazily which won't cover if the log function was extracted eagerly. + // We could also eagerly patch the method. var disabledDepth; var prevLog; var prevInfo; @@ -123,8 +163,8 @@ if (process.env.NODE_ENV !== "production") { var prevGroup; var prevGroupCollapsed; var prevGroupEnd; - var props; - var props1; + var props; // $FlowFixMe Flow thinks console is immutable. + /* eslint-disable react-internal/no-production-logging */ var props1; // $FlowFixMe Flow thinks console is immutable. var ReactCurrentDispatcher; var prefix1; var match; @@ -133,13 +173,17 @@ if (process.env.NODE_ENV !== "production") { var PossiblyWeakMap; var frame; var control; - var previousPrepareStackTrace; + var previousPrepareStackTrace; // $FlowFixMe It does accept undefined. var previousDispatcher; - var Fake; + // Something should be setting the props in the constructor. + var Fake; // $FlowFixMe + // This extracts the first frame from the sample that isn't also in the control. + // Skipping one frame that we assume is the frame that calls the two. var sampleLines; var controlLines; var s; var c; + // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. var _frame; var name; var syntheticFrame; @@ -175,10 +219,10 @@ if (process.env.NODE_ENV !== "production") { var value2; var valueField; var descriptor; - var currentValue; + var currentValue; // if someone has already defined a value or Safari, then bail var get, set; var tracker; - var tracker1; + var tracker1; // if there is no tracker at this point it's unlikely var lastValue; var nextValue; var didWarnValueDefaultValue; @@ -197,20 +241,33 @@ if (process.env.NODE_ENV !== "production") { var controlled; var value3; var type2; - var node5; + var node5; // Do not assign value if it is already set. This prevents user text input var type3; - var isButton; - var initialValue; + var isButton; // Avoid setting value attribute on submit/reset inputs as it overrides the + var initialValue; // Do not assign value if it is already set. This prevents user text input + // this is needed to work around a chrome bug where setting defaultChecked + // will sometimes influence the value of checked (even after detachment). + // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416 + // We need to temporarily unset name to avoid disrupting radio button groups. var name1; var node6; var name2; var queryRoot; + // but that sometimes behaves strangely in IE8. We could also try using + // `form.getElementsByName`, but that will only return direct children + // and won't include inputs that use the HTML5 `form=` attribute. Since + // the input might not even be in a form. It might not even be in the + // document. Let's just use the local `querySelectorAll` to ensure we don't + // miss anything. var group; var otherNode; + // and the same name are rendered into the same form (same as #1939). + // That's probably okay; we don't support it just as we don't support + // mixing React radio buttons with non-React ones. var otherProps; var didWarnSelectedSetOnOption; var didWarnInvalidChild; - var content; + var content; // Flatten children. We'll warn if they are invalid var hostProps1; var content1; var didWarnValueDefaultValue$1; @@ -222,6 +279,8 @@ if (process.env.NODE_ENV !== "production") { var selectedValues; var selectedValue; var selected; + // Do not set `select.value` as exact behavior isn't consistent across all + // browsers for all cases. var _selectedValue; var defaultSelected; var node7; @@ -234,43 +293,86 @@ if (process.env.NODE_ENV !== "production") { var value6; var didWarnValDefaultVal; var node11; + // get reset if `textContent` is mutated. We could add a check in setTextContent + // to only set the value if/when the value differs from the node value (which would + // completely solve this IE9 bug), but Sebastian+Sophie seemed to like this + // solution. The value can be a boolean or object so that's why it's forced + // to be a string. var hostProps2; var node12; - var initialValue1; + var initialValue1; // Only bother fetching default value if we're going to use it var children, defaultValue1; var node13; var value7; var defaultValue2; - var newValue; - var node14; - var textContent; + // Cast `value` to a string to ensure the value is set correctly. While + // browsers typically do this as necessary, jsdom doesn't. + var newValue; // To avoid side effects (such as losing text selection), only set value if changed + var node14; // This is in postMount because we need access to the DOM node, which is not + // available until after the component has mounted. + var textContent; // Only set node.value if textContent is equal to the expected var HTML_NAMESPACE; var MATH_NAMESPACE; var SVG_NAMESPACE; - var Namespaces; - var createMicrosoftUnsafeLocalFunction; + var Namespaces; // Assumes there is no parent namespace. + /* globals MSApp */ /** + * Create a function which has 'unsafe' privileges (required by windows8 apps) + */ var createMicrosoftUnsafeLocalFunction; var reusableSVGContainer; - var setInnerHTML = function() { + /** + * Set the innerHTML property of a node + * + * @param {DOMElement} node + * @param {string} html + * @internal + */ var setInnerHTML = function() { var svgNode; }; - var ELEMENT_NODE; + /** + * HTML nodeType values that represent the type of the node + */ var ELEMENT_NODE; var TEXT_NODE; var COMMENT_NODE; var DOCUMENT_NODE; var DOCUMENT_FRAGMENT_NODE; - var setTextContent = function() { + /** + * Set the textContent property of a node. For text updates, it's faster + * to set the `nodeValue` of the Text node directly instead of using + * `.textContent` which will remove the existing node and create a new one. + * + * @param {DOMElement} node + * @param {string} text + * @internal + */ var setTextContent = function() { var firstChild; }; + // List derived from Gecko source code: + // https://github.com/mozilla/gecko-dev/blob/4e638efc71/layout/style/test/property_database.js var shorthandToLonghand; - var isUnitlessNumber; - var prefixes; + /** + * CSS properties which accept numbers but are not in units of "px". + */ var isUnitlessNumber; + /** + * Support style names that may come passed in prefixed by adding permutations + * of vendor prefixes. + */ var prefixes; // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an + // Note that we've removed escapeTextForBrowser() calls here since the + // whole string will be escaped when the attribute is injected into + // the markup. If you provide unsafe user data here they can inject + // arbitrary CSS which may be problematic (I couldn't repro this): + // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ + // This is not an XSS hole but instead a potential CSS injection issue + // which has lead to a greater discussion about how we're going to + // trust URLs moving forward. See #2115901 var isEmpty; var uppercasePattern; var msPattern; var warnValidStyle; + // 'msTransform' is correct, but the other prefixes should be capitalized var badVendoredStyleNamePattern; var msPattern$1; - var hyphenPattern; + var hyphenPattern; // style values shouldn't contain a semicolon var badStyleValueWithSemicolonPattern; var warnedStyleNames; var warnedStyleValues; @@ -302,9 +404,15 @@ if (process.env.NODE_ENV !== "production") { var originalKey; var correctOriginalKey; var warningKey; + // For HTML, certain tags should omit their close tag. We keep a list for + // those special-case tags. var omittedCloseTags; + // `omittedCloseTags` except that `menuitem` should still have its closing tag. var voidElementTags; var HTML; + // When adding attributes to the HTML or SVG allowed attribute list, be sure to + // also add them to this module to ensure casing and incorrect name + // warnings. var possibleStandardNames; var ariaProperties; var warnedProperties; @@ -312,9 +420,9 @@ if (process.env.NODE_ENV !== "production") { var rARIACamel; var hasOwnProperty$1; var ariaName; - var correctName; + var correctName; // If this is an aria-* attribute, but is not listed in the known DOM var lowerCasedName1; - var standardName; + var standardName; // If this is an aria-* attribute, but is not listed in the known DOM var invalidProps; var key2; var isValid; @@ -332,7 +440,7 @@ if (process.env.NODE_ENV !== "production") { var registrationNameDependencies, possibleRegistrationNames; var registrationName; var propertyInfo; - var isReserved; + var isReserved; // Known attributes should match the casing specified in the property config. var standardName; }); var warnUnknownProperties = function() { @@ -345,55 +453,93 @@ if (process.env.NODE_ENV !== "production") { var IS_NON_DELEGATED; var IS_CAPTURE_PHASE; var IS_REPLAYED; + // set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when + // we call willDeferLaterForLegacyFBSupport, thus not bailing out + // will result in endless cycles like an infinite loop. + // We also don't want to defer during event replaying. var SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS; - var target; + // Fallback to nativeEvent.srcElement for IE9 + // https://github.com/facebook/react/issues/12506 + var target; // Normalize SVG element events #4963 var restoreImpl; var restoreTarget; var restoreQueue; + // We perform this translation at the end of the event loop so that we + // always receive the correct fiber here var internalInstance; - var stateNode; + var stateNode; // Guard against Fiber being unmounted. var _props; var target1; var queuedTargets; + // the renderer. Such as when we're dispatching events or if third party + // libraries need to call batchedUpdates. Eventually, this API will go away when + // everything is batched by default. We'll then have a similar API to opt-out of + // scheduled work and instead do synchronous work. + // Defaults var batchedUpdatesImpl; var discreteUpdatesImpl; var flushDiscreteUpdatesImpl; var batchedEventUpdatesImpl; var isInsideEventHandler; var isBatchingEventUpdates; + // Here we wait until all updates have propagated, which is important + // when using controlled components within layers: + // https://github.com/facebook/react/issues/1698 + // Then we restore state of any controlled component. var controlledComponentsHavePendingUpdates; var prevIsInsideEventHandler; var stateNode1; var props2; var listener; - var passiveBrowserEventsSupported; - var options1; + var passiveBrowserEventsSupported; // Check if browser support events with passive listeners + var options1; // $FlowFixMe: Ignore Flow complaining about needing a value var funcArgs; var invokeGuardedCallbackImpl; var fakeNode; (function invokeGuardedCallbackDev() { var evt; - var didCall; - var didError; - var windowEvent; + var didCall; // Keeps track of whether the user-provided callback threw an error. We + // set this to true at the beginning, then set it to false right after + // calling the function. If the function errors, `didError` will never be + // set to false. This strategy works even if the browser is flaky and + // fails to call our global error handler, because it doesn't rely on + // the error event at all. + var didError; // Keeps track of the value of window.event so that we can reset it + // during the callback to let user code access window.event in the + // browsers that support it. + var windowEvent; // Keeps track of the descriptor of window.event to restore it after event + // dispatching: https://github.com/facebook/react/issues/13688 var windowEventDescriptor; + // dispatch our fake event using `dispatchEvent`. Inside the handler, we + // call the user-provided callback. var funcArgs; - var error; + // that was thrown. It's possible that this error handler will fire more + // than once; for example, if non-React code also calls `dispatchEvent` + // and a handler for that event throws. We should be resilient to most of + // those cases. Even if our error event handler fires more than once, the + // last error event is always used. If the callback actually does error, + // we know that the last error event is the correct one, because it's not + // possible for anything else to have happened in between our callback + // erroring and the code that follows the `dispatchEvent` call below. If + // the callback doesn't error, but the error event was fired, we know to + // ignore it because `didError` will be false, as described above. + var error; // Use this to track whether the error event is ever called. var didSetError; var isCrossOriginError; - var evtType; + var evtType; // Attach our event handlers }); var invokeGuardedCallbackImpl$1; var hasError; - var caughtError; + var caughtError; // Used by event system to capture/rethrow the first error. var hasRethrowError; var rethrowError; var reporter; var error; var error1; var error2; + // Don't change these two values. They're used by React Dev Tools. var NoFlags; - var PerformedWork; + var PerformedWork; // You can change the rest (and add more). var Placement; var Update; var PlacementAndUpdate; @@ -403,18 +549,20 @@ if (process.env.NODE_ENV !== "production") { var DidCapture; var Ref; var Snapshot; - var Passive; + var Passive; // TODO (effects) Remove this bit once the new reconciler is synced to the old. var PassiveUnmountPendingDev; var Hydrating; - var HydratingAndUpdate; - var LifecycleEffectMask; - var HostEffectMask; + var HydratingAndUpdate; // Passive & Update & Callback & Ref & Snapshot + var LifecycleEffectMask; // Union of all host effects + var HostEffectMask; // These are not really side effects, but we still reuse this field. var Incomplete; var ShouldCapture; - var ForceUpdateForLegacySuspense; + var ForceUpdateForLegacySuspense; // Static tags describe aspects of a fiber that are not specific to a render, var ReactCurrentOwner; var node15; var nearestMounted; + // If there is no alternate, this might be a new tree that isn't inserted + // yet. If it is, then it will have a pending insertion effect on it. var nextNode; var suspenseState; var current1; @@ -423,13 +571,25 @@ if (process.env.NODE_ENV !== "production") { var instance; var fiber; var alternate; + // If there is no alternate, then we only need to check if it is mounted. var nearestMounted1; + // to see what path the root points to. On the way we may hit one of the + // special cases and we'll deal with them. var a; var b; var parentA; var parentB; + // There is no alternate. This is an unusual case. Currently, it only + // happens when a Suspense component is hidden. An extra fragment fiber + // is inserted in between the Suspense fiber and its children. Skip + // over this extra fragment fiber and proceed to the next parent. var nextParent; var child; + // The return pointers point to the same fiber. We'll have to use the + // default, slow path: scan the child sets of each parent alternate to see + // which child belongs to which set. + // + // Search parent A's child set var didFindChild; var _child; var currentParent; @@ -442,13 +602,14 @@ if (process.env.NODE_ENV !== "production") { var attemptContinuousHydration; var attemptHydrationAtCurrentPriority; var attemptHydrationAtPriority; - var hasScheduledReplayAttempt; - var queuedDiscreteEvents; + var hasScheduledReplayAttempt; // The queue of discrete events to be replayed. + var queuedDiscreteEvents; // Indicates if any continuous event targets are non-null for early bailout. + // if the last target was dehydrated. var queuedFocus; var queuedDrag; - var queuedMouse; + var queuedMouse; // For pointer events there can be one latest event per pointerId. var queuedPointers; - var queuedPointerCaptures; + var queuedPointerCaptures; // We could consider replaying selectionchange and touchmoves too. var queuedExplicitHydrationTargets; var discreteReplayableEvents; var queuedEvent; @@ -461,6 +622,9 @@ if (process.env.NODE_ENV !== "production") { var queuedEvent1; var _fiber2; var targetContainers; + // These set relatedTarget to null because the replayed event will be treated as if we + // moved from outside the window (no target) onto the target once it hydrates. + // Instead of mutating we could clone the event. switch(null){ case "focusin": var focusEvent; @@ -475,6 +639,9 @@ if (process.env.NODE_ENV !== "production") { var _pointerEvent; var _pointerId2; } + // TODO: This function shares a lot of logic with attemptToDispatchEvent. + // Try to unify them. It's a bit tricky since it would require two return + // values. var targetInst; var nearestMounted2; var tag; @@ -483,8 +650,12 @@ if (process.env.NODE_ENV !== "production") { var targetContainers1; var targetContainer; var nextBlockedOn; + // We're still blocked. Try again later. var _fiber3; var nextDiscreteEvent; + // We're still blocked. + // Increase the priority of this boundary to unblock + // the next discrete event. var _fiber4; var targetContainers2; var targetContainer1; @@ -497,9 +668,15 @@ if (process.env.NODE_ENV !== "production") { var UserBlockingEvent; var ContinuousEvent; var prefixes1; - var vendorPrefixes; - var prefixedEventNames; - var style1; + /** + * A list of event names to a configurable list of vendor prefixes. + */ var vendorPrefixes; + /** + * Event names that have already been detected and prefixed (if applicable). + */ var prefixedEventNames; + /** + * Element to check for prefixes on. + */ var style1; var prefixMap; var styleProp; var ANIMATION_END; @@ -507,24 +684,33 @@ if (process.env.NODE_ENV !== "production") { var ANIMATION_START; var TRANSITION_END; var topLevelEventsToReactNames; - var eventPriorities; + var eventPriorities; // We store most of the events in this module in pairs of two strings so we can re-use + // the code required to apply the same logic for event prioritization and that of the + // SimpleEventPlugin. This complicates things slightly, but the aim is to reduce code + // duplication (for which there would be quite a bit). For the events that are not needed + // for the SimpleEventPlugin (otherDiscreteEvents) we process them separately as an + // array of top level events. + // Lastly, we ignore prettier so we can keep the formatting sane. + // prettier-ignore var discreteEventPairsForSimpleEventPlugin; var otherDiscreteEvents; - var userBlockingPairsForSimpleEventPlugin; + var userBlockingPairsForSimpleEventPlugin; // prettier-ignore var continuousPairsForSimpleEventPlugin; var topEvent; var event; var capitalizedEvent; var reactName; - var priority; + var priority; // Default to a ContinuousEvent. Note: we might var Scheduler_now; + // ascending numbers so we can compare them like numbers. They start at 90 to + // avoid clashing with Scheduler's priorities. var ImmediatePriority; var UserBlockingPriority; var NormalPriority; var LowPriority; - var IdlePriority; + var IdlePriority; // NoPriority is the absence of priority. Also React-only. var NoPriority; - var initialTimeMs; + var initialTimeMs; // If the initial timestamp is reasonably small, use Scheduler's `now` directly. var SyncLanePriority; var SyncBatchedLanePriority; var InputDiscreteHydrationLanePriority; @@ -562,6 +748,7 @@ if (process.env.NODE_ENV !== "production") { var IdleLanes; var OffscreenLane; var NoTimestamp; + // Used by getHighestPriorityLanes and getNextLanes: var return_highestLanePriority; var inputDiscreteLanes; var inputContinuousLanes; @@ -569,17 +756,37 @@ if (process.env.NODE_ENV !== "production") { var transitionLanes; var retryLanes; var idleLanes; + // Early bailout if there's no pending work left. var pendingLanes; var nextLanes; var nextLanePriority; var expiredLanes; var suspendedLanes; - var pingedLanes; + var pingedLanes; // Check if any work has expired. + // Do not work on any idle work until all the non-idle work has finished, + // even if the work is suspended. var nonIdlePendingLanes; var nonIdleUnblockedLanes; var nonIdlePingedLanes; + // The only remaining work is Idle. var unblockedLanes; var wipLanePriority; + // + // A lane is said to be entangled with another when it's not allowed to render + // in a batch that does not also include the other lane. Typically we do this + // when multiple updates have the same source, and we only want to respond to + // the most recent event from that source. + // + // Note that we apply entanglements *after* checking for partial work above. + // This means that if a lane is entangled during an interleaved event while + // it's already rendering, we won't interrupt it. This is intentional, since + // entanglement is usually "best effort": we'll try our best to render the + // lanes in the same batch, but it's not worth throwing out partially + // completed work in order to do it. + // + // For those exceptions where entanglement is semantically important, like + // useMutableSource, we should ensure that there is no partial work at the + // time we apply the entanglement. var entangledLanes; var entanglements; var lanes; @@ -591,10 +798,15 @@ if (process.env.NODE_ENV !== "production") { var lane1; var eventTime; var priority1; + // TODO: This gets called every time we yield. We can optimize by storing + // the earliest expiration time on the root. Then use that to quickly bail out + // of this function. var pendingLanes1; var suspendedLanes1; var pingedLanes1; - var expirationTimes; + var expirationTimes; // Iterate through the pending lanes and check if we've reached their + // expiration time. If so, we'll assume the update is being starved and mark + // it as expired to force it to finish. var lanes1; var index2; var lane2; @@ -610,13 +822,30 @@ if (process.env.NODE_ENV !== "production") { case null: var lane3; } + // First look for lanes that are completely unclaimed, i.e. have no + // pending work. var lane4; + // This is a fork of `findUpdateLane` designed specifically for Suspense + // "retries" — a special update that attempts to flip a Suspense boundary + // from its placeholder state to its primary/resolved state. var lane5; + // This finds the most significant non-zero bit. var index3; + // Intentionally pushing one by one. + // https://v8.dev/blog/elements-kinds#avoid-creating-holes var laneMap; - var higherPriorityLanes; + // it's not practical to try every single possible combination. We need a + // heuristic to decide which lanes to attempt to render, and in which batches. + // For now, we use the same heuristic as in the old ExpirationTimes model: + // retry any lane at equal or lower priority, but don't try updates at higher + // priority without also including the lower priority updates. This works well + // when considering updates across different priority levels, but isn't + // sufficient for updates within the same priority, since we want to treat + // those updates as parallel. + // Unsuspend any update at equal or lower priority. + var higherPriorityLanes; // Turns 0b1000 into 0b0111 var eventTimes1; - var index4; + var index4; // We can always overwrite an existing timestamp because we prefer the most var expirationTimes1; var lanes2; var index5; @@ -624,7 +853,7 @@ if (process.env.NODE_ENV !== "production") { var noLongerPendingLanes; var entanglements1; var eventTimes2; - var expirationTimes2; + var expirationTimes2; // Clear the lanes that no longer have pending work var lanes3; var index6; var lane7; @@ -632,22 +861,36 @@ if (process.env.NODE_ENV !== "production") { var lanes4; var index7; var lane8; - var clz32; + var clz32; // Count leading zeros. Only used on lanes, so assume input is an integer. + // Based on: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 var log; var LN2; - var UserBlockingPriority$1, runWithPriority; - var _enabled; + // Intentionally not named imports because Rollup would use dynamic dispatch for + var UserBlockingPriority$1, runWithPriority; // TODO: can we stop exporting these? + var _enabled; // This is exported in FB builds for use by legacy FB layer infra. var eventPriority; var listenerWrapper; var allowReplay; var blockedOn; + // TODO: Warn if _enabled is false. var nativeEventTarget; var targetInst1; var nearestMounted3; var tag1; var instance2; var root1; - var root2; + /** + * These variables store information about text content of a target node, + * allowing comparison of content before and after a given event. + * + * Identify the node where selection currently begins, then observe + * both its text content and its current position in the DOM. Since the + * browser may natively replace the target node during composition, we can + * use its position to find its replacement. + * + * + */ var root2; var startText; var fallbackText; var start; @@ -668,49 +911,110 @@ if (process.env.NODE_ENV !== "production") { }), function() { var event; }; - var EventInterface; + /** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ var EventInterface; var SyntheticEvent; var UIEventInterface; var SyntheticUIEvent; var lastMovementX; var lastMovementY; var lastMouseEvent; - var MouseEventInterface; + /** + * @interface MouseEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ var MouseEventInterface; var SyntheticMouseEvent; - var DragEventInterface; + /** + * @interface DragEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ var DragEventInterface; var SyntheticDragEvent; - var FocusEventInterface; + /** + * @interface FocusEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ var FocusEventInterface; var SyntheticFocusEvent; - var AnimationEventInterface; + /** + * @interface Event + * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface + * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent + */ var AnimationEventInterface; var SyntheticAnimationEvent; - var ClipboardEventInterface; + /** + * @interface Event + * @see http://www.w3.org/TR/clipboard-apis/ + */ var ClipboardEventInterface; var SyntheticClipboardEvent; - var CompositionEventInterface; + /** + * @interface Event + * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents + */ var CompositionEventInterface; var SyntheticCompositionEvent; + /** + * @interface Event + * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105 + * /#events-inputevents + */ // Happens to share the same list for now. var SyntheticInputEvent; - var normalizeKey; - var translateToKey; + /** + * Normalization of deprecated HTML5 `key` values + * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names + */ var normalizeKey; + /** + * Translation from legacy `keyCode` to HTML5 `key` + * Only special keys supported, all others depend on keyboard layout or browser + * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names + */ var translateToKey; + // Normalize inconsistent values reported by browsers due to + // implementations of a working draft specification. + // FireFox implements `key` but returns `MozPrintableKey` for all + // printable characters (normalized to `Unidentified`), ignore it. var key3; - var charCode1; - var modifierKeyToProp; + var charCode1; // The enter-key is technically both printable and non-printable and can + /** + * Translation from modifier key to the associated property in the event. + * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers + */ var modifierKeyToProp; // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support var syntheticEvent; var nativeEvent; var keyProp; - var KeyboardEventInterface; + /** + * @interface KeyboardEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ var KeyboardEventInterface; var SyntheticKeyboardEvent; - var PointerEventInterface; + /** + * @interface PointerEvent + * @see http://www.w3.org/TR/pointerevents/ + */ var PointerEventInterface; var SyntheticPointerEvent; - var TouchEventInterface; + /** + * @interface TouchEvent + * @see http://www.w3.org/TR/touch-events/ + */ var TouchEventInterface; var SyntheticTouchEvent; - var TransitionEventInterface; + /** + * @interface Event + * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events- + * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent + */ var TransitionEventInterface; var SyntheticTransitionEvent; - var WheelEventInterface; + /** + * @interface WheelEvent + * @see http://www.w3.org/TR/DOM-Level-3-Events/ + */ var WheelEventInterface; var SyntheticWheelEvent; - var END_KEYCODES; + var END_KEYCODES; // Tab, Return, Esc, Space var START_KEYCODE; var canUseCompositionEvent; var documentMode; - var canUseTextInputEvent; + // directly represent `beforeInput`. The IE `textinput` event is not as + // useful, so we don't use it. + var canUseTextInputEvent; // In IE9+, we have access to composition events, but the data supplied + // by the native compositionend event may be incorrect. Japanese ideographic + // spaces, for instance (\u3000) are not recorded correctly. var useFallbackCompositionData; var SPACEBAR_CODE; var SPACEBAR_CHAR; @@ -724,27 +1028,50 @@ if (process.env.NODE_ENV !== "production") { var customData; switch(null){ case "keypress": - var which; + /** + * If native `textInput` events are available, our goal is to make + * use of them. However, there is a special case: the spacebar key. + * In Webkit, preventing default on a spacebar `textInput` event + * cancels character insertion, but it *also* causes the browser + * to fall back to its default spacebar behavior of scrolling the + * page. + * + * Tracking at: + * https://code.google.com/p/chromium/issues/detail?id=355103 + * + * To avoid this issue, use the keypress event as if no `textInput` + * event is available. + */ var which; case "textInput": - var chars; + // Record the characters to be added to the DOM. + var chars; // If it's a spacebar character, assume that we have already handled } var chars1; var chars2; var listeners1; var event2; - var supportedInputTypes; + /** + * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + */ var supportedInputTypes; var nodeName1; var eventName; var isSupported; var element; var listeners2; var event3; - var activeElement; + /** + * For IE shims + */ var activeElement; var activeElementInst; var nodeName2; var dispatchQueue; var targetNode; - var isInputEventSupported; + /** + * SECTION: handle `input` event + */ var isInputEventSupported; + // Use the `click` event to detect changes to checkbox and radio inputs. + // This approach works across all browsers, whereas `change` does not fire + // until `blur` in IE8. var nodeName3; var state; var targetNode1; @@ -752,8 +1079,13 @@ if (process.env.NODE_ENV !== "production") { var inst; var isOverEvent; var isOutEvent; + // If this is an over event with a target, we might have already dispatched + // the event in the out event of the other target. If this is replayed, + // then it's because we couldn't dispatch against this target previously + // so we have to do it now instead. var related; - var win; + var win; // TODO: why is this nullable in the types but we read from it? + // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8. var doc; var from; var to; @@ -766,7 +1098,8 @@ if (process.env.NODE_ENV !== "production") { var fromNode; var toNode; var leave; - var enter; + var enter; // We should only process this nativeEvent if we are processing + // the first ancestor. Next time, we will ignore the event. var nativeTargetInst; var enterEvent; var objectIs; @@ -779,7 +1112,7 @@ if (process.env.NODE_ENV !== "production") { var ownerDocument; var win1; var selection; - var anchorNode, anchorOffset, focusNode, focusOffset; + var anchorNode, anchorOffset, focusNode, focusOffset; // In Firefox, anchorNode and focusNode can be "anonymous divs", e.g. the var length; var start1; var end1; @@ -789,11 +1122,11 @@ if (process.env.NODE_ENV !== "production") { var parentNode; var next; var doc1; - var win2; + var win2; // Edge fails with "Object expected" in some scenarios. var selection1; var length1; var start2; - var end2; + var end2; // IE 11 uses modern selection, but doesn't support the extend method. var temp; var startMarker; var endMarker; @@ -818,6 +1151,10 @@ if (process.env.NODE_ENV !== "production") { var mouseDown; var win4; var selection3; + // Ensure we have the right element, and that the user is not dragging a + // selection (this matches native `select` event behavior). In HTML5, select + // fires only on input and textarea thus if there's no focused element we + // won't dispatch. var doc2; var currentSelection; var listeners3; @@ -827,11 +1164,18 @@ if (process.env.NODE_ENV !== "production") { var SyntheticEventCtor1; var reactEventType; var inCapturePhase; + // Some events don't bubble in the browser. + // In the past, React has always bubbled them, but this can be surprising. + // We're going to try aligning closer to the browser behavior by not bubbling + // them in React either. We'll start by not bubbling onScroll, and then expand. var accumulateTargetOnly; var _listeners; + // Intentionally create event lazily. var _event; - var shouldProcessPolyfillPlugins; - var mediaEventTypes; + var shouldProcessPolyfillPlugins; // We don't process these events unless we are in the + var mediaEventTypes; // We should not delegate these events to the container, but rather + // set them on the actual target element itself. This is primarily + // because these events do not consistently bubble in the DOM. var nonDelegatedEvents; var type4; var previousInstance; @@ -846,17 +1190,33 @@ if (process.env.NODE_ENV !== "production") { var listenerSetKey; var listeningMarker; var eventSystemFlags; - var target2; + var target2; // selectionchange needs to be attached to the document var listenerSet1; - var listenerSetKey1; - var listener2; + var listenerSetKey1; // If the listener entry is empty or we should upgrade, then + var listener2; // If passive option is not supported, then the event will be + // active and not passive. var isPassiveListener; - var unsubscribeListener; + var unsubscribeListener; // When legacyFBSupport is enabled, it's for when we var ancestorInst; - var targetContainerNode; + var targetContainerNode; // If we are using the legacy FB support flag, we + // The below logic attempts to work out if we need to change + // the target fiber to a different ancestor. We had similar logic + // in the legacy event system, except the big difference between + // systems is that the modern event system now has an event listener + // attached to each React Root and React Portal Root. Together, + // the DOM nodes representing these roots are the "rootContainer". + // To figure out which ancestor instance we should use, we traverse + // up the fiber tree from the target instance and attempt to find + // root boundaries that match that of our current "rootContainer". + // If we find that "rootContainer", we find the parent fiber + // sub-tree for that root and make that our ancestor instance. var node21; var nodeTag; var container2; + // The target is a portal, but it's not the rootContainer we're looking for. + // Normally portals handle their own events all the way down to the root. + // So we should be able to stop now. However, we don't know if this portal + // was part of *our* root. var grandNode; var grandTag; var grandContainer; @@ -866,13 +1226,13 @@ if (process.env.NODE_ENV !== "production") { var reactEventName; var listeners5; var instance4; - var lastHostComponent; - var _instance2, stateNode2, tag2; + var lastHostComponent; // Accumulate all instances and listeners via the target -> root path. + var _instance2, stateNode2, tag2; // Handle listeners that are on HostComponents (i.e.

) var listener3; var captureName1; var listeners6; - var instance5; - var _instance3, stateNode3, tag3; + var instance5; // Accumulate all instances and listeners via the target -> root path. + var _instance3, stateNode3, tag3; // Handle listeners that are on HostComponents (i.e.
) var currentTarget1; var captureListener; var bubbleListener; @@ -908,6 +1268,10 @@ if (process.env.NODE_ENV !== "production") { var canDiffStyleForHydrationWarning; var normalizeMarkupForTextOrAttribute; var normalizeHTML; + // It also can turn \u0000 into \uFFFD inside attributes. + // https://www.w3.org/TR/html5/single-page.html#preprocessing-the-input-stream + // If we have a mismatch, it might be caused by that. + // We will still patch up in this case but not fire the warning. var NORMALIZE_NEWLINES_REGEX; var NORMALIZE_NULL_AND_REPLACEMENT_REGEX; (function() { @@ -925,19 +1289,31 @@ if (process.env.NODE_ENV !== "production") { var names; }); (function() { + // We could have created a separate document here to avoid + // re-initializing custom elements if they exist. But this breaks + // how