vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.68k stars 26.61k forks source link

Next.js includes inefficiently transpiled code #37142

Open gaearon opened 2 years ago

gaearon commented 2 years ago

Verify canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:41 PST 2021; root:xnu-8019.61.5~1/RELEASE_ARM64_T6000
Binaries:
  Node: 16.14.2
  npm: 8.5.0
  Yarn: 1.22.15
  pnpm: 6.11.0
Relevant packages:
  next: 12.1.7-canary.11
  react: 18.1.0
  react-dom: 18.1.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

Even an empty Next.js project, when compiled, seems to include a bunch of inefficiently transpiled code.

Here is a prettified main.js from an empty Next.js project: https://gist.github.com/gaearon/6ce1f86577a55a738f2319fcdaa90892

Some parts that look particularly suspicious:

     function a(e, t) {
        (null == t || t > e.length) && (t = e.length);
        for (var r = 0, n = new Array(t); r < t; r++) n[r] = e[r];
        return n;
      }
      function i(e, t) {
        if (!(e instanceof t))
          throw new TypeError("Cannot call a class as a function");
      }
      function u(e, t) {
        for (var r = 0; r < t.length; r++) {
          var n = t[r];
          (n.enumerable = n.enumerable || !1),
            (n.configurable = !0),
            "value" in n && (n.writable = !0),
            Object.defineProperty(e, n.key, n);
        }
      }
      function c(e) {
        return (c = Object.setPrototypeOf
          ? Object.getPrototypeOf
          : function (e) {
              return e.__proto__ || Object.getPrototypeOf(e);
            })(e);
      }
      function l() {
        if ("function" !== typeof WeakMap) return null;
        var e = new WeakMap();
        return (
          (l = function () {
            return e;
          }),
          e
        );
      }
      function s(e, t) {
        return !t || ("object" !== d(t) && "function" !== typeof t)
          ? (function (e) {
              if (void 0 === e)
                throw new ReferenceError(
                  "this hasn't been initialised - super() hasn't been called"
                );
              return e;
            })(e)
          : t;
      }
      function f(e, t) {
        return (f =
          Object.setPrototypeOf ||
          function (e, t) {
            return (e.__proto__ = t), e;
          })(e, t);
      }
      function p(e, t) {
        return (
          (function (e) {
            if (Array.isArray(e)) return e;
          })(e) ||
          (function (e, t) {
            var r =
              null == e
                ? null
                : ("undefined" !== typeof Symbol && e[Symbol.iterator]) ||
                  e["@@iterator"];
            if (null != r) {
              var n,
                o,
                a = [],
                i = !0,
                u = !1;
              try {
                for (
                  r = r.call(e);
                  !(i = (n = r.next()).done) &&
                  (a.push(n.value), !t || a.length !== t);
                  i = !0
                );
              } catch (c) {
                (u = !0), (o = c);
              } finally {
                try {
                  i || null == r.return || r.return();
                } finally {
                  if (u) throw o;
                }
              }
              return a;
            }
          })(e, t) ||
          (function (e, t) {
            if (!e) return;
            if ("string" === typeof e) return a(e, t);
            var r = Object.prototype.toString.call(e).slice(8, -1);
            "Object" === r && e.constructor && (r = e.constructor.name);
            if ("Map" === r || "Set" === r) return Array.from(r);
            if (
              "Arguments" === r ||
              /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
            )
              return a(e, t);
          })(e, t) ||
          (function () {
            throw new TypeError(
              "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
            );
          })()
        );
      }
      var d = function (e) {
        return e && "undefined" !== typeof Symbol && e.constructor === Symbol
          ? "symbol"
          : typeof e;
      };
      function h(e) {
        var t = (function () {
          if ("undefined" === typeof Reflect || !Reflect.construct) return !1;
          if (Reflect.construct.sham) return !1;
          if ("function" === typeof Proxy) return !0;
          try {
            return (
              Boolean.prototype.valueOf.call(
                Reflect.construct(Boolean, [], function () {})
              ),
              !0
            );
          } catch (e) {
            return !1;
          }
        })();
        return function () {
          var r,
            n = c(e);
          if (t) {
            var o = c(this).constructor;
            r = Reflect.construct(n, arguments, o);
          } else r = n.apply(this, arguments);
          return s(this, r);
        };
      }
      Object.defineProperty(t, "__esModule", { value: !0 }),
      var y = (function (e) {
          if (e && e.__esModule) return e;
          var t = {};
          if (null != e)
            for (var r in e)
              if (Object.prototype.hasOwnProperty.call(e, r)) {
                var n =
                  Object.defineProperty && Object.getOwnPropertyDescriptor
                    ? Object.getOwnPropertyDescriptor(e, r)
                    : {};
                n.get || n.set ? Object.defineProperty(t, r, n) : (t[r] = e[r]);
              }
          return (t.default = e), t;
      function M(e, t, r, n, o, a, i) {
        try {
          var u = e[a](i),
            c = u.value;
        } catch (l) {
          return void r(l);
        }
        u.done ? t(c) : Promise.resolve(c).then(n, o);
      }
      function T(e) {
        return function () {
          var t = this,
            r = arguments;
          return new Promise(function (n, o) {
            var a = e.apply(t, r);
            function i(e) {
              M(a, n, o, i, u, "next", e);
            }
            function u(e) {
              M(a, n, o, i, u, "throw", e);
            }
            i(void 0);
          });
        };
      }
      function L(e, t, r) {
        return (
          t in e
            ? Object.defineProperty(e, t, {
                value: r,
                enumerable: !0,
                configurable: !0,
                writable: !0,
              })
            : (e[t] = r),
          e
        );
      }
      function I(e) {
        return e && e.__esModule ? e : { default: e };
      }
      function N(e) {
        for (
          var t = arguments,
            r = function (r) {
              var n = null != t[r] ? t[r] : {},
                o = Object.keys(n);
              "function" === typeof Object.getOwnPropertySymbols &&
                (o = o.concat(
                  Object.getOwnPropertySymbols(n).filter(function (e) {
                    return Object.getOwnPropertyDescriptor(n, e).enumerable;
                  })
                )),
                o.forEach(function (t) {
                  L(e, t, n[t]);
                });
            },
            n = 1;
          n < arguments.length;
          n++
        )
          r(n);
        return e;
      }
        K = (function (e) {
          !(function (e, t) {
            if ("function" !== typeof t && null !== t)
              throw new TypeError(
                "Super expression must either be null or a function"
              );
            (e.prototype = Object.create(t && t.prototype, {
              constructor: { value: e, writable: !0, configurable: !0 },
            })),
              t && f(e, t);
          })(a, e);
          var t,
            r,
            n,
            o = h(a);
          function a() {
            return i(this, a), o.apply(this, arguments);
          }
        ("function" === typeof t.default ||
          ("object" === typeof t.default && null !== t.default)) &&
          "undefined" === typeof t.default.__esModule &&
          (Object.defineProperty(t.default, "__esModule", { value: !0 }),
          Object.assign(t.default, t),
          (e.exports = t.default));

(the one above is repeated many many times)

     "use strict";
      function n(e, t) {
        (null == t || t > e.length) && (t = e.length);
        for (var r = 0, n = new Array(t); r < t; r++) n[r] = e[r];
        return n;
      }
      function o(e, t) {
        return (
          (function (e) {
            if (Array.isArray(e)) return e;
          })(e) ||
          (function (e, t) {
            var r =
              null == e
                ? null
                : ("undefined" !== typeof Symbol && e[Symbol.iterator]) ||
                  e["@@iterator"];
            if (null != r) {
              var n,
                o,
                a = [],
                i = !0,
                u = !1;
              try {
                for (
                  r = r.call(e);
                  !(i = (n = r.next()).done) &&
                  (a.push(n.value), !t || a.length !== t);
                  i = !0
                );
              } catch (c) {
                (u = !0), (o = c);
              } finally {
                try {
                  i || null == r.return || r.return();
                } finally {
                  if (u) throw o;
                }
              }
              return a;
            }
          })(e, t) ||
          (function (e, t) {
            if (!e) return;
            if ("string" === typeof e) return n(e, t);
            var r = Object.prototype.toString.call(e).slice(8, -1);
            "Object" === r && e.constructor && (r = e.constructor.name);
            if ("Map" === r || "Set" === r) return Array.from(r);
            if (
              "Arguments" === r ||
              /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
            )
              return n(e, t);
          })(e, t) ||
          (function () {
            throw new TypeError(
              "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
            );
          })()
        );
      }
      Object.defineProperty(t, "__esModule", { value: !0 }),
        (t.Portal = void 0);
      var a,
        i = (a = r(7294)) && a.__esModule ? a : { default: a },
        u = r(3935);
      "use strict";
      function n(e, t) {
        (null == t || t > e.length) && (t = e.length);
        for (var r = 0, n = new Array(t); r < t; r++) n[r] = e[r];
        return n;
      }
      function o(e, t) {
        return (
          (function (e) {
            if (Array.isArray(e)) return e;
          })(e) ||
          (function (e, t) {
            var r =
              null == e
                ? null
                : ("undefined" !== typeof Symbol && e[Symbol.iterator]) ||
                  e["@@iterator"];
            if (null != r) {
              var n,
                o,
                a = [],
                i = !0,
                u = !1;
              try {
                for (
                  r = r.call(e);
                  !(i = (n = r.next()).done) &&
                  (a.push(n.value), !t || a.length !== t);
                  i = !0
                );
              } catch (c) {
                (u = !0), (o = c);
              } finally {
                try {
                  i || null == r.return || r.return();
                } finally {
                  if (u) throw o;
                }
              }
              return a;
            }
          })(e, t) ||
          (function (e, t) {
            if (!e) return;
            if ("string" === typeof e) return n(e, t);
            var r = Object.prototype.toString.call(e).slice(8, -1);
            "Object" === r && e.constructor && (r = e.constructor.name);
            if ("Map" === r || "Set" === r) return Array.from(r);
            if (
              "Arguments" === r ||
              /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
            )
              return n(e, t);
          })(e, t) ||
          (function () {
            throw new TypeError(
              "Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
            );
          })()
        );
      }
      Object.defineProperty(t, "__esModule", { value: !0 }),
     function n(e, t) {
        (null == t || t > e.length) && (t = e.length);
        for (var r = 0, n = new Array(t); r < t; r++) n[r] = e[r];
        return n;
      }
      function o() {
        if ("undefined" === typeof Reflect || !Reflect.construct) return !1;
        if (Reflect.construct.sham) return !1;
        if ("function" === typeof Proxy) return !0;
        try {
          return (
            Date.prototype.toString.call(
              Reflect.construct(Date, [], function () {})
            ),
            !0
          );
        } catch (e) {
          return !1;
        }
      }
      function a(e, t, r) {
        return (a = o()
          ? Reflect.construct
          : function (e, t, r) {
              var n = [null];
              n.push.apply(n, t);
              var o = new (Function.bind.apply(e, n))();
              return r && i(o, r.prototype), o;
            }).apply(null, arguments);
      }
      function i(e, t) {
        return (i =
          Object.setPrototypeOf ||
          function (e, t) {
            return (e.__proto__ = t), e;
          })(e, t);
      }
      function u(e) {
        return (
          (function (e) {
            if (Array.isArray(e)) return n(e);
          })(e) ||
          (function (e) {
            if (
              ("undefined" !== typeof Symbol && null != e[Symbol.iterator]) ||
              null != e["@@iterator"]
            )
              return Array.from(e);
          })(e) ||
          (function (e, t) {
            if (!e) return;
            if ("string" === typeof e) return n(e, t);
            var r = Object.prototype.toString.call(e).slice(8, -1);
            "Object" === r && e.constructor && (r = e.constructor.name);
            if ("Map" === r || "Set" === r) return Array.from(r);
            if (
              "Arguments" === r ||
              /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)
            )
              return n(e, t);
          })(e) ||
          (function () {
            throw new TypeError(
              "Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
            );
          })()
        );
      }

I presume that some of this is classes, some is destructuring, some is module system, and some is async/await. I think it would be great if:

Expected Behavior

No repetitive and inefficient compilation artifacts in the default Next.js production bundle.

To Reproduce

Create a new Next.js project and build it.

ijjk commented 2 years ago

Hi, we have an experimental config to make the transpilation more specific to the browser requirements in the latest canary of Next.js it can be enabled with:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  experimental: {
    legacyBrowsers: false,
    browsersListForSwc: true
  }
}

module.exports = nextConfig

The browserslist used with the above config can be seen here https://github.com/vercel/next.js/blob/81850eb295c59446b0e0b003356844c7c69cf38c/packages/next/shared/lib/constants.ts#L29

Related RFC https://github.com/vercel/next.js/discussions/33227

gaearon commented 2 years ago

Awesome, thanks! I'll try this as a stopgap. It's still pretty bad the output is so bloated/duplicated for the older browsers though. Do you think this is worth fixing on its own? Sharing the helpers in a single module like Babel does would go a long way.

gaearon commented 2 years ago

To clarify, some of the patterns I've quotes are repeated many times throughout the bundle. Not sure if it's per class, per module, or per await/spread usage.

ijjk commented 2 years ago

Yeah there's definitely room for improvement here separate of the features being transpiled which we can investigate!

gaearon commented 2 years ago

For the approach in https://github.com/vercel/next.js/issues/37142#issuecomment-1135206523, is the browsers list configurable?

ijjk commented 2 years ago

Yeah the above config will honor a custom browserslist config if present instead of the default provided.

gaearon commented 2 years ago

If I use the config you've suggested, the output is much better!

Some repeated unfortunate patterns which I presume are from module system:

        ("function" === typeof t.default ||
          ("object" === typeof t.default && null !== t.default)) &&
          "undefined" === typeof t.default.__esModule &&
          (Object.defineProperty(t.default, "__esModule", { value: !0 }),
          Object.assign(t.default, t),
          (e.exports = t.default));
    },
  var n = (function (e) {
          if (e && e.__esModule) return e;
          var t = {};
          if (null != e)
            for (var r in e)
              if (Object.prototype.hasOwnProperty.call(e, r)) {
                var n =
                  Object.defineProperty && Object.getOwnPropertyDescriptor
                    ? Object.getOwnPropertyDescriptor(e, r)
                    : {};
                n.get || n.set ? Object.defineProperty(t, r, n) : (t[r] = e[r]);
              }
          return (t.default = e),
ijjk commented 2 years ago

The duplication in helpers noticed here should be fixed by https://github.com/vercel/next.js/pull/37150

ku8ar commented 2 years ago

Why we can't just manually add .swcrc to configure browsersList, loose mode etc as we wish? SWC by default transpiles to some ancient ES5. E.g. template literals have Object.freeze in their initialization. In projects with styled-components it slows down code.

flieks commented 2 years ago

like @ku8ar i also would like to add an .swcrc to turn on topLevelAwait using custom babel config i can't get that to work

mytchdot commented 2 years ago

Per @ku8ar 's comment, wouldn't it be equally as practical to kill two birds with one stone here and allow the custom browserlist through the .swcrc...?

mvarendorff commented 2 years ago

For those lurking: Support for the experimental config mentioned in this comment has been released in stable 12.2.0!

jankaifer commented 1 year ago

What is the current status of this issue? Are there more optimizations needed for older browsers or was that fixed here https://github.com/vercel/next.js/issues/37142#issuecomment-1135473389?