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

Adopt context based experimental styled-jsx version #28646

Merged
merged 8 commits into from
Sep 9, 2021

Conversation

huozhi
Copy link
Member

@huozhi huozhi commented Aug 31, 2021

Integrate experimental (concurrent mode) version of styled-jsx to unblock streaming work

  • Wrap <StyleRegistry> on App
  • use useStyleRegistry to access style registry and flush styles to JSX elements
  • add defaultGetInitialProps in DocumentContext to return jsx styles
  • Once this PR is approved, will publish a new version of styled-jsx
  • Replace the version resolution in package.json

related: vercel/styled-jsx#721

@ijjk ijjk added created-by: Next.js team PRs by the Next.js team. type: next labels Aug 31, 2021
@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@huozhi huozhi changed the title Adopt context based experimental styled-jsx version [WIP] Adopt context based experimental styled-jsx version Aug 31, 2021
@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@huozhi huozhi requested review from devknoll and shuding September 1, 2021 07:55
@ijjk

This comment has been minimized.

devknoll
devknoll previously approved these changes Sep 1, 2021
Copy link
Contributor

@devknoll devknoll left a comment

Choose a reason for hiding this comment

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

LGTM (modulo lint/tests)

packages/next/pages/_document.tsx Outdated Show resolved Hide resolved
@huozhi huozhi changed the title [WIP] Adopt context based experimental styled-jsx version Adopt context based experimental styled-jsx version Sep 2, 2021
@ijjk

This comment has been minimized.

@ijjk

This comment has been minimized.

@huozhi huozhi marked this pull request as ready for review September 8, 2021 14:52
@ijjk

This comment has been minimized.

@ijjk
Copy link
Member

ijjk commented Sep 8, 2021

Failing test suites

Commit: eb98799

test/integration/config-devtool-dev/test/index.test.js

  • devtool set in development mode in next config > should warn and revert when a devtool is set in development mode
Expand output

● devtool set in development mode in next config › should warn and revert when a devtool is set in development mode

thrown: "Exceeded timeout of 30000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."

  11 | import webdriver from 'next-webdriver'
  12 | import { join } from 'path'
> 13 |
     | ^
  14 | jest.setTimeout(1000 * 30)
  15 |
  16 | const appDir = join(__dirname, '../')

  at integration/config-devtool-dev/test/index.test.js:13:5
  at Object.<anonymous> (integration/config-devtool-dev/test/index.test.js:12:1)

@ijjk
Copy link
Member

ijjk commented Sep 8, 2021

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary huozhi/next.js use-styled-v5 Change
buildDuration 16.1s 16.3s ⚠️ +150ms
buildDurationCached 4s 4s -68ms
nodeModulesSize 48.2 MB 48.2 MB ⚠️ +1.74 kB
Page Load Tests Overall decrease ⚠️
vercel/next.js canary huozhi/next.js use-styled-v5 Change
/ failed reqs 0 0
/ total time (seconds) 3.223 3.285 ⚠️ +0.06
/ avg req/sec 775.73 760.96 ⚠️ -14.77
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 2.02 2.023 0
/error-in-render avg req/sec 1237.34 1236 ⚠️ -1.34
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary huozhi/next.js use-styled-v5 Change
745.HASH.js gzip 179 B 179 B
framework-HASH.js gzip 42.2 kB 42.2 kB
main-HASH.js gzip 23.3 kB 26.6 kB ⚠️ +3.25 kB
webpack-HASH.js gzip 1.45 kB 1.45 kB
Overall change 67.2 kB 70.4 kB ⚠️ +3.25 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary huozhi/next.js use-styled-v5 Change
polyfills-a4..dd70.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary huozhi/next.js use-styled-v5 Change
_app-HASH.js gzip 979 B 979 B
_error-HASH.js gzip 194 B 194 B
amp-HASH.js gzip 312 B 312 B
css-HASH.js gzip 329 B 329 B
dynamic-HASH.js gzip 2.67 kB 2.67 kB
head-HASH.js gzip 351 B 351 B
hooks-HASH.js gzip 918 B 918 B
image-HASH.js gzip 4.14 kB 4.14 kB
index-HASH.js gzip 261 B 261 B
link-HASH.js gzip 1.66 kB 1.66 kB
routerDirect..HASH.js gzip 318 B 318 B
script-HASH.js gzip 387 B 387 B
withRouter-HASH.js gzip 320 B 320 B
bb14e60e810b..30f.css gzip 125 B 125 B
Overall change 13 kB 13 kB
Client Build Manifests
vercel/next.js canary huozhi/next.js use-styled-v5 Change
_buildManifest.js gzip 492 B 492 B
Overall change 492 B 492 B
Rendered Page Sizes Overall increase ⚠️
vercel/next.js canary huozhi/next.js use-styled-v5 Change
index.html gzip 539 B 540 B ⚠️ +1 B
link.html gzip 552 B 552 B
withRouter.html gzip 533 B 535 B ⚠️ +2 B
Overall change 1.62 kB 1.63 kB ⚠️ +3 B

Diffs

Diff for _buildManifest.js
@@ -10,7 +10,7 @@ self.__BUILD_MANIFEST = {
     "static\u002Fchunks\u002Fpages\u002Fcss-d747126cbf11007733b6.js"
   ],
   "/dynamic": [
-    "static\u002Fchunks\u002Fpages\u002Fdynamic-49adf2e1bdf9c9e868d3.js"
+    "static\u002Fchunks\u002Fpages\u002Fdynamic-31ec8b3d0e5d37bd30a4.js"
   ],
   "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-28fcf610d5156765f0fb.js"],
   "/hooks": [
Diff for dynamic-HASH.js
@@ -1,7 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [739],
   {
-    /***/ 8771: /***/ function(
+    /***/ 2694: /***/ function(
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -765,7 +765,7 @@
       __unused_webpack_exports,
       __webpack_require__
     ) {
-      module.exports = __webpack_require__(8771);
+      module.exports = __webpack_require__(2694);
 
       /***/
     }
Diff for main-HASH.js
@@ -921,6 +921,8 @@
 
       var _reactDom = _interopRequireDefault(__webpack_require__(3935));
 
+      var _styledJsx = __webpack_require__(8771);
+
       var _headManagerContext = __webpack_require__(699);
 
       var _mitt = _interopRequireDefault(__webpack_require__(1436));
@@ -1780,7 +1782,11 @@
               {
                 value: headManager
               },
-              children
+              /*#__PURE__*/ _react["default"].createElement(
+                _styledJsx.StyleRegistry,
+                null,
+                children
+              )
             )
           )
         );
@@ -7644,6 +7650,202 @@
       /***/
     },
 
+    /***/ 4155: /***/ function(module) {
+      // shim for using process in browser
+      var process = (module.exports = {});
+
+      // 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;
+
+      function defaultSetTimout() {
+        throw new Error("setTimeout has not been defined");
+      }
+      function defaultClearTimeout() {
+        throw new Error("clearTimeout has not been defined");
+      }
+      (function() {
+        try {
+          if (typeof setTimeout === "function") {
+            cachedSetTimeout = setTimeout;
+          } else {
+            cachedSetTimeout = defaultSetTimout;
+          }
+        } catch (e) {
+          cachedSetTimeout = defaultSetTimout;
+        }
+        try {
+          if (typeof clearTimeout === "function") {
+            cachedClearTimeout = clearTimeout;
+          } else {
+            cachedClearTimeout = defaultClearTimeout;
+          }
+        } catch (e) {
+          cachedClearTimeout = defaultClearTimeout;
+        }
+      })();
+      function runTimeout(fun) {
+        if (cachedSetTimeout === setTimeout) {
+          //normal enviroments in sane situations
+          return setTimeout(fun, 0);
+        }
+        // if setTimeout wasn't available but was latter defined
+        if (
+          (cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) &&
+          setTimeout
+        ) {
+          cachedSetTimeout = setTimeout;
+          return setTimeout(fun, 0);
+        }
+        try {
+          // when when somebody has screwed with setTimeout but no I.E. maddness
+          return cachedSetTimeout(fun, 0);
+        } catch (e) {
+          try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+            return cachedSetTimeout.call(null, fun, 0);
+          } catch (e) {
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+            return cachedSetTimeout.call(this, fun, 0);
+          }
+        }
+      }
+      function runClearTimeout(marker) {
+        if (cachedClearTimeout === clearTimeout) {
+          //normal enviroments in sane situations
+          return clearTimeout(marker);
+        }
+        // if clearTimeout wasn't available but was latter defined
+        if (
+          (cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) &&
+          clearTimeout
+        ) {
+          cachedClearTimeout = clearTimeout;
+          return clearTimeout(marker);
+        }
+        try {
+          // when when somebody has screwed with setTimeout but no I.E. maddness
+          return cachedClearTimeout(marker);
+        } catch (e) {
+          try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+            return cachedClearTimeout.call(null, marker);
+          } catch (e) {
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+            return cachedClearTimeout.call(this, marker);
+          }
+        }
+      }
+      var queue = [];
+      var draining = false;
+      var currentQueue;
+      var queueIndex = -1;
+
+      function cleanUpNextTick() {
+        if (!draining || !currentQueue) {
+          return;
+        }
+        draining = false;
+        if (currentQueue.length) {
+          queue = currentQueue.concat(queue);
+        } else {
+          queueIndex = -1;
+        }
+        if (queue.length) {
+          drainQueue();
+        }
+      }
+
+      function drainQueue() {
+        if (draining) {
+          return;
+        }
+        var timeout = runTimeout(cleanUpNextTick);
+        draining = true;
+
+        var len = queue.length;
+        while (len) {
+          currentQueue = queue;
+          queue = [];
+          while (++queueIndex < len) {
+            if (currentQueue) {
+              currentQueue[queueIndex].run();
+            }
+          }
+          queueIndex = -1;
+          len = queue.length;
+        }
+        currentQueue = null;
+        draining = false;
+        runClearTimeout(timeout);
+      }
+
+      process.nextTick = function(fun) {
+        var args = new Array(arguments.length - 1);
+        if (arguments.length > 1) {
+          for (var i = 1; i < arguments.length; i++) {
+            args[i - 1] = arguments[i];
+          }
+        }
+        queue.push(new Item(fun, args));
+        if (queue.length === 1 && !draining) {
+          runTimeout(drainQueue);
+        }
+      };
+
+      // v8 likes predictible objects
+      function Item(fun, array) {
+        this.fun = fun;
+        this.array = array;
+      }
+      Item.prototype.run = function() {
+        this.fun.apply(null, this.array);
+      };
+      process.title = "browser";
+      process.browser = true;
+      process.env = {};
+      process.argv = [];
+      process.version = ""; // empty string to avoid regexp issues
+      process.versions = {};
+
+      function noop() {}
+
+      process.on = noop;
+      process.addListener = noop;
+      process.once = noop;
+      process.off = noop;
+      process.removeListener = noop;
+      process.removeAllListeners = noop;
+      process.emit = noop;
+      process.prependListener = noop;
+      process.prependOnceListener = noop;
+
+      process.listeners = function(name) {
+        return [];
+      };
+
+      process.binding = function(name) {
+        throw new Error("process.binding is not supported");
+      };
+
+      process.cwd = function() {
+        return "/";
+      };
+      process.chdir = function(dir) {
+        throw new Error("process.chdir is not supported");
+      };
+      process.umask = function() {
+        return 0;
+      };
+
+      /***/
+    },
+
     /***/ 5666: /***/ function(module) {
       /**
        * Copyright (c) 2014-present, Facebook, Inc.
@@ -8420,6 +8622,806 @@
       /***/
     },
 
