Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(turbopack): Fix tree shaking with import * as R #74725

Merged
merged 35 commits into from
Jan 14, 2025
Merged

Conversation

kdy1
Copy link
Member

@kdy1 kdy1 commented Jan 10, 2025

What?

Fix tree shaking with import * as R from 'ramda'.

Why?

It's required

How?

Closes PACK-3684

@kdy1 kdy1 self-assigned this Jan 10, 2025
@ijjk ijjk added the created-by: Turbopack team PRs by the Turbopack team. label Jan 10, 2025
@ijjk
Copy link
Member

ijjk commented Jan 10, 2025

Failing test suites

Commit: f2bec0b

pnpm test-dev-turbo test/development/acceptance/ReactRefreshRequire.test.ts (turbopack)

  • ReactRefreshRequire > propagates a module that stops accepting in next version
Expand output

● ReactRefreshRequire › propagates a module that stops accepting in next version

expect(received).toEqual(expected) // deep equality

- Expected  - 0
+ Received  + 1

  Array [
    "init BarV1.1",
+   "init BarV1.1",
  ]

  399 |         `window.log.push('init BarV1.1'); export default function Bar() {};`
  400 |       ))
> 401 |     expect(await session.evaluate(() => (window as any).log)).toEqual([
      |                                                               ^
  402 |       'init BarV1.1',
  403 |     ])
  404 |

  at Object.toEqual (development/acceptance/ReactRefreshRequire.test.ts:401:63)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Jan 10, 2025

Stats from current PR

Default Build (Increase detected ⚠️)
General
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
buildDuration 17s 18.2s ⚠️ +1.2s
buildDurationCached 14.4s 11.8s N/A
nodeModulesSize 418 MB 416 MB N/A
nextStartRea..uration (ms) 418ms 415ms N/A
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
5306-HASH.js gzip 53.9 kB 53.3 kB N/A
8276.HASH.js gzip 169 B 168 B N/A
8377-HASH.js gzip 5.44 kB 5.44 kB N/A
bccd1874-HASH.js gzip 52.9 kB 53 kB ⚠️ +102 B
framework-HASH.js gzip 57.5 kB 57.5 kB N/A
main-app-HASH.js gzip 238 B 242 B N/A
main-HASH.js gzip 34.2 kB 34.1 kB N/A
webpack-HASH.js gzip 1.71 kB 1.71 kB N/A
Overall change 52.9 kB 53 kB ⚠️ +102 B
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Overall change 39.4 kB 39.4 kB
Client Pages
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
_app-HASH.js gzip 193 B 193 B
_error-HASH.js gzip 193 B 193 B
amp-HASH.js gzip 512 B 510 B N/A
css-HASH.js gzip 343 B 342 B N/A
dynamic-HASH.js gzip 1.84 kB 1.84 kB
edge-ssr-HASH.js gzip 265 B 265 B
head-HASH.js gzip 363 B 362 B N/A
hooks-HASH.js gzip 393 B 392 B N/A
image-HASH.js gzip 4.57 kB 4.57 kB N/A
index-HASH.js gzip 268 B 268 B
link-HASH.js gzip 2.35 kB 2.34 kB N/A
routerDirect..HASH.js gzip 328 B 328 B
script-HASH.js gzip 397 B 397 B
withRouter-HASH.js gzip 323 B 326 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 3.59 kB 3.59 kB
Client Build Manifests
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
_buildManifest.js gzip 749 B 747 B N/A
Overall change 0 B 0 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
index.html gzip 524 B 521 B N/A
link.html gzip 539 B 535 B N/A
withRouter.html gzip 520 B 518 B N/A
Overall change 0 B 0 B
Edge SSR bundle Size
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
edge-ssr.js gzip 129 kB 128 kB N/A
page.js gzip 208 kB 207 kB N/A
Overall change 0 B 0 B
Middleware size
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
middleware-b..fest.js gzip 669 B 667 B N/A
middleware-r..fest.js gzip 155 B 156 B N/A
middleware.js gzip 31.3 kB 31.2 kB N/A
edge-runtime..pack.js gzip 844 B 844 B
Overall change 844 B 844 B
Next Runtimes Overall increase ⚠️
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
274-experime...dev.js gzip 322 B 322 B
274.runtime.dev.js gzip 314 B 314 B
app-page-exp...dev.js gzip 373 kB 367 kB N/A
app-page-exp..prod.js gzip 130 kB 129 kB N/A
app-page-tur..prod.js gzip 143 kB 142 kB N/A
app-page-tur..prod.js gzip 139 kB 138 kB N/A
app-page.run...dev.js gzip 361 kB 355 kB N/A
app-page.run..prod.js gzip 126 kB 126 kB N/A
app-route-ex...dev.js gzip 37.6 kB 37.6 kB N/A
app-route-ex..prod.js gzip 25.6 kB 25.6 kB N/A
app-route-tu..prod.js gzip 25.6 kB 25.6 kB N/A
app-route-tu..prod.js gzip 25.4 kB 25.4 kB N/A
app-route.ru...dev.js gzip 39.2 kB 39.2 kB N/A
app-route.ru..prod.js gzip 25.4 kB 25.4 kB N/A
pages-api-tu..prod.js gzip 9.69 kB 9.69 kB
pages-api.ru...dev.js gzip 11.6 kB 11.6 kB
pages-api.ru..prod.js gzip 9.68 kB 9.68 kB
pages-turbo...prod.js gzip 21.7 kB 21.7 kB
pages.runtim...dev.js gzip 27.5 kB 27.5 kB
pages.runtim..prod.js gzip 21.7 kB 21.7 kB
server.runti..prod.js gzip 916 kB 916 kB ⚠️ +362 B
Overall change 1.02 MB 1.02 MB ⚠️ +362 B
build cache Overall increase ⚠️
vercel/next.js canary vercel/next.js kdy1/pack-3684 Change
0.pack gzip 2.09 MB 2.09 MB N/A
index.pack gzip 74.9 kB 75.7 kB ⚠️ +723 B
Overall change 74.9 kB 75.7 kB ⚠️ +723 B
Diff details
Diff for page.js

Diff too large to display

Diff for middleware.js

Diff too large to display

Diff for edge-ssr.js

Diff too large to display

Diff for 5306-HASH.js

Diff too large to display

Diff for bccd1874-HASH.js
@@ -1,13 +1,13 @@
 "use strict";
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
-  [7629],
+  [1758],
   {
-    /***/ 641: /***/ (
+    /***/ 8699: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
     ) => {
-      /* provided dependency */ var process = __webpack_require__(6611);
+      /* provided dependency */ var process = __webpack_require__(9829);
       /**
        * @license React
        * react-dom-client.production.js
@@ -22,9 +22,9 @@
  Modernizr 3.0.0pre (Custom Build) | MIT
 */
 
-      var Scheduler = __webpack_require__(8684),
-        React = __webpack_require__(1446),
-        ReactDOM = __webpack_require__(8307);
+      var Scheduler = __webpack_require__(462),
+        React = __webpack_require__(228),
+        ReactDOM = __webpack_require__(9221);
       function formatProdErrorMessage(code) {
         var url = "https://react.dev/errors/" + code;
         if (1 < arguments.length) {
@@ -2086,14 +2086,14 @@
       if (canUseDOM) {
         var JSCompiler_inline_result$jscomp$279;
         if (canUseDOM) {
-          var isSupported$jscomp$inline_414 = "oninput" in document;
-          if (!isSupported$jscomp$inline_414) {
-            var element$jscomp$inline_415 = document.createElement("div");
-            element$jscomp$inline_415.setAttribute("oninput", "return;");
-            isSupported$jscomp$inline_414 =
-              "function" === typeof element$jscomp$inline_415.oninput;
+          var isSupported$jscomp$inline_410 = "oninput" in document;
+          if (!isSupported$jscomp$inline_410) {
+            var element$jscomp$inline_411 = document.createElement("div");
+            element$jscomp$inline_411.setAttribute("oninput", "return;");
+            isSupported$jscomp$inline_410 =
+              "function" === typeof element$jscomp$inline_411.oninput;
           }
-          JSCompiler_inline_result$jscomp$279 = isSupported$jscomp$inline_414;
+          JSCompiler_inline_result$jscomp$279 = isSupported$jscomp$inline_410;
         } else JSCompiler_inline_result$jscomp$279 = !1;
         isInputEventSupported =
           JSCompiler_inline_result$jscomp$279 &&
@@ -2361,25 +2361,6 @@
         topLevelEventsToReactNames.set(domEventName, reactName);
         registerTwoPhaseEvent(reactName, [domEventName]);
       }
-      var CapturedStacks = new WeakMap();
-      function createCapturedValueAtFiber(value, source) {
-        if ("object" === typeof value && null !== value) {
-          var existing = CapturedStacks.get(value);
-          if (void 0 !== existing) return existing;
-          source = {
-            value: value,
-            source: source,
-            stack: getStackByFiberInDevAndProd(source),
-          };
-          CapturedStacks.set(value, source);
-          return source;
-        }
-        return {
-          value: value,
-          source: source,
-          stack: getStackByFiberInDevAndProd(source),
-        };
-      }
       var concurrentQueues = [],
         concurrentQueuesIndex = 0,
         concurrentlyUpdatedLanes = 0;
@@ -3007,6 +2988,265 @@
             cache.controller.abort();
           });
       }
+      var CapturedStacks = new WeakMap();
+      function createCapturedValueAtFiber(value, source) {
+        if ("object" === typeof value && null !== value) {
+          var existing = CapturedStacks.get(value);
+          if (void 0 !== existing) return existing;
+          source = {
+            value: value,
+            source: source,
+            stack: getStackByFiberInDevAndProd(source),
+          };
+          CapturedStacks.set(value, source);
+          return source;
+        }
+        return {
+          value: value,
+          source: source,
+          stack: getStackByFiberInDevAndProd(source),
+        };
+      }
+      var forkStack = [],
+        forkStackIndex = 0,
+        treeForkProvider = null,
+        treeForkCount = 0,
+        idStack = [],
+        idStackIndex = 0,
+        treeContextProvider = null,
+        treeContextId = 1,
+        treeContextOverflow = "";
+      function pushTreeFork(workInProgress, totalChildren) {
+        forkStack[forkStackIndex++] = treeForkCount;
+        forkStack[forkStackIndex++] = treeForkProvider;
+        treeForkProvider = workInProgress;
+        treeForkCount = totalChildren;
+      }
+      function pushTreeId(workInProgress, totalChildren, index) {
+        idStack[idStackIndex++] = treeContextId;
+        idStack[idStackIndex++] = treeContextOverflow;
+        idStack[idStackIndex++] = treeContextProvider;
+        treeContextProvider = workInProgress;
+        var baseIdWithLeadingBit = treeContextId;
+        workInProgress = treeContextOverflow;
+        var baseLength = 32 - clz32(baseIdWithLeadingBit) - 1;
+        baseIdWithLeadingBit &= ~(1 << baseLength);
+        index += 1;
+        var length = 32 - clz32(totalChildren) + baseLength;
+        if (30 < length) {
+          var numberOfOverflowBits = baseLength - (baseLength % 5);
+          length = (
+            baseIdWithLeadingBit &
+            ((1 << numberOfOverflowBits) - 1)
+          ).toString(32);
+          baseIdWithLeadingBit >>= numberOfOverflowBits;
+          baseLength -= numberOfOverflowBits;
+          treeContextId =
+            (1 << (32 - clz32(totalChildren) + baseLength)) |
+            (index << baseLength) |
+            baseIdWithLeadingBit;
+          treeContextOverflow = length + workInProgress;
+        } else
+          (treeContextId =
+            (1 << length) | (index << baseLength) | baseIdWithLeadingBit),
+            (treeContextOverflow = workInProgress);
+      }
+      function pushMaterializedTreeId(workInProgress) {
+        null !== workInProgress.return &&
+          (pushTreeFork(workInProgress, 1), pushTreeId(workInProgress, 1, 0));
+      }
+      function popTreeContext(workInProgress) {
+        for (; workInProgress === treeForkProvider; )
+          (treeForkProvider = forkStack[--forkStackIndex]),
+            (forkStack[forkStackIndex] = null),
+            (treeForkCount = forkStack[--forkStackIndex]),
+            (forkStack[forkStackIndex] = null);
+        for (; workInProgress === treeContextProvider; )
+          (treeContextProvider = idStack[--idStackIndex]),
+            (idStack[idStackIndex] = null),
+            (treeContextOverflow = idStack[--idStackIndex]),
+            (idStack[idStackIndex] = null),
+            (treeContextId = idStack[--idStackIndex]),
+            (idStack[idStackIndex] = null);
+      }
+      var hydrationParentFiber = null,
+        nextHydratableInstance = null,
+        isHydrating = !1,
+        hydrationErrors = null,
+        rootOrSingletonContext = !1,
+        HydrationMismatchException = Error(formatProdErrorMessage(519));
+      function throwOnHydrationMismatch(fiber) {
+        var error = Error(formatProdErrorMessage(418, ""));
+        queueHydrationError(createCapturedValueAtFiber(error, fiber));
+        throw HydrationMismatchException;
+      }
+      function prepareToHydrateHostInstance(fiber) {
+        var instance = fiber.stateNode,
+          type = fiber.type,
+          props = fiber.memoizedProps;
+        instance[internalInstanceKey] = fiber;
+        instance[internalPropsKey] = props;
+        switch (type) {
+          case "dialog":
+            listenToNonDelegatedEvent("cancel", instance);
+            listenToNonDelegatedEvent("close", instance);
+            break;
+          case "iframe":
+          case "object":
+          case "embed":
+            listenToNonDelegatedEvent("load", instance);
+            break;
+          case "video":
+          case "audio":
+            for (type = 0; type < mediaEventTypes.length; type++)
+              listenToNonDelegatedEvent(mediaEventTypes[type], instance);
+            break;
+          case "source":
+            listenToNonDelegatedEvent("error", instance);
+            break;
+          case "img":
+          case "image":
+          case "link":
+            listenToNonDelegatedEvent("error", instance);
+            listenToNonDelegatedEvent("load", instance);
+            break;
+          case "details":
+            listenToNonDelegatedEvent("toggle", instance);
+            break;
+          case "input":
+            listenToNonDelegatedEvent("invalid", instance);
+            initInput(
+              instance,
+              props.value,
+              props.defaultValue,
+              props.checked,
+              props.defaultChecked,
+              props.type,
+              props.name,
+              !0
+            );
+            track(instance);
+            break;
+          case "select":
+            listenToNonDelegatedEvent("invalid", instance);
+            break;
+          case "textarea":
+            listenToNonDelegatedEvent("invalid", instance),
+              initTextarea(
+                instance,
+                props.value,
+                props.defaultValue,
+                props.children
+              ),
+              track(instance);
+        }
+        type = props.children;
+        ("string" !== typeof type &&
+          "number" !== typeof type &&
+          "bigint" !== typeof type) ||
+        instance.textContent === "" + type ||
+        !0 === props.suppressHydrationWarning ||
+        checkForUnmatchedText(instance.textContent, type)
+          ? (null != props.popover &&
+              (listenToNonDelegatedEvent("beforetoggle", instance),
+              listenToNonDelegatedEvent("toggle", instance)),
+            null != props.onScroll &&
+              listenToNonDelegatedEvent("scroll", instance),
+            null != props.onScrollEnd &&
+              listenToNonDelegatedEvent("scrollend", instance),
+            null != props.onClick && (instance.onclick = noop$1),
+            (instance = !0))
+          : (instance = !1);
+        instance || throwOnHydrationMismatch(fiber);
+      }
+      function popToNextHostParent(fiber) {
+        for (hydrationParentFiber = fiber.return; hydrationParentFiber; )
+          switch (hydrationParentFiber.tag) {
+            case 3:
+            case 27:
+              rootOrSingletonContext = !0;
+              return;
+            case 5:
+            case 13:
+              rootOrSingletonContext = !1;
+              return;
+            default:
+              hydrationParentFiber = hydrationParentFiber.return;
+          }
+      }
+      function popHydrationState(fiber) {
+        if (fiber !== hydrationParentFiber) return !1;
+        if (!isHydrating)
+          return popToNextHostParent(fiber), (isHydrating = !0), !1;
+        var shouldClear = !1,
+          JSCompiler_temp;
+        if ((JSCompiler_temp = 3 !== fiber.tag && 27 !== fiber.tag)) {
+          if ((JSCompiler_temp = 5 === fiber.tag))
+            (JSCompiler_temp = fiber.type),
+              (JSCompiler_temp =
+                !("form" !== JSCompiler_temp && "button" !== JSCompiler_temp) ||
+                shouldSetTextContent(fiber.type, fiber.memoizedProps));
+          JSCompiler_temp = !JSCompiler_temp;
+        }
+        JSCompiler_temp && (shouldClear = !0);
+        shouldClear &&
+          nextHydratableInstance &&
+          throwOnHydrationMismatch(fiber);
+        popToNextHostParent(fiber);
+        if (13 === fiber.tag) {
+          fiber = fiber.memoizedState;
+          fiber = null !== fiber ? fiber.dehydrated : null;
+          if (!fiber) throw Error(formatProdErrorMessage(317));
+          a: {
+            fiber = fiber.nextSibling;
+            for (shouldClear = 0; fiber; ) {
+              if (8 === fiber.nodeType)
+                if (
+                  ((JSCompiler_temp = fiber.data), "/$" === JSCompiler_temp)
+                ) {
+                  if (0 === shouldClear) {
+                    nextHydratableInstance = getNextHydratable(
+                      fiber.nextSibling
+                    );
+                    break a;
+                  }
+                  shouldClear--;
+                } else
+                  ("$" !== JSCompiler_temp &&
+                    "$!" !== JSCompiler_temp &&
+                    "$?" !== JSCompiler_temp) ||
+                    shouldClear++;
+              fiber = fiber.nextSibling;
+            }
+            nextHydratableInstance = null;
+          }
+        } else
+          nextHydratableInstance = hydrationParentFiber
+            ? getNextHydratable(fiber.stateNode.nextSibling)
+            : null;
+        return !0;
+      }
+      function resetHydrationState() {
+        nextHydratableInstance = hydrationParentFiber = null;
+        isHydrating = !1;
+      }
+      function upgradeHydrationErrorsToRecoverable() {
+        var queuedErrors = hydrationErrors;
+        null !== queuedErrors &&
+          (null === workInProgressRootRecoverableErrors
+            ? (workInProgressRootRecoverableErrors = queuedErrors)
+            : workInProgressRootRecoverableErrors.push.apply(
+                workInProgressRootRecoverableErrors,
+                queuedErrors
+              ),
+          (hydrationErrors = null));
+        return queuedErrors;
+      }
+      function queueHydrationError(error) {
+        null === hydrationErrors
+          ? (hydrationErrors = [error])
+          : hydrationErrors.push(error);
+      }
       function applyDerivedStateFromProps(
         workInProgress,
         ctor,
@@ -3114,74 +3354,12 @@
         }
         if ((Component = Component.defaultProps)) {
           newProps === baseProps && (newProps = assign({}, newProps));
-          for (var propName$28 in Component)
-            void 0 === newProps[propName$28] &&
-              (newProps[propName$28] = Component[propName$28]);
+          for (var propName$30 in Component)
+            void 0 === newProps[propName$30] &&
+              (newProps[propName$30] = Component[propName$30]);
         }
         return newProps;
       }
-      var forkStack = [],
-        forkStackIndex = 0,
-        treeForkProvider = null,
-        treeForkCount = 0,
-        idStack = [],
-        idStackIndex = 0,
-        treeContextProvider = null,
-        treeContextId = 1,
-        treeContextOverflow = "";
-      function pushTreeFork(workInProgress, totalChildren) {
-        forkStack[forkStackIndex++] = treeForkCount;
-        forkStack[forkStackIndex++] = treeForkProvider;
-        treeForkProvider = workInProgress;
-        treeForkCount = totalChildren;
-      }
-      function pushTreeId(workInProgress, totalChildren, index) {
-        idStack[idStackIndex++] = treeContextId;
-        idStack[idStackIndex++] = treeContextOverflow;
-        idStack[idStackIndex++] = treeContextProvider;
-        treeContextProvider = workInProgress;
-        var baseIdWithLeadingBit = treeContextId;
-        workInProgress = treeContextOverflow;
-        var baseLength = 32 - clz32(baseIdWithLeadingBit) - 1;
-        baseIdWithLeadingBit &= ~(1 << baseLength);
-        index += 1;
-        var length = 32 - clz32(totalChildren) + baseLength;
-        if (30 < length) {
-          var numberOfOverflowBits = baseLength - (baseLength % 5);
-          length = (
-            baseIdWithLeadingBit &
-            ((1 << numberOfOverflowBits) - 1)
-          ).toString(32);
-          baseIdWithLeadingBit >>= numberOfOverflowBits;
-          baseLength -= numberOfOverflowBits;
-          treeContextId =
-            (1 << (32 - clz32(totalChildren) + baseLength)) |
-            (index << baseLength) |
-            baseIdWithLeadingBit;
-          treeContextOverflow = length + workInProgress;
-        } else
-          (treeContextId =
-            (1 << length) | (index << baseLength) | baseIdWithLeadingBit),
-            (treeContextOverflow = workInProgress);
-      }
-      function pushMaterializedTreeId(workInProgress) {
-        null !== workInProgress.return &&
-          (pushTreeFork(workInProgress, 1), pushTreeId(workInProgress, 1, 0));
-      }
-      function popTreeContext(workInProgress) {
-        for (; workInProgress === treeForkProvider; )
-          (treeForkProvider = forkStack[--forkStackIndex]),
-            (forkStack[forkStackIndex] = null),
-            (treeForkCount = forkStack[--forkStackIndex]),
-            (forkStack[forkStackIndex] = null);
-        for (; workInProgress === treeContextProvider; )
-          (treeContextProvider = idStack[--idStackIndex]),
-            (idStack[idStackIndex] = null),
-            (treeContextOverflow = idStack[--idStackIndex]),
-            (idStack[idStackIndex] = null),
-            (treeContextId = idStack[--idStackIndex]),
-            (idStack[idStackIndex] = null);
-      }
       var SuspenseException = Error(formatProdErrorMessage(460)),
         SuspenseyCommitException = Error(formatProdErrorMessage(474)),
         SuspenseActionException = Error(formatProdErrorMessage(542)),
@@ -7446,17 +7624,14 @@
               workInProgress.child
             );
           case 5:
-            return (
-              null === current &&
-                isHydrating &&
-                ((lazyComponent = nextHydratableInstance),
-                (init = !lazyComponent) ||
-                  ((lazyComponent = canHydrateInstance(
-                    lazyComponent,
-                    workInProgress.type,
-                    workInProgress.pendingProps,
-                    rootOrSingletonContext
-                  )),
+            if (null === current && isHydrating) {
+              if ((init = lazyComponent = nextHydratableInstance))
+                (lazyComponent = canHydrateInstance(
+                  lazyComponent,
+                  workInProgress.type,
+                  workInProgress.pendingProps,
+                  rootOrSingletonContext
+                )),
                   null !== lazyComponent
                     ? ((workInProgress.stateNode = lazyComponent),
                       (hydrationParentFiber = workInProgress),
@@ -7464,60 +7639,55 @@
                         lazyComponent.firstChild
                       )),
                       (rootOrSingletonContext = !1),
-                      (lazyComponent = !0))
-                    : (lazyComponent = !1),
-                  (init = !lazyComponent)),
-                init && throwOnHydrationMismatch(workInProgress)),
-              pushHostContext(workInProgress),
-              (init = workInProgress.type),
-              (nextProps = workInProgress.pendingProps),
-              (nextState = null !== current ? current.memoizedProps : null),
-              (lazyComponent = nextProps.children),
-              shouldSetTextContent(init, nextProps)
-                ? (lazyComponent = null)
-                : null !== nextState &&
-                  shouldSetTextContent(init, nextState) &&
-                  (workInProgress.flags |= 32),
-              null !== workInProgress.memoizedState &&
-                ((init = renderWithHooks(
-                  current,
-                  workInProgress,
-                  TransitionAwareHostComponent,
-                  null,
-                  null,
-                  renderLanes
-                )),
-                (HostTransitionContext._currentValue = init)),
-              markRef(current, workInProgress),
-              reconcileChildren(
+                      (init = !0))
+                    : (init = !1);
+              init || throwOnHydrationMismatch(workInProgress);
+            }
+            pushHostContext(workInProgress);
+            init = workInProgress.type;
+            nextProps = workInProgress.pendingProps;
+            nextState = null !== current ? current.memoizedProps : null;
+            lazyComponent = nextProps.children;
+            shouldSetTextContent(init, nextProps)
+              ? (lazyComponent = null)
+              : null !== nextState &&
+                shouldSetTextContent(init, nextState) &&
+                (workInProgress.flags |= 32);
+            null !== workInProgress.memoizedState &&
+              ((init = renderWithHooks(
                 current,
                 workInProgress,
-                lazyComponent,
+                TransitionAwareHostComponent,
+                null,
+                null,
                 renderLanes
-              ),
-              workInProgress.child
+              )),
+              (HostTransitionContext._currentValue = init));
+            markRef(current, workInProgress);
+            reconcileChildren(
+              current,
+              workInProgress,
+              lazyComponent,
+              renderLanes
             );
+            return workInProgress.child;
           case 6:
-            return (
-              null === current &&
-                isHydrating &&
-                ((renderLanes = nextHydratableInstance),
-                (current = !renderLanes) ||
-                  ((renderLanes = canHydrateTextInstance(
-                    renderLanes,
-                    workInProgress.pendingProps,
-                    rootOrSingletonContext
-                  )),
+            if (null === current && isHydrating) {
+              if ((current = renderLanes = nextHydratableInstance))
+                (renderLanes = canHydrateTextInstance(
+                  renderLanes,
+                  workInProgress.pendingProps,
+                  rootOrSingletonContext
+                )),
                   null !== renderLanes
                     ? ((workInProgress.stateNode = renderLanes),
                       (hydrationParentFiber = workInProgress),
                       (nextHydratableInstance = null),
-                      (renderLanes = !0))
-                    : (renderLanes = !1),
-                  (current = !renderLanes)),
-                current && throwOnHydrationMismatch(workInProgress)),
-              null
-            );
+                      (current = !0))
+                    : (current = !1);
+              current || throwOnHydrationMismatch(workInProgress);
+            }
+            return null;
           case 13:
             return updateSuspenseComponent(
               current,
@@ -7790,14 +7960,15 @@
         try {
           var ref = current.ref;
           if (null !== ref) {
+            var instance = current.stateNode;
             switch (current.tag) {
               case 26:
               case 27:
               case 5:
-                var instanceToUse = current.stateNode;
+                var instanceToUse = instance;
                 break;
               default:
-                instanceToUse = current.stateNode;
+                instanceToUse = instance;
             }
             "function" === typeof ref
               ? (current.refCleanup = ref(instanceToUse))
@@ -9985,184 +10156,6 @@
         };
         return mode;
       }
-      var hydrationParentFiber = null,
-        nextHydratableInstance = null,
-        isHydrating = !1,
-        hydrationErrors = null,
-        rootOrSingletonContext = !1,
-        HydrationMismatchException = Error(formatProdErrorMessage(519));
-      function throwOnHydrationMismatch(fiber) {
-        var error = Error(formatProdErrorMessage(418, ""));
-        queueHydrationError(createCapturedValueAtFiber(error, fiber));
-        throw HydrationMismatchException;
-      }
-      function prepareToHydrateHostInstance(fiber) {
-        var instance = fiber.stateNode,
-          type = fiber.type,
-          props = fiber.memoizedProps;
-        instance[internalInstanceKey] = fiber;
-        instance[internalPropsKey] = props;
-        switch (type) {
-          case "dialog":
-            listenToNonDelegatedEvent("cancel", instance);
-            listenToNonDelegatedEvent("close", instance);
-            break;
-          case "iframe":
-          case "object":
-          case "embed":
-            listenToNonDelegatedEvent("load", instance);
-            break;
-          case "video":
-          case "audio":
-            for (type = 0; type < mediaEventTypes.length; type++)
-              listenToNonDelegatedEvent(mediaEventTypes[type], instance);
-            break;
-          case "source":
-            listenToNonDelegatedEvent("error", instance);
-            break;
-          case "img":
-          case "image":
-          case "link":
-            listenToNonDelegatedEvent("error", instance);
-            listenToNonDelegatedEvent("load", instance);
-            break;
-          case "details":
-            listenToNonDelegatedEvent("toggle", instance);
-            break;
-          case "input":
-            listenToNonDelegatedEvent("invalid", instance);
-            initInput(
-              instance,
-              props.value,
-              props.defaultValue,
-              props.checked,
-              props.defaultChecked,
-              props.type,
-              props.name,
-              !0
-            );
-            track(instance);
-            break;
-          case "select":
-            listenToNonDelegatedEvent("invalid", instance);
-            break;
-          case "textarea":
-            listenToNonDelegatedEvent("invalid", instance),
-              initTextarea(
-                instance,
-                props.value,
-                props.defaultValue,
-                props.children
-              ),
-              track(instance);
-        }
-        type = props.children;
-        ("string" !== typeof type &&
-          "number" !== typeof type &&
-          "bigint" !== typeof type) ||
-        instance.textContent === "" + type ||
-        !0 === props.suppressHydrationWarning ||
-        checkForUnmatchedText(instance.textContent, type)
-          ? (null != props.popover &&
-              (listenToNonDelegatedEvent("beforetoggle", instance),
-              listenToNonDelegatedEvent("toggle", instance)),
-            null != props.onScroll &&
-              listenToNonDelegatedEvent("scroll", instance),
-            null != props.onScrollEnd &&
-              listenToNonDelegatedEvent("scrollend", instance),
-            null != props.onClick && (instance.onclick = noop$1),
-            (instance = !0))
-          : (instance = !1);
-        instance || throwOnHydrationMismatch(fiber);
-      }
-      function popToNextHostParent(fiber) {
-        for (hydrationParentFiber = fiber.return; hydrationParentFiber; )
-          switch (hydrationParentFiber.tag) {
-            case 3:
-            case 27:
-              rootOrSingletonContext = !0;
-              return;
-            case 5:
-            case 13:
-              rootOrSingletonContext = !1;
-              return;
-            default:
-              hydrationParentFiber = hydrationParentFiber.return;
-          }
-      }
-      function popHydrationState(fiber) {
-        if (fiber !== hydrationParentFiber) return !1;
-        if (!isHydrating)
-          return popToNextHostParent(fiber), (isHydrating = !0), !1;
-        var shouldClear = !1,
-          JSCompiler_temp;
-        if ((JSCompiler_temp = 3 !== fiber.tag && 27 !== fiber.tag)) {
-          if ((JSCompiler_temp = 5 === fiber.tag))
-            (JSCompiler_temp = fiber.type),
-              (JSCompiler_temp =
-                !("form" !== JSCompiler_temp && "button" !== JSCompiler_temp) ||
-                shouldSetTextContent(fiber.type, fiber.memoizedProps));
-          JSCompiler_temp = !JSCompiler_temp;
-        }
-        JSCompiler_temp && (shouldClear = !0);
-        shouldClear &&
-          nextHydratableInstance &&
-          throwOnHydrationMismatch(fiber);
-        popToNextHostParent(fiber);
-        if (13 === fiber.tag) {
-          fiber = fiber.memoizedState;
-          fiber = null !== fiber ? fiber.dehydrated : null;
-          if (!fiber) throw Error(formatProdErrorMessage(317));
-          a: {
-            fiber = fiber.nextSibling;
-            for (shouldClear = 0; fiber; ) {
-              if (8 === fiber.nodeType)
-                if (
-                  ((JSCompiler_temp = fiber.data), "/$" === JSCompiler_temp)
-                ) {
-                  if (0 === shouldClear) {
-                    nextHydratableInstance = getNextHydratable(
-                      fiber.nextSibling
-                    );
-                    break a;
-                  }
-                  shouldClear--;
-                } else
-                  ("$" !== JSCompiler_temp &&
-                    "$!" !== JSCompiler_temp &&
-                    "$?" !== JSCompiler_temp) ||
-                    shouldClear++;
-              fiber = fiber.nextSibling;
-            }
-            nextHydratableInstance = null;
-          }
-        } else
-          nextHydratableInstance = hydrationParentFiber
-            ? getNextHydratable(fiber.stateNode.nextSibling)
-            : null;
-        return !0;
-      }
-      function resetHydrationState() {
-        nextHydratableInstance = hydrationParentFiber = null;
-        isHydrating = !1;
-      }
-      function upgradeHydrationErrorsToRecoverable() {
-        var queuedErrors = hydrationErrors;
-        null !== queuedErrors &&
-          (null === workInProgressRootRecoverableErrors
-            ? (workInProgressRootRecoverableErrors = queuedErrors)
-            : workInProgressRootRecoverableErrors.push.apply(
-                workInProgressRootRecoverableErrors,
-                queuedErrors
-              ),
-          (hydrationErrors = null));
-        return queuedErrors;
-      }
-      function queueHydrationError(error) {
-        null === hydrationErrors
-          ? (hydrationErrors = [error])
-          : hydrationErrors.push(error);
-      }
       function markUpdate(workInProgress) {
         workInProgress.flags |= 4;
       }
@@ -12508,20 +12501,20 @@
         }
       }
       for (
-        var i$jscomp$inline_1490 = 0;
-        i$jscomp$inline_1490 < simpleEventPluginEvents.length;
-        i$jscomp$inline_1490++
+        var i$jscomp$inline_1474 = 0;
+        i$jscomp$inline_1474 < simpleEventPluginEvents.length;
+        i$jscomp$inline_1474++
       ) {
-        var eventName$jscomp$inline_1491 =
-            simpleEventPluginEvents[i$jscomp$inline_1490],
-          domEventName$jscomp$inline_1492 =
-            eventName$jscomp$inline_1491.toLowerCase(),
-          capitalizedEvent$jscomp$inline_1493 =
-            eventName$jscomp$inline_1491[0].toUpperCase() +
-            eventName$jscomp$inline_1491.slice(1);
+        var eventName$jscomp$inline_1475 =
+            simpleEventPluginEvents[i$jscomp$inline_1474],
+          domEventName$jscomp$inline_1476 =
+            eventName$jscomp$inline_1475.toLowerCase(),
+          capitalizedEvent$jscomp$inline_1477 =
+            eventName$jscomp$inline_1475[0].toUpperCase() +
+            eventName$jscomp$inline_1475.slice(1);
         registerSimpleEvent(
-          domEventName$jscomp$inline_1492,
-          "on" + capitalizedEvent$jscomp$inline_1493
+          domEventName$jscomp$inline_1476,
+          "on" + capitalizedEvent$jscomp$inline_1477
         );
       }
       registerSimpleEvent(ANIMATION_END, "onAnimationEnd");
@@ -16207,16 +16200,16 @@
           0 === i && attemptExplicitHydrationTarget(target);
         }
       };
-      var isomorphicReactPackageVersion$jscomp$inline_1737 = React.version;
+      var isomorphicReactPackageVersion$jscomp$inline_1721 = React.version;
       if (
-        "19.1.0-canary-b3a95caf-20250113" !==
-        isomorphicReactPackageVersion$jscomp$inline_1737
+        "19.1.0-canary-74ea0c73-20250109" !==
+        isomorphicReactPackageVersion$jscomp$inline_1721
       )
         throw Error(
           formatProdErrorMessage(
             527,
-            isomorphicReactPackageVersion$jscomp$inline_1737,
-            "19.1.0-canary-b3a95caf-20250113"
+            isomorphicReactPackageVersion$jscomp$inline_1721,
+            "19.1.0-canary-74ea0c73-20250109"
           )
         );
       ReactDOMSharedInternals.findDOMNode = function (componentOrElement) {
@@ -16236,24 +16229,24 @@
           null === componentOrElement ? null : componentOrElement.stateNode;
         return componentOrElement;
       };
-      var internals$jscomp$inline_2214 = {
+      var internals$jscomp$inline_2190 = {
         bundleType: 0,
-        version: "19.1.0-canary-b3a95caf-20250113",
+        version: "19.1.0-canary-74ea0c73-20250109",
         rendererPackageName: "react-dom",
         currentDispatcherRef: ReactSharedInternals,
-        reconcilerVersion: "19.1.0-canary-b3a95caf-20250113",
+        reconcilerVersion: "19.1.0-canary-74ea0c73-20250109",
       };
       if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
-        var hook$jscomp$inline_2215 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
+        var hook$jscomp$inline_2191 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
         if (
-          !hook$jscomp$inline_2215.isDisabled &&
-          hook$jscomp$inline_2215.supportsFiber
+          !hook$jscomp$inline_2191.isDisabled &&
+          hook$jscomp$inline_2191.supportsFiber
         )
           try {
-            (rendererID = hook$jscomp$inline_2215.inject(
-              internals$jscomp$inline_2214
+            (rendererID = hook$jscomp$inline_2191.inject(
+              internals$jscomp$inline_2190
             )),
-              (injectedHook = hook$jscomp$inline_2215);
+              (injectedHook = hook$jscomp$inline_2191);
           } catch (err) {}
       }
       exports.createRoot = function (container, options) {
@@ -16351,7 +16344,7 @@
         listenToAllSupportedEvents(container);
         return new ReactDOMHydrationRoot(initialChildren);
       };
-      exports.version = "19.1.0-canary-b3a95caf-20250113";
+      exports.version = "19.1.0-canary-74ea0c73-20250109";
 
       /***/
     },
Diff for main-HASH.js

Diff too large to display

Diff for app-page-exp..ntime.dev.js
failed to diff
Diff for app-page-exp..time.prod.js

Diff too large to display

Diff for app-page-tur..time.prod.js

Diff too large to display

Diff for app-page-tur..time.prod.js

Diff too large to display

Diff for app-page.runtime.dev.js
failed to diff
Diff for app-page.runtime.prod.js

Diff too large to display

Diff for app-route-ex..ntime.dev.js

Diff too large to display

Diff for app-route-ex..time.prod.js

Diff too large to display

Diff for app-route-tu..time.prod.js

Diff too large to display

Diff for app-route-tu..time.prod.js

Diff too large to display

Diff for app-route.runtime.dev.js

Diff too large to display

Diff for app-route.ru..time.prod.js

Diff too large to display

Diff for server.runtime.prod.js
failed to diff
Commit: f2bec0b

@kdy1 kdy1 changed the title fix(turbopack): Fix tree shaking with import * fix(turbopack): Fix tree shaking with import * as R Jan 10, 2025
@kdy1 kdy1 marked this pull request as ready for review January 10, 2025 20:19
@kdy1 kdy1 requested a review from sokra January 10, 2025 20:19
@mischnic
Copy link
Contributor

mischnic commented Jan 10, 2025

We could also do it the other way around by instead creating the correct Effect::ImportedBinding in the analyzer

diff --git turbopack/crates/turbopack-ecmascript/src/analyzer/graph.rs turbopack/crates/turbopack-ecmascript/src/analyzer/graph.rs
index 7d3bc58036..14234da3dd 100644
--- turbopack/crates/turbopack-ecmascript/src/analyzer/graph.rs
+++ turbopack/crates/turbopack-ecmascript/src/analyzer/graph.rs
@@ -328,6 +328,14 @@ impl EvalContext {
         }
     }
 
+    fn eval_member_prop(&self, prop: &MemberProp) -> Option<JsValue> {
+        match prop {
+            MemberProp::Ident(ident) => Some(ident.sym.clone().into()),
+            MemberProp::Computed(ComputedPropName { expr, .. }) => Some(self.eval(expr)),
+            MemberProp::PrivateName(_) => None,
+        }
+    }
+
     fn eval_tpl(&self, e: &Tpl, raw: bool) -> JsValue {
         debug_assert!(e.quasis.len() == e.exprs.len() + 1);
 
@@ -750,6 +758,17 @@ pub fn as_parent_path(ast_path: &AstNodePath<AstParentNodeRef<'_>>) -> Vec<AstPa
     ast_path.iter().map(|n| n.kind()).collect()
 }
 
+pub fn as_parent_path_skip(
+    ast_path: &AstNodePath<AstParentNodeRef<'_>>,
+    skip: usize,
+) -> Vec<AstParentKind> {
+    ast_path
+        .iter()
+        .take(ast_path.len() - skip)
+        .map(|n| n.kind())
+        .collect()
+}
+
 pub fn as_parent_path_with(
     ast_path: &AstNodePath<AstParentNodeRef<'_>>,
     additional: AstParentKind,
@@ -1796,6 +1815,35 @@ impl VisitAstPath for Analyzer<'_> {
         if let Some((esm_reference_index, export)) =
             self.eval_context.imports.get_binding(&ident.to_id())
         {
+            if export.is_none() {
+                if let Some(AstParentNodeRef::MemberExpr(member, MemberExprField::Obj)) =
+                    ast_path.get(ast_path.len() - 2)
+                {
+                    if let Some(prop) = self.eval_context.eval_member_prop(&member.prop) {
+                        if let Some(prop_str) = prop.as_str() {
+                            // a namespace member access like
+                            // `import * as ns from "..."; ns.exportName`
+                            self.add_effect(Effect::ImportedBinding {
+                                esm_reference_index,
+                                export: Some(prop_str.into()),
+                                ast_path: as_parent_path_skip(ast_path, 1),
+                                span: member.span(),
+                                in_try: is_in_try(ast_path),
+                            });
+                            return;
+                        }
+                    }
+                }
+            }
+
             self.add_effect(Effect::ImportedBinding {
                 esm_reference_index,
                 export,

@kdy1 kdy1 requested review from sokra and mischnic January 11, 2025 03:46
@@ -1207,6 +1207,28 @@ pub(crate) async fn analyse_ecmascript_module_internal(
.await?,
)
} else {
let r = match options.tree_shaking_mode {
Some(TreeShakingMode::ReexportsOnly) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only in this mode? Wouldn't this also be benefitial even when splitting into fragments?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will go to a different code path, namely follow_reexports_with_side_effects.

#[turbo_tasks::function]
async fn follow_reexports_with_side_effects(
module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
export_name: RcStr,
side_effect_free_packages: Vc<Glob>,
) -> Result<Vc<FollowExportsWithSideEffectsResult>> {
let mut side_effects = vec![];
let mut current_module = module;
let mut current_export_name = export_name;
let result = loop {
let is_side_effect_free = *current_module
.is_marked_as_side_effect_free(side_effect_free_packages)
.await?;
if !is_side_effect_free {
side_effects.push(only_effects(*current_module).to_resolved().await?);
}
// We ignore the side effect of the entry module here, because we need to proceed.
let result = follow_reexports(
*current_module,
current_export_name.clone(),
side_effect_free_packages,
true,
)
.to_resolved()
.await?;
let FollowExportsResult {
module,
export_name,
ty,
} = &*result.await?;
match ty {
FoundExportType::SideEffects => {
current_module = *module;
current_export_name = export_name.clone().unwrap_or(current_export_name);
}
_ => break result,
}
};
Ok(FollowExportsWithSideEffectsResult {
side_effects,
result,
}
.cell())
}

In the full module fragment tree shaking mode import * will not create None for Option<ModulePart>. The line producing None is located at

which is only used for ReexportsOnly

Copy link
Contributor

@mischnic mischnic Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, I don't think we have a test for the other tree shaking mode though. Could you add that, seems like we already have something similar going on for mui-utils which runs the same code from side-effects-optimization/mui-utils but just with a different config

@kdy1 kdy1 requested a review from mischnic January 14, 2025 19:47
@kdy1 kdy1 requested a review from mischnic January 14, 2025 20:02
@kdy1 kdy1 enabled auto-merge (squash) January 14, 2025 20:11
@kdy1 kdy1 merged commit 0133480 into canary Jan 14, 2025
130 of 135 checks passed
@kdy1 kdy1 deleted the kdy1/pack-3684 branch January 14, 2025 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
created-by: Turbopack team PRs by the Turbopack team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants