From 0d9ecf39c1f452be1f2e583f72cebc6986a8088b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Sat, 1 Jun 2024 23:18:34 +0900 Subject: [PATCH] fix(es/resolver): Fix hoisting of `const` and `let` (#8987) **Description:** - Repro: https://github.com/kdy1/repro-next-66237 **Related issue:** - https://github.com/vercel/next.js/issues/66237 --- .../no-loop-func/default/output.swc-stderr | 33 ------- .../tests/fixture/next/66237/input.js | 96 +++++++++++++++++++ .../tests/fixture/next/66237/output.js | 37 +++++++ .../src/resolver/mod.rs | 10 +- .../tests/resolver/next-66237/input.js | 27 ++++++ .../tests/resolver/next-66237/output.js | 34 +++++++ 6 files changed, 195 insertions(+), 42 deletions(-) create mode 100644 crates/swc_ecma_minifier/tests/fixture/next/66237/input.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/next/66237/output.js create mode 100644 crates/swc_ecma_transforms_base/tests/resolver/next-66237/input.js create mode 100644 crates/swc_ecma_transforms_base/tests/resolver/next-66237/output.js diff --git a/crates/swc/tests/errors/lints/no-loop-func/default/output.swc-stderr b/crates/swc/tests/errors/lints/no-loop-func/default/output.swc-stderr index e7445d91d0ab..1022fe34088c 100644 --- a/crates/swc/tests/errors/lints/no-loop-func/default/output.swc-stderr +++ b/crates/swc/tests/errors/lints/no-loop-func/default/output.swc-stderr @@ -34,39 +34,6 @@ 59 | setTimeout(() => { `---- - x the name `ee` is defined multiple times - ,-[46:1] - 46 | while (cond) { - 47 | let x = 10; - 48 | - 49 | function ee() { - : ^| - : `-- previous definition of `ee` here - 50 | alert(x); - 51 | } - 52 | } - 53 | - 54 | // not ok - 55 | while (true) { - 56 | var a = 0; - 57 | - 58 | while (true) { - 59 | setTimeout(() => { - 60 | a; - 61 | }) - 62 | } - 63 | } - 64 | - 65 | - 66 | - 67 | let { aa, bb: { bb }, cc: [cc], ...ee } = obj; - : ^| - : `-- `ee` redefined here - 68 | for (const k in obj) { - 69 | setTimeout(() => { - 70 | aa; - `---- - x Function declared in a loop contains unsafe references to variable i ,-[6:1] 6 | diff --git a/crates/swc_ecma_minifier/tests/fixture/next/66237/input.js b/crates/swc_ecma_minifier/tests/fixture/next/66237/input.js new file mode 100644 index 000000000000..c91ba3e7697e --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/next/66237/input.js @@ -0,0 +1,96 @@ +"use strict"; +(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([[854], { + +/***/ 3712: +/***/ (function (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ $Q: function () { return /* binding */ C; }, +/* harmony export */ Ev: function () { return /* binding */ B; }, +/* harmony export */ e_: function () { return /* binding */ I; }, +/* harmony export */ jU: function () { return /* binding */ e; } + /* harmony export */ +}); + /* unused harmony exports ACTION_ELEMENTS, SbbScrollHandler, breakpoints, findInput, findReferencedElement, hostContext, isAndroid, isBlink, isBreakpoint, isChromium, isEdge, isFirefox, isIOS, isNextjs, isSafari, isTrident, isWebkit, pageScrollDisabled */ + let a; + try { + a = typeof Intl < "u" && Intl.v8BreakIterator; + } catch (e) { + a = !1; + } + const e = () => typeof document == "object" && !!document, l = () => e() && /(edge)/i.test(navigator.userAgent), c = () => e() && /(msie|trident)/i.test(navigator.userAgent), y = () => e() && !!(window.chrome || a) && typeof CSS < "u" && !l() && !c(), g = () => e() && /AppleWebKit/i.test(navigator.userAgent) && !y() && !l() && !c(), w = () => e() && /iPad|iPhone|iPod/.test(navigator.userAgent) && !("MSStream" in window), v = () => e() && /(firefox|minefield)/i.test(navigator.userAgent), A = () => e() && /android/i.test(navigator.userAgent) && !c(), E = () => e() && /safari/i.test(navigator.userAgent) && g(), p = () => !!globalThis.next, S = () => { + var t, n; + return (n = (t = navigator.userAgentData) == null ? void 0 : t.brands) == null ? void 0 : n.some((o) => o.brand == "Chromium"); + }, x = (/* unused pure expression or super */ null && ([ + "zero", + "micro", + "small", + "medium", + "wide", + "large", + "ultra" + ])); + function k(t, n, o) { + if (!e()) return !1; + const i = getComputedStyle(document.documentElement), s = t ? i.getPropertyValue("--sbb-breakpoint-".concat(t, "-min")) : "", r = n ? "".concat(parseFloat(i.getPropertyValue("--sbb-breakpoint-".concat(n, "-").concat(o != null && o.includeMaxBreakpoint ? "max" : "min"))) - (o != null && o.includeMaxBreakpoint ? 0 : 0.0625), "rem") : "", b = s && "(min-width: ".concat(s, ")"), m = r && "(max-width: ".concat(r, ")"), f = s && r && " and "; + return window.matchMedia("".concat(b).concat(f).concat(m)).matches; + } + function h(t) { + if (e()) { + if (typeof t == "string") return document.getElementById(t); + if (t instanceof window.Element) return t; + } else return null; + return null; + } + const I = () => e() && document.documentElement.getAttribute("dir") || "ltr"; + function $(t, n) { + if (!e()) return null; + var _n_parentElement; + for (n = (_n_parentElement = n.parentElement) !== null && _n_parentElement !== void 0 ? _n_parentElement : n.getRootNode().host; n && n !== document && n !== window;) { + const o = n.closest(t); + if (o) return o; + n = n.getRootNode().host; + } + return null; + } + const M = "a,button,sbb-teaser-hero,sbb-teaser"; + function _(t, n) { + var o; + if (!n) { + const i = (o = t.closest) == null ? void 0 : o.call(t, "sbb-form-field"); + return i == null ? void 0 : i.querySelector("input"); + } + return h(n); + } + function B(t, n, o) { + o ? t.setAttribute(n, o) : t.removeAttribute(n); + } + function u() { + return document.body.hasAttribute("data-sbb-scroll-disabled"); + } + class W { + disableScroll() { + if (u()) return; + this._position = document.body.style.position, this._overflow = document.body.style.overflow, this._marginInlineEnd = document.body.style.marginInlineEnd; + const n = window.innerWidth - document.documentElement.clientWidth; + document.body.style.overflow = "hidden", document.body.style.position = "relative", document.body.style.marginInlineEnd = "".concat(n, "px"), document.body.style.setProperty("--sbb-scrollbar-width", "".concat(n, "px")), document.body.toggleAttribute("data-sbb-scroll-disabled", !0); + } + enableScroll() { + u() && (document.body.style.position = this._position || "", document.body.style.overflow = this._overflow || "", document.body.style.marginInlineEnd = this._marginInlineEnd || "", document.body.style.setProperty("--sbb-scrollbar-width", "0"), document.body.removeAttribute("data-sbb-scroll-disabled")); + } + } + const d = /* @__PURE__ */ new Map(); + function C(t) { + if (d.has(t.constructor)) return d.get(t.constructor); + const n = // eslint-disable-next-line @typescript-eslint/naming-convention + customElements.__definitions; + for (const [o, i] of n) if (i.ctor === t.constructor) return d.set(t.constructor, o), o; + throw new Error("Given element ".concat(t.constructor.name, " has not been registered yet.")); + } + + + + /***/ + }), + +}]); \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/next/66237/output.js b/crates/swc_ecma_minifier/tests/fixture/next/66237/output.js new file mode 100644 index 000000000000..12dd91ca7fde --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/next/66237/output.js @@ -0,0 +1,37 @@ +"use strict"; +(self.webpackChunk_N_E = self.webpackChunk_N_E || []).push([ + [ + 854 + ], + { + 3712: function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { + __webpack_require__.d(__webpack_exports__, { + $Q: function() { + return C; + }, + Ev: function() { + return B; + }, + e_: function() { + return I; + }, + jU: function() { + return e; + } + }); + try { + "u" > typeof Intl && Intl.v8BreakIterator; + } catch (e) {} + const e = ()=>"object" == typeof document && !!document, I = ()=>e() && document.documentElement.getAttribute("dir") || "ltr"; + function B(t, n, o) { + o ? t.setAttribute(n, o) : t.removeAttribute(n); + } + const d = new Map(); + function C(t) { + if (d.has(t.constructor)) return d.get(t.constructor); + for (const [o, i] of customElements.__definitions)if (i.ctor === t.constructor) return d.set(t.constructor, o), o; + throw Error("Given element ".concat(t.constructor.name, " has not been registered yet.")); + } + } + } +]); diff --git a/crates/swc_ecma_transforms_base/src/resolver/mod.rs b/crates/swc_ecma_transforms_base/src/resolver/mod.rs index f2e4e438e72c..0de61dc4b412 100644 --- a/crates/swc_ecma_transforms_base/src/resolver/mod.rs +++ b/crates/swc_ecma_transforms_base/src/resolver/mod.rs @@ -1969,15 +1969,7 @@ impl VisitMut for Hoister<'_, '_> { for item in stmts { match item { - Stmt::Decl(Decl::Var(v)) - if matches!( - &**v, - VarDecl { - kind: VarDeclKind::Var, - .. - } - ) => - { + Stmt::Decl(Decl::Var(..)) => { item.visit_mut_with(self); } Stmt::Decl(Decl::Fn(..)) => { diff --git a/crates/swc_ecma_transforms_base/tests/resolver/next-66237/input.js b/crates/swc_ecma_transforms_base/tests/resolver/next-66237/input.js new file mode 100644 index 000000000000..8f8d4d4c79d8 --- /dev/null +++ b/crates/swc_ecma_transforms_base/tests/resolver/next-66237/input.js @@ -0,0 +1,27 @@ +"use strict"; +(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([[854], { + +/***/ 3712: +/***/ (function (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ $Q: function () { return /* binding */ C; }, +/* harmony export */ Ev: function () { return /* binding */ B; }, +/* harmony export */ e_: function () { return /* binding */ I; }, +/* harmony export */ jU: function () { return /* binding */ e; } + /* harmony export */ +}); + /* unused harmony exports ACTION_ELEMENTS, SbbScrollHandler, breakpoints, findInput, findReferencedElement, hostContext, isAndroid, isBlink, isBreakpoint, isChromium, isEdge, isFirefox, isIOS, isNextjs, isSafari, isTrident, isWebkit, pageScrollDisabled */ + let a; + try { + a = typeof Intl < "u" && Intl.v8BreakIterator; + } catch (e) { + a = !1; + } + const e = () => typeof document == "object" && !!document, l = () => e() && /(edge)/i.test(navigator.userAgent), c = () => e() && /(msie|trident)/i.test(navigator.userAgent), y = () => e() && !!(window.chrome || a) && typeof CSS < "u" && !l() && !c(), g = () => e() && /AppleWebKit/i.test(navigator.userAgent) && !y() && !l() && !c(), w = () => e() && /iPad|iPhone|iPod/.test(navigator.userAgent) && !("MSStream" in window), v = () => e() && /(firefox|minefield)/i.test(navigator.userAgent), A = () => e() && /android/i.test(navigator.userAgent) && !c(), E = () => e() && /safari/i.test(navigator.userAgent) && g(), p = () => !!globalThis.next, S = () => { + var t, n; + return (n = (t = navigator.userAgentData) == null ? void 0 : t.brands) == null ? void 0 : n.some((o) => o.brand == "Chromium"); + } + }), + +}]); \ No newline at end of file diff --git a/crates/swc_ecma_transforms_base/tests/resolver/next-66237/output.js b/crates/swc_ecma_transforms_base/tests/resolver/next-66237/output.js new file mode 100644 index 000000000000..02abac0c3e52 --- /dev/null +++ b/crates/swc_ecma_transforms_base/tests/resolver/next-66237/output.js @@ -0,0 +1,34 @@ +"use strict"; +(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([ + [ + 854 + ], + { + 3712: function(__unused_webpack___webpack_module____3, __webpack_exports____3, __webpack_require____3) { + __webpack_require____3.d(__webpack_exports____3, { + $Q: function() { + return C; + }, + Ev: function() { + return B; + }, + e_: function() { + return I; + }, + jU: function() { + return e__3; + } + }); + let a__3; + try { + a__3 = typeof Intl < "u" && Intl.v8BreakIterator; + } catch (e__9) { + a__3 = !1; + } + const e__3 = ()=>typeof document == "object" && !!document, l__3 = ()=>e__3() && /(edge)/i.test(navigator.userAgent), c__3 = ()=>e__3() && /(msie|trident)/i.test(navigator.userAgent), y__3 = ()=>e__3() && !!(window.chrome || a__3) && typeof CSS < "u" && !l__3() && !c__3(), g__3 = ()=>e__3() && /AppleWebKit/i.test(navigator.userAgent) && !y__3() && !l__3() && !c__3(), w__3 = ()=>e__3() && /iPad|iPhone|iPod/.test(navigator.userAgent) && !("MSStream" in window), v__3 = ()=>e__3() && /(firefox|minefield)/i.test(navigator.userAgent), A__3 = ()=>e__3() && /android/i.test(navigator.userAgent) && !c__3(), E__3 = ()=>e__3() && /safari/i.test(navigator.userAgent) && g__3(), p__3 = ()=>!!globalThis.next, S__3 = ()=>{ + var t__10, n__10; + return (n__10 = (t__10 = navigator.userAgentData) == null ? void 0 : t__10.brands) == null ? void 0 : n__10.some((o__11)=>o__11.brand == "Chromium"); + }; + } + } +]);