+    /***/ 9887: /***/ function(module) {
+      "use strict";
+
+      function hash(str) {
+        var hash = 5381,
+          i = str.length;
+
+        while (i) {
+          hash = (hash * 33) ^ str.charCodeAt(--i);
+        }
+
+        /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
+         * integers. Since we want the results to be always positive, convert the
+         * signed int to an unsigned by doing an unsigned bitshift. */
+        return hash >>> 0;
+      }
+
+      module.exports = hash;
+
+      /***/
+    },
+
+    /***/ 5919: /***/ function(
+      __unused_webpack_module,
+      exports,
+      __webpack_require__
+    ) {
+      "use strict";
+
+      exports.__esModule = true;
+      exports.useStyleRegistry = exports.createStyleRegistry = exports.StyleRegistry = void 0;
+
+      var _stylesheetRegistry = __webpack_require__(8122);
+
+      exports.StyleRegistry = _stylesheetRegistry.StyleRegistry;
+      exports.createStyleRegistry = _stylesheetRegistry.createStyleRegistry;
+      exports.useStyleRegistry = _stylesheetRegistry.useStyleRegistry;
+
+      /***/
+    },
+
+    /***/ 9035: /***/ function(
+      __unused_webpack_module,
+      exports,
+      __webpack_require__
+    ) {
+      "use strict";
+
+      exports.__esModule = true;
+      exports.computeId = computeId;
+      exports.computeSelector = computeSelector;
+
+      var _stringHash = _interopRequireDefault(__webpack_require__(9887));
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      var sanitize = function sanitize(rule) {
+        return rule.replace(/\/style/gi, "\\/style");
+      };
+
+      var cache = {};
+      /**
+       * computeId
+       *
+       * Compute and memoize a jsx id from a basedId and optionally props.
+       */
+
+      function computeId(baseId, props) {
+        if (!props) {
+          return "jsx-" + baseId;
+        }
+
+        var propsToString = String(props);
+        var key = baseId + propsToString;
+
+        if (!cache[key]) {
+          cache[key] =
+            "jsx-" + (0, _stringHash["default"])(baseId + "-" + propsToString);
+        }
+
+        return cache[key];
+      }
+      /**
+       * computeSelector
+       *
+       * Compute and memoize dynamic selectors.
+       */
+
+      function computeSelector(id, css) {
+        var selectoPlaceholderRegexp = /__jsx-style-dynamic-selector/g; // Sanitize SSR-ed CSS.
+        // Client side code doesn't need to be sanitized since we use
+        // document.createTextNode (dev) and the CSSOM api sheet.insertRule (prod).
+
+        if (typeof window === "undefined") {
+          css = sanitize(css);
+        }
+
+        var idcss = id + css;
+
+        if (!cache[idcss]) {
+          cache[idcss] = css.replace(selectoPlaceholderRegexp, id);
+        }
+
+        return cache[idcss];
+      }
+
+      /***/
+    },
+
+    /***/ 4287: /***/ function(
+      __unused_webpack_module,
+      exports,
+      __webpack_require__
+    ) {
+      "use strict";
+      /* provided dependency */ var process = __webpack_require__(4155);
+
+      exports.__esModule = true;
+      exports["default"] = void 0;
+
+      function _defineProperties(target, props) {
+        for (var i = 0; i < props.length; i++) {
+          var descriptor = props[i];
+          descriptor.enumerable = descriptor.enumerable || false;
+          descriptor.configurable = true;
+          if ("value" in descriptor) descriptor.writable = true;
+          Object.defineProperty(target, descriptor.key, descriptor);
+        }
+      }
+
+      function _createClass(Constructor, protoProps, staticProps) {
+        if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+        if (staticProps) _defineProperties(Constructor, staticProps);
+        return Constructor;
+      }
+
+      /*
+Based on Glamor's sheet
+https://github.com/threepointone/glamor/blob/667b480d31b3721a905021b26e1290ce92ca2879/src/sheet.js
+*/
+      var isProd =
+        typeof process !== "undefined" &&
+        process.env &&
+        "production" === "production";
+
+      var isString = function isString(o) {
+        return Object.prototype.toString.call(o) === "[object String]";
+      };
+
+      var StyleSheet = /*#__PURE__*/ (function() {
+        function StyleSheet(_temp) {
+          var _ref = _temp === void 0 ? {} : _temp,
+            _ref$name = _ref.name,
+            name = _ref$name === void 0 ? "stylesheet" : _ref$name,
+            _ref$optimizeForSpeed = _ref.optimizeForSpeed,
+            optimizeForSpeed =
+              _ref$optimizeForSpeed === void 0 ? isProd : _ref$optimizeForSpeed,
+            _ref$isBrowser = _ref.isBrowser,
+            isBrowser =
+              _ref$isBrowser === void 0
+                ? typeof window !== "undefined"
+                : _ref$isBrowser;
+
+          invariant(isString(name), "`name` must be a string");
+          this._name = name;
+          this._deletedRulePlaceholder = "#" + name + "-deleted-rule____{}";
+          invariant(
+            typeof optimizeForSpeed === "boolean",
+            "`optimizeForSpeed` must be a boolean"
+          );
+          this._optimizeForSpeed = optimizeForSpeed;
+          this._isBrowser = isBrowser;
+          this._serverSheet = undefined;
+          this._tags = [];
+          this._injected = false;
+          this._rulesCount = 0;
+          var node =
+            this._isBrowser &&
+            document.querySelector('meta[property="csp-nonce"]');
+          this._nonce = node ? node.getAttribute("content") : null;
+        }
+
+        var _proto = StyleSheet.prototype;
+
+        _proto.setOptimizeForSpeed = function setOptimizeForSpeed(bool) {
+          invariant(
+            typeof bool === "boolean",
+            "`setOptimizeForSpeed` accepts a boolean"
+          );
+          invariant(
+            this._rulesCount === 0,
+            "optimizeForSpeed cannot be when rules have already been inserted"
+          );
+          this.flush();
+          this._optimizeForSpeed = bool;
+          this.inject();
+        };
+
+        _proto.isOptimizeForSpeed = function isOptimizeForSpeed() {
+          return this._optimizeForSpeed;
+        };
+
+        _proto.inject = function inject() {
+          var _this = this;
+
+          invariant(!this._injected, "sheet already injected");
+          this._injected = true;
+
+          if (this._isBrowser && this._optimizeForSpeed) {
+            this._tags[0] = this.makeStyleTag(this._name);
+            this._optimizeForSpeed = "insertRule" in this.getSheet();
+
+            if (!this._optimizeForSpeed) {
+              if (!isProd) {
+                console.warn(
+                  "StyleSheet: optimizeForSpeed mode not supported falling back to standard mode."
+                );
+              }
+
+              this.flush();
+              this._injected = true;
+            }
+
+            return;
+          }
+
+          this._serverSheet = {
+            cssRules: [],
+            insertRule: function insertRule(rule, index) {
+              if (typeof index === "number") {
+                _this._serverSheet.cssRules[index] = {
+                  cssText: rule
+                };
+              } else {
+                _this._serverSheet.cssRules.push({
+                  cssText: rule
+                });
+              }
+
+              return index;
+            },
+            deleteRule: function deleteRule(index) {
+              _this._serverSheet.cssRules[index] = null;
+            }
+          };
+        };
+
+        _proto.getSheetForTag = function getSheetForTag(tag) {
+          if (tag.sheet) {
+            return tag.sheet;
+          } // this weirdness brought to you by firefox
+
+          for (var i = 0; i < document.styleSheets.length; i++) {
+            if (document.styleSheets[i].ownerNode === tag) {
+              return document.styleSheets[i];
+            }
+          }
+        };
+
+        _proto.getSheet = function getSheet() {
+          return this.getSheetForTag(this._tags[this._tags.length - 1]);
+        };
+
+        _proto.insertRule = function insertRule(rule, index) {
+          invariant(isString(rule), "`insertRule` accepts only strings");
+
+          if (!this._isBrowser) {
+            if (typeof index !== "number") {
+              index = this._serverSheet.cssRules.length;
+            }
+
+            this._serverSheet.insertRule(rule, index);
+
+            return this._rulesCount++;
+          }
+
+          if (this._optimizeForSpeed) {
+            var sheet = this.getSheet();
+
+            if (typeof index !== "number") {
+              index = sheet.cssRules.length;
+            } // this weirdness for perf, and chrome's weird bug
+            // https://stackoverflow.com/questions/20007992/chrome-suddenly-stopped-accepting-insertrule
+
+            try {
+              sheet.insertRule(rule, index);
+            } catch (error) {
+              if (!isProd) {
+                console.warn(
+                  "StyleSheet: illegal rule: \n\n" +
+                    rule +
+                    "\n\nSee https://stackoverflow.com/q/20007992 for more info"
+                );
+              }
+
+              return -1;
+            }
+          } else {
+            var insertionPoint = this._tags[index];
+
+            this._tags.push(
+              this.makeStyleTag(this._name, rule, insertionPoint)
+            );
+          }
+
+          return this._rulesCount++;
+        };
+
+        _proto.replaceRule = function replaceRule(index, rule) {
+          if (this._optimizeForSpeed || !this._isBrowser) {
+            var sheet = this._isBrowser ? this.getSheet() : this._serverSheet;
+
+            if (!rule.trim()) {
+              rule = this._deletedRulePlaceholder;
+            }
+
+            if (!sheet.cssRules[index]) {
+              // @TBD Should we throw an error?
+              return index;
+            }
+
+            sheet.deleteRule(index);
+
+            try {
+              sheet.insertRule(rule, index);
+            } catch (error) {
+              if (!isProd) {
+                console.warn(
+                  "StyleSheet: illegal rule: \n\n" +
+                    rule +
+                    "\n\nSee https://stackoverflow.com/q/20007992 for more info"
+                );
+              } // In order to preserve the indices we insert a deleteRulePlaceholder
+
+              sheet.insertRule(this._deletedRulePlaceholder, index);
+            }
+          } else {
+            var tag = this._tags[index];
+            invariant(tag, "old rule at index `" + index + "` not found");
+            tag.textContent = rule;
+          }
+
+          return index;
+        };
+
+        _proto.deleteRule = function deleteRule(index) {
+          if (!this._isBrowser) {
+            this._serverSheet.deleteRule(index);
+
+            return;
+          }
+
+          if (this._optimizeForSpeed) {
+            this.replaceRule(index, "");
+          } else {
+            var tag = this._tags[index];
+            invariant(tag, "rule at index `" + index + "` not found");
+            tag.parentNode.removeChild(tag);
+            this._tags[index] = null;
+          }
+        };
+
+        _proto.flush = function flush() {
+          this._injected = false;
+          this._rulesCount = 0;
+
+          if (this._isBrowser) {
+            this._tags.forEach(function(tag) {
+              return tag && tag.parentNode.removeChild(tag);
+            });
+
+            this._tags = [];
+          } else {
+            // simpler on server
+            this._serverSheet.cssRules = [];
+          }
+        };
+
+        _proto.cssRules = function cssRules() {
+          var _this2 = this;
+
+          if (!this._isBrowser) {
+            return this._serverSheet.cssRules;
+          }
+
+          return this._tags.reduce(function(rules, tag) {
+            if (tag) {
+              rules = rules.concat(
+                Array.prototype.map.call(
+                  _this2.getSheetForTag(tag).cssRules,
+                  function(rule) {
+                    return rule.cssText === _this2._deletedRulePlaceholder
+                      ? null
+                      : rule;
+                  }
+                )
+              );
+            } else {
+              rules.push(null);
+            }
+
+            return rules;
+          }, []);
+        };
+
+        _proto.makeStyleTag = function makeStyleTag(
+          name,
+          cssString,
+          relativeToTag
+        ) {
+          if (cssString) {
+            invariant(
+              isString(cssString),
+              "makeStyleTag acceps only strings as second parameter"
+            );
+          }
+
+          var tag = document.createElement("style");
+          if (this._nonce) tag.setAttribute("nonce", this._nonce);
+          tag.type = "text/css";
+          tag.setAttribute("data-" + name, "");
+
+          if (cssString) {
+            tag.appendChild(document.createTextNode(cssString));
+          }
+
+          var head = document.head || document.getElementsByTagName("head")[0];
+
+          if (relativeToTag) {
+            head.insertBefore(tag, relativeToTag);
+          } else {
+            head.appendChild(tag);
+          }
+
+          return tag;
+        };
+
+        _createClass(StyleSheet, [
+          {
+            key: "length",
+            get: function get() {
+              return this._rulesCount;
+            }
+          }
+        ]);
+
+        return StyleSheet;
+      })();
+
+      exports["default"] = StyleSheet;
+
+      function invariant(condition, message) {
+        if (!condition) {
+          throw new Error("StyleSheet: " + message + ".");
+        }
+      }
+
+      /***/
+    },
+
+    /***/ 8122: /***/ function(
+      __unused_webpack_module,
+      exports,
+      __webpack_require__
+    ) {
+      "use strict";
+
+      exports.__esModule = true;
+      exports.createStyleRegistry = createStyleRegistry;
+      exports.StyleRegistry = StyleRegistry;
+      exports.useStyleRegistry = useStyleRegistry;
+      exports.StyleSheetContext = exports.StyleSheetRegistry = void 0;
+
+      var _react = _interopRequireWildcard(__webpack_require__(7294));
+
+      var _stylesheet = _interopRequireDefault(__webpack_require__(4287));
+
+      var _hash = __webpack_require__(9035);
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      function _getRequireWildcardCache() {
+        if (typeof WeakMap !== "function") return null;
+        var cache = new WeakMap();
+        _getRequireWildcardCache = function _getRequireWildcardCache() {
+          return cache;
+        };
+        return cache;
+      }
+
+      function _interopRequireWildcard(obj) {
+        if (obj && obj.__esModule) {
+          return obj;
+        }
+        if (
+          obj === null ||
+          (typeof obj !== "object" && typeof obj !== "function")
+        ) {
+          return { default: obj };
+        }
+        var cache = _getRequireWildcardCache();
+        if (cache && cache.has(obj)) {
+          return cache.get(obj);
+        }
+        var newObj = {};
+        var hasPropertyDescriptor =
+          Object.defineProperty && Object.getOwnPropertyDescriptor;
+        for (var key in obj) {
+          if (Object.prototype.hasOwnProperty.call(obj, key)) {
+            var desc = hasPropertyDescriptor
+              ? Object.getOwnPropertyDescriptor(obj, key)
+              : null;
+            if (desc && (desc.get || desc.set)) {
+              Object.defineProperty(newObj, key, desc);
+            } else {
+              newObj[key] = obj[key];
+            }
+          }
+        }
+        newObj["default"] = obj;
+        if (cache) {
+          cache.set(obj, newObj);
+        }
+        return newObj;
+      }
+
+      function mapRulesToStyle(cssRules, options) {
+        if (options === void 0) {
+          options = {};
+        }
+
+        return cssRules.map(function(args) {
+          var id = args[0];
+          var css = args[1];
+          return _react["default"].createElement("style", {
+            id: "__" + id,
+            // Avoid warnings upon render with a key
+            key: "__" + id,
+            nonce: options.nonce ? options.nonce : undefined,
+            dangerouslySetInnerHTML: {
+              __html: css
+            }
+          });
+        });
+      }
+
+      var StyleSheetRegistry = /*#__PURE__*/ (function() {
+        function StyleSheetRegistry(_temp) {
+          var _ref = _temp === void 0 ? {} : _temp,
+            _ref$styleSheet = _ref.styleSheet,
+            styleSheet = _ref$styleSheet === void 0 ? null : _ref$styleSheet,
+            _ref$optimizeForSpeed = _ref.optimizeForSpeed,
+            optimizeForSpeed =
+              _ref$optimizeForSpeed === void 0 ? false : _ref$optimizeForSpeed,
+            _ref$isBrowser = _ref.isBrowser,
+            isBrowser =
+              _ref$isBrowser === void 0
+                ? typeof window !== "undefined"
+                : _ref$isBrowser;
+
+          this._sheet =
+            styleSheet ||
+            new _stylesheet["default"]({
+              name: "styled-jsx",
+              optimizeForSpeed: optimizeForSpeed
+            });
+
+          this._sheet.inject();
+
+          if (styleSheet && typeof optimizeForSpeed === "boolean") {
+            this._sheet.setOptimizeForSpeed(optimizeForSpeed);
+
+            this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
+          }
+
+          this._isBrowser = isBrowser;
+          this._fromServer = undefined;
+          this._indices = {};
+          this._instancesCounts = {};
+        }
+
+        var _proto = StyleSheetRegistry.prototype;
+
+        _proto.add = function add(props) {
+          var _this = this;
+
+          if (undefined === this._optimizeForSpeed) {
+            this._optimizeForSpeed = Array.isArray(props.children);
+
+            this._sheet.setOptimizeForSpeed(this._optimizeForSpeed);
+
+            this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
+          }
+
+          if (this._isBrowser && !this._fromServer) {
+            this._fromServer = this.selectFromServer();
+            this._instancesCounts = Object.keys(this._fromServer).reduce(
+              function(acc, tagName) {
+                acc[tagName] = 0;
+                return acc;
+              },
+              {}
+            );
+          }
+
+          var _this$getIdAndRules = this.getIdAndRules(props),
+            styleId = _this$getIdAndRules.styleId,
+            rules = _this$getIdAndRules.rules; // Deduping: just increase the instances count.
+
+          if (styleId in this._instancesCounts) {
+            this._instancesCounts[styleId] += 1;
+            return;
+          }
+
+          var indices = rules
+            .map(function(rule) {
+              return _this._sheet.insertRule(rule);
+            }) // Filter out invalid rules
+            .filter(function(index) {
+              return index !== -1;
+            });
+          this._indices[styleId] = indices;
+          this._instancesCounts[styleId] = 1;
+        };
+
+        _proto.remove = function remove(props) {
+          var _this2 = this;
+
+          var _this$getIdAndRules2 = this.getIdAndRules(props),
+            styleId = _this$getIdAndRules2.styleId;
+
+          invariant(
+            styleId in this._instancesCounts,
+            "styleId: `" + styleId + "` not found"
+          );
+          this._instancesCounts[styleId] -= 1;
+
+          if (this._instancesCounts[styleId] < 1) {
+            var tagFromServer = this._fromServer && this._fromServer[styleId];
+
+            if (tagFromServer) {
+              tagFromServer.parentNode.removeChild(tagFromServer);
+              delete this._fromServer[styleId];
+            } else {
+              this._indices[styleId].forEach(function(index) {
+                return _this2._sheet.deleteRule(index);
+              });
+
+              delete this._indices[styleId];
+            }
+
+            delete this._instancesCounts[styleId];
+          }
+        };
+
+        _proto.update = function update(props, nextProps) {
+          this.add(nextProps);
+          this.remove(props);
+        };
+
+        _proto.flush = function flush() {
+          this._sheet.flush();
+
+          this._sheet.inject();
+
+          this._fromServer = undefined;
+          this._indices = {};
+          this._instancesCounts = {};
+        };
+
+        _proto.cssRules = function cssRules() {
+          var _this3 = this;
+
+          var fromServer = this._fromServer
+            ? Object.keys(this._fromServer).map(function(styleId) {
+                return [styleId, _this3._fromServer[styleId]];
+              })
+            : [];
+
+          var cssRules = this._sheet.cssRules();
+
+          return fromServer.concat(
+            Object.keys(this._indices)
+              .map(function(styleId) {
+                return [
+                  styleId,
+                  _this3._indices[styleId]
+                    .map(function(index) {
+                      return cssRules[index].cssText;
+                    })
+                    .join(_this3._optimizeForSpeed ? "" : "\n")
+                ];
+              }) // filter out empty rules
+              .filter(function(rule) {
+                return Boolean(rule[1]);
+              })
+          );
+        };
+
+        _proto.styles = function styles(options) {
+          return mapRulesToStyle(this.cssRules(), options);
+        };
+
+        _proto.getIdAndRules = function getIdAndRules(props) {
+          var css = props.children,
+            dynamic = props.dynamic,
+            id = props.id;
+
+          if (dynamic) {
+            var styleId = (0, _hash.computeId)(id, dynamic);
+            return {
+              styleId: styleId,
+              rules: Array.isArray(css)
+                ? css.map(function(rule) {
+                    return (0, _hash.computeSelector)(styleId, rule);
+                  })
+                : [(0, _hash.computeSelector)(styleId, css)]
+            };
+          }
+
+          return {
+            styleId: (0, _hash.computeId)(id),
+            rules: Array.isArray(css) ? css : [css]
+          };
+        };
+        /**
+         * selectFromServer
+         *
+         * Collects style tags from the document with id __jsx-XXX
+         */
+
+        _proto.selectFromServer = function selectFromServer() {
+          var elements = Array.prototype.slice.call(
+            document.querySelectorAll('[id^="__jsx-"]')
+          );
+          return elements.reduce(function(acc, element) {
+            var id = element.id.slice(2);
+            acc[id] = element;
+            return acc;
+          }, {});
+        };
+
+        return StyleSheetRegistry;
+      })();
+
+      exports.StyleSheetRegistry = StyleSheetRegistry;
+
+      function invariant(condition, message) {
+        if (!condition) {
+          throw new Error("StyleSheetRegistry: " + message + ".");
+        }
+      }
+
+      var StyleSheetContext = (0, _react.createContext)(null);
+      exports.StyleSheetContext = StyleSheetContext;
+
+      function createStyleRegistry() {
+        return new StyleSheetRegistry();
+      }
+
+      function StyleRegistry(_ref2) {
+        var configuredRegistry = _ref2.registry,
+          children = _ref2.children;
+        var rootRegistry = (0, _react.useContext)(StyleSheetContext);
+
+        var _useState = (0, _react.useState)(function() {
+            return rootRegistry || configuredRegistry || createStyleRegistry();
+          }),
+          registry = _useState[0];
+
+        return _react["default"].createElement(
+          StyleSheetContext.Provider,
+          {
+            value: registry
+          },
+          children
+        );
+      }
+
+      function useStyleRegistry() {
+        return (0, _react.useContext)(StyleSheetContext);
+      }
+
+      /***/
+    },
+
+    /***/ 8771: /***/ function(
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) {
+      module.exports = __webpack_require__(5919);
+
+      /***/
+    },
+
     /***/ 2431: /***/ function() {
       /* (ignored) */
       /***/
Diff for index.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-7f96b35aa75506e85a2e.js"
+      src="/_next/static/chunks/main-a8927f490c0ef8e6d5be.js"
       defer=""
     ></script>
     <script
Diff for link.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-7f96b35aa75506e85a2e.js"
+      src="/_next/static/chunks/main-a8927f490c0ef8e6d5be.js"
       defer=""
     ></script>
     <script
Diff for withRouter.html
@@ -19,7 +19,7 @@
       defer=""
     ></script>
     <script
-      src="/_next/static/chunks/main-7f96b35aa75506e85a2e.js"
+      src="/_next/static/chunks/main-a8927f490c0ef8e6d5be.js"
       defer=""
     ></script>
     <script

Webpack 4 Mode (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary huozhi/next.js use-styled-v5 Change
buildDuration 12.8s 13.1s ⚠️ +227ms
buildDurationCached 5.4s 5.4s -1ms
nodeModulesSize 48.2 MB 48.2 MB ⚠️ +1.74 kB
Page Load Tests Overall increase ✓
vercel/next.js canary huozhi/next.js use-styled-v5 Change
/ failed reqs 0 0
/ total time (seconds) 3.181 3.234 ⚠️ +0.05
/ avg req/sec 785.94 773.15 ⚠️ -12.79
/error-in-render failed reqs 0 0
/error-in-render total time (seconds) 1.98 1.912 -0.07
/error-in-render avg req/sec 1262.83 1307.36 +44.53
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary huozhi/next.js use-styled-v5 Change
16.HASH.js gzip 186 B 186 B
677f882d2ed8..HASH.js gzip 14.1 kB 14.1 kB
framework.HASH.js gzip 41.9 kB 41.9 kB
main-HASH.js gzip 10.7 kB 13.8 kB ⚠️ +3.12 kB
webpack-HASH.js gzip 1.19 kB 1.19 kB
Overall change 68.1 kB 71.2 kB ⚠️ +3.12 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary huozhi/next.js use-styled-v5 Change
polyfills-a4..dd70.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary huozhi/next.js use-styled-v5 Change
_app-HASH.js gzip 964 B 964 B
_error-HASH.js gzip 3.8 kB 3.8 kB
amp-HASH.js gzip 552 B 552 B
css-HASH.js gzip 333 B 333 B
dynamic-HASH.js gzip 2.87 kB 2.87 kB
head-HASH.js gzip 3.06 kB 3.06 kB
hooks-HASH.js gzip 924 B 924 B
index-HASH.js gzip 231 B 231 B
link-HASH.js gzip 1.64 kB 1.64 kB
routerDirect..HASH.js gzip 298 B 298 B
script-HASH.js gzip 3.03 kB 3.03 kB
withRouter-HASH.js gzip 295 B 295 B
30809af5c834..565.css gzip 125 B 125 B
Overall change 18.1 kB 18.1 kB
Client Build Manifests
vercel/next.js canary huozhi/next.js use-styled-v5 Change
_buildManifest.js gzip 500 B 500 B
Overall change 500 B 500 B
Rendered Page Sizes Overall decrease ✓
vercel/next.js canary huozhi/next.js use-styled-v5 Change
index.html gzip 585 B 585 B
link.html gzip 597 B 597 B
withRouter.html gzip 578 B 577 B -1 B
Overall change 1.76 kB 1.76 kB -1 B

Diffs

Diff for main-HASH.js
@@ -909,6 +909,224 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
       /***/
     },
 
+    /***/ "8oxB": /***/ function(module, exports) {
+      // shim for using process in browser
+      var process = (module.exports = {});
+
+      // 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;
+
+      function defaultSetTimout() {
+        throw new Error("setTimeout has not been defined");
+      }
+      function defaultClearTimeout() {
+        throw new Error("clearTimeout has not been defined");
+      }
+      (function() {
+        try {
+          if (typeof setTimeout === "function") {
+            cachedSetTimeout = setTimeout;
+          } else {
+            cachedSetTimeout = defaultSetTimout;
+          }
+        } catch (e) {
+          cachedSetTimeout = defaultSetTimout;
+        }
+        try {
+          if (typeof clearTimeout === "function") {
+            cachedClearTimeout = clearTimeout;
+          } else {
+            cachedClearTimeout = defaultClearTimeout;
+          }
+        } catch (e) {
+          cachedClearTimeout = defaultClearTimeout;
+        }
+      })();
+      function runTimeout(fun) {
+        if (cachedSetTimeout === setTimeout) {
+          //normal enviroments in sane situations
+          return setTimeout(fun, 0);
+        }
+        // if setTimeout wasn't available but was latter defined
+        if (
+          (cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) &&
+          setTimeout
+        ) {
+          cachedSetTimeout = setTimeout;
+          return setTimeout(fun, 0);
+        }
+        try {
+          // when when somebody has screwed with setTimeout but no I.E. maddness
+          return cachedSetTimeout(fun, 0);
+        } catch (e) {
+          try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+            return cachedSetTimeout.call(null, fun, 0);
+          } catch (e) {
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+            return cachedSetTimeout.call(this, fun, 0);
+          }
+        }
+      }
+      function runClearTimeout(marker) {
+        if (cachedClearTimeout === clearTimeout) {
+          //normal enviroments in sane situations
+          return clearTimeout(marker);
+        }
+        // if clearTimeout wasn't available but was latter defined
+        if (
+          (cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) &&
+          clearTimeout
+        ) {
+          cachedClearTimeout = clearTimeout;
+          return clearTimeout(marker);
+        }
+        try {
+          // when when somebody has screwed with setTimeout but no I.E. maddness
+          return cachedClearTimeout(marker);
+        } catch (e) {
+          try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+            return cachedClearTimeout.call(null, marker);
+          } catch (e) {
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+            return cachedClearTimeout.call(this, marker);
+          }
+        }
+      }
+      var queue = [];
+      var draining = false;
+      var currentQueue;
+      var queueIndex = -1;
+
+      function cleanUpNextTick() {
+        if (!draining || !currentQueue) {
+          return;
+        }
+        draining = false;
+        if (currentQueue.length) {
+          queue = currentQueue.concat(queue);
+        } else {
+          queueIndex = -1;
+        }
+        if (queue.length) {
+          drainQueue();
+        }
+      }
+
+      function drainQueue() {
+        if (draining) {
+          return;
+        }
+        var timeout = runTimeout(cleanUpNextTick);
+        draining = true;
+
+        var len = queue.length;
+        while (len) {
+          currentQueue = queue;
+          queue = [];
+          while (++queueIndex < len) {
+            if (currentQueue) {
+              currentQueue[queueIndex].run();
+            }
+          }
+          queueIndex = -1;
+          len = queue.length;
+        }
+        currentQueue = null;
+        draining = false;
+        runClearTimeout(timeout);
+      }
+
+      process.nextTick = function(fun) {
+        var args = new Array(arguments.length - 1);
+        if (arguments.length > 1) {
+          for (var i = 1; i < arguments.length; i++) {
+            args[i - 1] = arguments[i];
+          }
+        }
+        queue.push(new Item(fun, args));
+        if (queue.length === 1 && !draining) {
+          runTimeout(drainQueue);
+        }
+      };
+
+      // v8 likes predictible objects
+      function Item(fun, array) {
+        this.fun = fun;
+        this.array = array;
+      }
+      Item.prototype.run = function() {
+        this.fun.apply(null, this.array);
+      };
+      process.title = "browser";
+      process.browser = true;
+      process.env = {};
+      process.argv = [];
+      process.version = ""; // empty string to avoid regexp issues
+      process.versions = {};
+
+      function noop() {}
+
+      process.on = noop;
+      process.addListener = noop;
+      process.once = noop;
+      process.off = noop;
+      process.removeListener = noop;
+      process.removeAllListeners = noop;
+      process.emit = noop;
+      process.prependListener = noop;
+      process.prependOnceListener = noop;
+
+      process.listeners = function(name) {
+        return [];
+      };
+
+      process.binding = function(name) {
+        throw new Error("process.binding is not supported");
+      };
+
+      process.cwd = function() {
+        return "/";
+      };
+      process.chdir = function(dir) {
+        throw new Error("process.chdir is not supported");
+      };
+      process.umask = function() {
+        return 0;
+      };
+
+      /***/
+    },
+
+    /***/ "9kyW": /***/ function(module, exports, __webpack_require__) {
+      "use strict";
+
+      function hash(str) {
+        var hash = 5381,
+          i = str.length;
+
+        while (i) {
+          hash = (hash * 33) ^ str.charCodeAt(--i);
+        }
+
+        /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
+         * integers. Since we want the results to be always positive, convert the
+         * signed int to an unsigned by doing an unsigned bitshift. */
+        return hash >>> 0;
+      }
+
+      module.exports = hash;
+
+      /***/
+    },
+
     /***/ BMP1: /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
@@ -1400,6 +1618,8 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
 
       var _reactDom = _interopRequireDefault(__webpack_require__("i8i4"));
 
+      var _styledJsx = __webpack_require__("XM5m");
+
       var _headManagerContext = __webpack_require__("CM2u");
 
       var _mitt = _interopRequireDefault(__webpack_require__("Gz+c"));
@@ -2257,7 +2477,11 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
               {
                 value: headManager
               },
-              children
+              /*#__PURE__*/ _react["default"].createElement(
+                _styledJsx.StyleRegistry,
+                null,
+                children
+              )
             )
           )
         );
@@ -2569,6 +2793,351 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
       /***/
     },
 
+    /***/ SevZ: /***/ function(module, exports, __webpack_require__) {
+      "use strict";
+
+      exports.__esModule = true;
+      exports.createStyleRegistry = createStyleRegistry;
+      exports.StyleRegistry = StyleRegistry;
+      exports.useStyleRegistry = useStyleRegistry;
+      exports.StyleSheetContext = exports.StyleSheetRegistry = void 0;
+
+      var _react = _interopRequireWildcard(__webpack_require__("q1tI"));
+
+      var _stylesheet = _interopRequireDefault(__webpack_require__("bVZc"));
+
+      var _hash = __webpack_require__("j+KY");
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : { default: obj };
+      }
+
+      function _getRequireWildcardCache() {
+        if (typeof WeakMap !== "function") return null;
+        var cache = new WeakMap();
+        _getRequireWildcardCache = function _getRequireWildcardCache() {
+          return cache;
+        };
+        return cache;
+      }
+
+      function _interopRequireWildcard(obj) {
+        if (obj && obj.__esModule) {
+          return obj;
+        }
+        if (
+          obj === null ||
+          (typeof obj !== "object" && typeof obj !== "function")
+        ) {
+          return { default: obj };
+        }
+        var cache = _getRequireWildcardCache();
+        if (cache && cache.has(obj)) {
+          return cache.get(obj);
+        }
+        var newObj = {};
+        var hasPropertyDescriptor =
+          Object.defineProperty && Object.getOwnPropertyDescriptor;
+        for (var key in obj) {
+          if (Object.prototype.hasOwnProperty.call(obj, key)) {
+            var desc = hasPropertyDescriptor
+              ? Object.getOwnPropertyDescriptor(obj, key)
+              : null;
+            if (desc && (desc.get || desc.set)) {
+              Object.defineProperty(newObj, key, desc);
+            } else {
+              newObj[key] = obj[key];
+            }
+          }
+        }
+        newObj["default"] = obj;
+        if (cache) {
+          cache.set(obj, newObj);
+        }
+        return newObj;
+      }
+
+      function mapRulesToStyle(cssRules, options) {
+        if (options === void 0) {
+          options = {};
+        }
+
+        return cssRules.map(function(args) {
+          var id = args[0];
+          var css = args[1];
+          return _react["default"].createElement("style", {
+            id: "__" + id,
+            // Avoid warnings upon render with a key
+            key: "__" + id,
+            nonce: options.nonce ? options.nonce : undefined,
+            dangerouslySetInnerHTML: {
+              __html: css
+            }
+          });
+        });
+      }
+
+      var StyleSheetRegistry = /*#__PURE__*/ (function() {
+        function StyleSheetRegistry(_temp) {
+          var _ref = _temp === void 0 ? {} : _temp,
+            _ref$styleSheet = _ref.styleSheet,
+            styleSheet = _ref$styleSheet === void 0 ? null : _ref$styleSheet,
+            _ref$optimizeForSpeed = _ref.optimizeForSpeed,
+            optimizeForSpeed =
+              _ref$optimizeForSpeed === void 0 ? false : _ref$optimizeForSpeed,
+            _ref$isBrowser = _ref.isBrowser,
+            isBrowser =
+              _ref$isBrowser === void 0
+                ? typeof window !== "undefined"
+                : _ref$isBrowser;
+
+          this._sheet =
+            styleSheet ||
+            new _stylesheet["default"]({
+              name: "styled-jsx",
+              optimizeForSpeed: optimizeForSpeed
+            });
+
+          this._sheet.inject();
+
+          if (styleSheet && typeof optimizeForSpeed === "boolean") {
+            this._sheet.setOptimizeForSpeed(optimizeForSpeed);
+
+            this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
+          }
+
+          this._isBrowser = isBrowser;
+          this._fromServer = undefined;
+          this._indices = {};
+          this._instancesCounts = {};
+        }
+
+        var _proto = StyleSheetRegistry.prototype;
+
+        _proto.add = function add(props) {
+          var _this = this;
+
+          if (undefined === this._optimizeForSpeed) {
+            this._optimizeForSpeed = Array.isArray(props.children);
+
+            this._sheet.setOptimizeForSpeed(this._optimizeForSpeed);
+
+            this._optimizeForSpeed = this._sheet.isOptimizeForSpeed();
+          }
+
+          if (this._isBrowser && !this._fromServer) {
+            this._fromServer = this.selectFromServer();
+            this._instancesCounts = Object.keys(this._fromServer).reduce(
+              function(acc, tagName) {
+                acc[tagName] = 0;
+                return acc;
+              },
+              {}
+            );
+          }
+
+          var _this$getIdAndRules = this.getIdAndRules(props),
+            styleId = _this$getIdAndRules.styleId,
+            rules = _this$getIdAndRules.rules; // Deduping: just increase the instances count.
+
+          if (styleId in this._instancesCounts) {
+            this._instancesCounts[styleId] += 1;
+            return;
+          }
+
+          var indices = rules
+            .map(function(rule) {
+              return _this._sheet.insertRule(rule);
+            }) // Filter out invalid rules
+            .filter(function(index) {
+              return index !== -1;
+            });
+          this._indices[styleId] = indices;
+          this._instancesCounts[styleId] = 1;
+        };
+
+        _proto.remove = function remove(props) {
+          var _this2 = this;
+
+          var _this$getIdAndRules2 = this.getIdAndRules(props),
+            styleId = _this$getIdAndRules2.styleId;
+
+          invariant(
+            styleId in this._instancesCounts,
+            "styleId: `" + styleId + "` not found"
+          );
+          this._instancesCounts[styleId] -= 1;
+
+          if (this._instancesCounts[styleId] < 1) {
+            var tagFromServer = this._fromServer && this._fromServer[styleId];
+
+            if (tagFromServer) {
+              tagFromServer.parentNode.removeChild(tagFromServer);
+              delete this._fromServer[styleId];
+            } else {
+              this._indices[styleId].forEach(function(index) {
+                return _this2._sheet.deleteRule(index);
+              });
+
+              delete this._indices[styleId];
+            }
+
+            delete this._instancesCounts[styleId];
+          }
+        };
+
+        _proto.update = function update(props, nextProps) {
+          this.add(nextProps);
+          this.remove(props);
+        };
+
+        _proto.flush = function flush() {
+          this._sheet.flush();
+
+          this._sheet.inject();
+
+          this._fromServer = undefined;
+          this._indices = {};
+          this._instancesCounts = {};
+        };
+
+        _proto.cssRules = function cssRules() {
+          var _this3 = this;
+
+          var fromServer = this._fromServer
+            ? Object.keys(this._fromServer).map(function(styleId) {
+                return [styleId, _this3._fromServer[styleId]];
+              })
+            : [];
+
+          var cssRules = this._sheet.cssRules();
+
+          return fromServer.concat(
+            Object.keys(this._indices)
+              .map(function(styleId) {
+                return [
+                  styleId,
+                  _this3._indices[styleId]
+                    .map(function(index) {
+                      return cssRules[index].cssText;
+                    })
+                    .join(_this3._optimizeForSpeed ? "" : "\n")
+                ];
+              }) // filter out empty rules
+              .filter(function(rule) {
+                return Boolean(rule[1]);
+              })
+          );
+        };
+
+        _proto.styles = function styles(options) {
+          return mapRulesToStyle(this.cssRules(), options);
+        };
+
+        _proto.getIdAndRules = function getIdAndRules(props) {
+          var css = props.children,
+            dynamic = props.dynamic,
+            id = props.id;
+
+          if (dynamic) {
+            var styleId = (0, _hash.computeId)(id, dynamic);
+            return {
+              styleId: styleId,
+              rules: Array.isArray(css)
+                ? css.map(function(rule) {
+                    return (0, _hash.computeSelector)(styleId, rule);
+                  })
+                : [(0, _hash.computeSelector)(styleId, css)]
+            };
+          }
+
+          return {
+            styleId: (0, _hash.computeId)(id),
+            rules: Array.isArray(css) ? css : [css]
+          };
+        };
+        /**
+         * selectFromServer
+         *
+         * Collects style tags from the document with id __jsx-XXX
+         */
+
+        _proto.selectFromServer = function selectFromServer() {
+          var elements = Array.prototype.slice.call(
+            document.querySelectorAll('[id^="__jsx-"]')
+          );
+          return elements.reduce(function(acc, element) {
+            var id = element.id.slice(2);
+            acc[id] = element;
+            return acc;
+          }, {});
+        };
+
+        return StyleSheetRegistry;
+      })();
+
+      exports.StyleSheetRegistry = StyleSheetRegistry;
+
+      function invariant(condition, message) {
+        if (!condition) {
+          throw new Error("StyleSheetRegistry: " + message + ".");
+        }
+      }
+
+      var StyleSheetContext = (0, _react.createContext)(null);
+      exports.StyleSheetContext = StyleSheetContext;
+
+      function createStyleRegistry() {
+        return new StyleSheetRegistry();
+      }
+
+      function StyleRegistry(_ref2) {
+        var configuredRegistry = _ref2.registry,
+          children = _ref2.children;
+        var rootRegistry = (0, _react.useContext)(StyleSheetContext);
+
+        var _useState = (0, _react.useState)(function() {
+            return rootRegistry || configuredRegistry || createStyleRegistry();
+          }),
+          registry = _useState[0];
+
+        return _react["default"].createElement(
+          StyleSheetContext.Provider,
+          {
+            value: registry
+          },
+          children
+        );
+      }
+
+      function useStyleRegistry() {
+        return (0, _react.useContext)(StyleSheetContext);
+      }
+
+      /***/
+    },
+
+    /***/ XM5m: /***/ function(module, exports, __webpack_require__) {
+      module.exports = __webpack_require__("aIo7");
+
+      /***/
+    },
+
+    /***/ aIo7: /***/ function(module, exports, __webpack_require__) {
+      "use strict";
+
+      exports.__esModule = true;
+      exports.useStyleRegistry = exports.createStyleRegistry = exports.StyleRegistry = void 0;
+
+      var _stylesheetRegistry = __webpack_require__("SevZ");
+
+      exports.StyleRegistry = _stylesheetRegistry.StyleRegistry;
+      exports.createStyleRegistry = _stylesheetRegistry.createStyleRegistry;
+      exports.useStyleRegistry = _stylesheetRegistry.useStyleRegistry;
+
+      /***/
+    },
+
     /***/ bGXG: /***/ function(module, exports, __webpack_require__) {
       "use strict";
 
@@ -2618,6 +3187,357 @@ _N_E = (window["webpackJsonp_N_E"] = window["webpackJsonp_N_E"] || []).push([
       /***/
     },
 
+    /***/ bVZc: /***/ function(module, exports, __webpack_require__) {
+      "use strict";
+      /* WEBPACK VAR INJECTION */ (function(process) {
+        exports.__esModule = true;
+        exports["default"] = void 0;
+
+        function _defineProperties(target, props) {
+          for (var i = 0; i < props.length; i++) {
+            var descriptor = props[i];
+            descriptor.enumerable = descriptor.enumerable || false;
+            descriptor.configurable = true;
+            if ("value" in descriptor) descriptor.writable = true;
+            Object.defineProperty(target, descriptor.key, descriptor);
+          }
+        }
+
+        function _createClass(Constructor, protoProps, staticProps) {
+          if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+          if (staticProps) _defineProperties(Constructor, staticProps);
+          return Constructor;
+        }
+
+        /*
+Based on Glamor's sheet
+https://github.com/threepointone/glamor/blob/667b480d31b3721a905021b26e1290ce92ca2879/src/sheet.js
+*/
+        var isProd =
+          typeof process !== "undefined" &&
+          process.env &&
+          "production" === "production";
+
+        var isString = function isString(o) {
+          return Object.prototype.toString.call(o) === "[object String]";
+        };
+
+        var StyleSheet = /*#__PURE__*/ (function() {
+          function StyleSheet(_temp) {
+            var _ref = _temp === void 0 ? {} : _temp,
+              _ref$name = _ref.name,
+              name = _ref$name === void 0 ? "stylesheet" : _ref$name,
+              _ref$optimizeForSpeed = _ref.optimizeForSpeed,
+              optimizeForSpeed =
+                _ref$optimizeForSpeed === void 0
+                  ? isProd
+                  : _ref$optimizeForSpeed,
+              _ref$isBrowser = _ref.isBrowser,
+              isBrowser =
+                _ref$isBrowser === void 0
+                  ? typeof window !== "undefined"
+                  : _ref$isBrowser;
+
+            invariant(isString(name), "`name` must be a string");
+            this._name = name;
+            this._deletedRulePlaceholder = "#" + name + "-deleted-rule____{}";
+            invariant(
+              typeof optimizeForSpeed === "boolean",
+              "`optimizeForSpeed` must be a boolean"
+            );
+            this._optimizeForSpeed = optimizeForSpeed;
+            this._isBrowser = isBrowser;
+            this._serverSheet = undefined;
+            this._tags = [];
+            this._injected = false;
+            this._rulesCount = 0;
+            var node =
+              this._isBrowser &&
+              document.querySelector('meta[property="csp-nonce"]');
+            this._nonce = node ? node.getAttribute("content") : null;
+          }
+
+          var _proto = StyleSheet.prototype;
+
+          _proto.setOptimizeForSpeed = function setOptimizeForSpeed(bool) {
+            invariant(
+              typeof bool === "boolean",
+              "`setOptimizeForSpeed` accepts a boolean"
+            );
+            invariant(
+              this._rulesCount === 0,
+              "optimizeForSpeed cannot be when rules have already been inserted"
+            );
+            this.flush();
+            this._optimizeForSpeed = bool;
+            this.inject();
+          };
+
+          _proto.isOptimizeForSpeed = function isOptimizeForSpeed() {
+            return this._optimizeForSpeed;
+          };
+
+          _proto.inject = function inject() {
+            var _this = this;
+
+            invariant(!this._injected, "sheet already injected");
+            this._injected = true;
+
+            if (this._isBrowser && this._optimizeForSpeed) {
+              this._tags[0] = this.makeStyleTag(this._name);
+              this._optimizeForSpeed = "insertRule" in this.getSheet();
+
+              if (!this._optimizeForSpeed) {
+                if (!isProd) {
+                  console.warn(
+                    "StyleSheet: optimizeForSpeed mode not supported falling back to standard mode."
+                  );
+                }
+
+                this.flush();
+                this._injected = true;
+              }
+
+              return;
+            }
+
+            this._serverSheet = {
+              cssRules: [],
+              insertRule: function insertRule(rule, index) {
+                if (typeof index === "number") {
+                  _this._serverSheet.cssRules[index] = {
+                    cssText: rule
+                  };
+                } else {
+                  _this._serverSheet.cssRules.push({
+                    cssText: rule
+                  });
+                }
+
+                return index;
+              },
+              deleteRule: function deleteRule(index) {
+                _this._serverSheet.cssRules[index] = null;
+              }
+            };
+          };
+
+          _proto.getSheetForTag = function getSheetForTag(tag) {
+            if (tag.sheet) {
+              return tag.sheet;
+            } // this weirdness brought to you by firefox
+
+            for (var i = 0; i < document.styleSheets.length; i++) {
+              if (document.styleSheets[i].ownerNode === tag) {
+                return document.styleSheets[i];
+              }
+            }
+          };
+
+          _proto.getSheet = function getSheet() {
+            return this.getSheetForTag(this._tags[this._tags.length - 1]);
+          };
+
+          _proto.insertRule = function insertRule(rule, index) {
+            invariant(isString(rule), "`insertRule` accepts only strings");
+
+            if (!this._isBrowser) {
+              if (typeof index !== "number") {
+                index = this._serverSheet.cssRules.length;
+              
Post job cleanup.
[command]/usr/bin/git version
git version 2.33.0
[command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand
[command]/usr/bin/git submodule foreach --recursive git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :
[command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader
http.https://github.com/.extraheader
[command]/usr/bin/git config --local --unset-all http.https://github.com/.extraheader
[command]/usr/bin/git submodule foreach --recursive git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :
Cleaning up orphan processes
Commit: eb987991cf2f7f9896c07102b33781b007c84df6

Copy link
Member

@timneutkens timneutkens left a comment

Choose a reason for hiding this comment

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

Looks good!

@timneutkens timneutkens merged commit 57d9076 into vercel:canary Sep 9, 2021
@huozhi huozhi deleted the use-styled-v5 branch September 9, 2021 08:15
@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants