-
Notifications
You must be signed in to change notification settings - Fork 27k
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 hydration middleware effects #31800
Fix hydration middleware effects #31800
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Failing test suitesCommit: 7048fa8 test/integration/middleware/core/test/index.test.js
Expand output● Middleware base tests › dev mode › renders correctly rewriting with a root subrequest
● Middleware base tests › dev mode › /fr renders correctly rewriting with a root subrequest
● Middleware base tests › production mode › renders correctly rewriting with a root subrequest
● Middleware base tests › production mode › /fr renders correctly rewriting with a root subrequest
|
To run middleware we are using a **sandbox** that emulates the web runtime and keeps a module cache. This cache is shared for all of the modules that we run using the sandbox while there are some module-level APIs that must be scoped depending on the module we are running. One example of this is `fetch` where we want to always inject a special header that indicate the module that is performing the fetch and use it to avoid getting into infinite loops for middleware. For those cases the cached implementation will be the first one that instantiates the module and therefore we can actually get into infinite loops. This is the reason why #31800 is failing. With this PR we refactor the sandbox so that the module cache is scoped per module name. This means that one execution of a middleware will preserve its cache only for that module so that each execution will still have its own `fetch` implementation, fixing this issue. Also, with this refactor the code is more clear and we also provide an option to avoid using the cache. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint`
Stats from current PRDefault Build (Decrease detected ✓)General Overall increase
|
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
buildDuration | 18.4s | 18.5s | |
buildDurationCached | 3.4s | 3.3s | -92ms |
nodeModulesSize | 345 MB | 345 MB |
Page Load Tests Overall decrease ⚠️
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 2.948 | 2.992 | |
/ avg req/sec | 848.13 | 835.58 | |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.367 | 1.366 | 0 |
/error-in-render avg req/sec | 1828.25 | 1829.83 | +1.58 |
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
450.HASH.js gzip | 179 B | 179 B | ✓ |
framework-HASH.js gzip | 42.2 kB | 42.2 kB | ✓ |
main-HASH.js gzip | 28.4 kB | 28.4 kB | |
webpack-HASH.js gzip | 1.45 kB | 1.45 kB | ✓ |
Overall change | 72.2 kB | 72.2 kB |
Legacy Client Bundles (polyfills)
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
_app-HASH.js gzip | 1.37 kB | 1.37 kB | ✓ |
_error-HASH.js gzip | 194 B | 194 B | ✓ |
amp-HASH.js gzip | 312 B | 312 B | ✓ |
css-HASH.js gzip | 327 B | 327 B | ✓ |
dynamic-HASH.js gzip | 2.38 kB | 2.38 kB | ✓ |
head-HASH.js gzip | 350 B | 350 B | ✓ |
hooks-HASH.js gzip | 635 B | 635 B | ✓ |
image-HASH.js gzip | 4.45 kB | 4.45 kB | ✓ |
index-HASH.js gzip | 263 B | 263 B | ✓ |
link-HASH.js gzip | 1.87 kB | 1.87 kB | ✓ |
routerDirect..HASH.js gzip | 321 B | 321 B | ✓ |
script-HASH.js gzip | 383 B | 383 B | ✓ |
withRouter-HASH.js gzip | 318 B | 318 B | ✓ |
85e02e95b279..7e3.css gzip | 107 B | 107 B | ✓ |
Overall change | 13.3 kB | 13.3 kB | ✓ |
Client Build Manifests
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
_buildManifest.js gzip | 460 B | 460 B | ✓ |
Overall change | 460 B | 460 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
index.html gzip | 532 B | 532 B | ✓ |
link.html gzip | 545 B | 545 B | ✓ |
withRouter.html gzip | 526 B | 526 B | ✓ |
Overall change | 1.6 kB | 1.6 kB | ✓ |
Diffs
Diff for main-HASH.js
@@ -4857,7 +4857,11 @@
delBasePath(resolvedAs),
this.locale
);
- _ctx.next = 64;
+ if (!(options._h !== 1)) {
+ _ctx.next = 82;
+ break;
+ }
+ _ctx.next = 65;
return this._preflightRequest({
as: as,
cache: "production" === "production",
@@ -4865,10 +4869,10 @@
pathname: pathname,
query: query
});
- case 64:
+ case 65:
effect = _ctx.sent;
if (!(effect.type === "rewrite")) {
- _ctx.next = 69;
+ _ctx.next = 70;
break;
}
{
@@ -4882,13 +4886,13 @@
parsed.pathname = effect.resolvedHref;
url = (0, _utils).formatWithValidation(parsed);
}
- _ctx.next = 81;
+ _ctx.next = 82;
break;
- case 69:
+ case 70:
if (
!(effect.type === "redirect" && effect.newAs)
) {
- _ctx.next = 73;
+ _ctx.next = 74;
break;
}
return _ctx.abrupt(
@@ -4900,14 +4904,14 @@
options
)
);
- case 73:
+ case 74:
if (
!(
effect.type === "redirect" &&
effect.destination
)
) {
- _ctx.next = 78;
+ _ctx.next = 79;
break;
}
window.location.href = effect.destination;
@@ -4915,9 +4919,9 @@
"return",
new Promise(function() {})
);
- case 78:
+ case 79:
if (!(effect.type === "refresh")) {
- _ctx.next = 81;
+ _ctx.next = 82;
break;
}
window.location.href = as;
@@ -4925,13 +4929,13 @@
"return",
new Promise(function() {})
);
- case 81:
+ case 82:
route = (0,
_normalizeTrailingSlash).removePathTrailingSlash(
pathname
);
if (!(0, _isDynamic).isDynamicRoute(route)) {
- _ctx.next = 97;
+ _ctx.next = 98;
break;
}
parsedAs1 = (0,
@@ -4953,7 +4957,7 @@
(shouldInterpolate && !interpolatedAs.result)
)
) {
- _ctx.next = 96;
+ _ctx.next = 97;
break;
}
missingParams = Object.keys(
@@ -4962,7 +4966,7 @@
return !query[param];
});
if (!(missingParams.length > 0)) {
- _ctx.next = 94;
+ _ctx.next = 95;
break;
}
if (false) {
@@ -4990,10 +4994,10 @@
: "incompatible-href-as"
)
);
- case 94:
- _ctx.next = 97;
+ case 95:
+ _ctx.next = 98;
break;
- case 96:
+ case 97:
if (shouldInterpolate) {
as = (0, _utils).formatWithValidation(
Object.assign({}, parsedAs1, {
@@ -5008,14 +5012,14 @@
// Merge params into `query`, overwriting any specified in search
Object.assign(query, routeMatch);
}
- case 97:
+ case 98:
Router.events.emit(
"routeChangeStart",
as,
routeProps
);
- _ctx.prev = 98;
- _ctx.next = 102;
+ _ctx.prev = 99;
+ _ctx.next = 103;
return this.getRouteInfo(
route,
pathname,
@@ -5024,14 +5028,14 @@
resolvedAs,
routeProps
);
- case 102:
+ case 103:
routeInfo = _ctx.sent;
(error = routeInfo.error),
(props = routeInfo.props),
(__N_SSG = routeInfo.__N_SSG),
(__N_SSP = routeInfo.__N_SSP);
if (!((__N_SSG || __N_SSP) && props)) {
- _ctx.next = 129;
+ _ctx.next = 130;
break;
}
if (
@@ -5040,7 +5044,7 @@
props.pageProps.__N_REDIRECT
)
) {
- _ctx.next = 114;
+ _ctx.next = 115;
break;
}
destination = props.pageProps.__N_REDIRECT;
@@ -5051,7 +5055,7 @@
false
)
) {
- _ctx.next = 112;
+ _ctx.next = 113;
break;
}
parsedHref = (0,
@@ -5071,31 +5075,31 @@
"return",
this.change(method, newUrl, newAs, options)
);
- case 112:
+ case 113:
window.location.href = destination;
return _ctx.abrupt(
"return",
new Promise(function() {})
);
- case 114:
+ case 115:
this.isPreview = !!props.__N_PREVIEW;
if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
- _ctx.next = 129;
+ _ctx.next = 130;
break;
}
- _ctx.prev = 117;
- _ctx.next = 120;
+ _ctx.prev = 118;
+ _ctx.next = 121;
return this.fetchComponent("/404");
- case 120:
+ case 121:
notFoundRoute = "/404";
- _ctx.next = 126;
+ _ctx.next = 127;
break;
- case 123:
- _ctx.prev = 123;
- _ctx.t1 = _ctx["catch"](117);
+ case 124:
+ _ctx.prev = 124;
+ _ctx.t1 = _ctx["catch"](118);
notFoundRoute = "/_error";
- case 126:
- _ctx.next = 128;
+ case 127:
+ _ctx.next = 129;
return this.getRouteInfo(
notFoundRoute,
notFoundRoute,
@@ -5106,9 +5110,9 @@
shallow: false
}
);
- case 128:
- routeInfo = _ctx.sent;
case 129:
+ routeInfo = _ctx.sent;
+ case 130:
Router.events.emit(
"beforeHistoryChange",
as,
@@ -5146,7 +5150,7 @@
y: 0
}
: null;
- _ctx.next = 138;
+ _ctx.next = 139;
return this.set(
route,
pathname,
@@ -5160,9 +5164,9 @@
if (e.cancelled) error = error || e;
else throw e;
});
- case 138:
+ case 139:
if (!error) {
- _ctx.next = 141;
+ _ctx.next = 142;
break;
}
Router.events.emit(
@@ -5172,7 +5176,7 @@
routeProps
);
throw error;
- case 141:
+ case 142:
if (false) {
}
Router.events.emit(
@@ -5181,22 +5185,22 @@
routeProps
);
return _ctx.abrupt("return", true);
- case 146:
- _ctx.prev = 146;
- _ctx.t2 = _ctx["catch"](98);
+ case 147:
+ _ctx.prev = 147;
+ _ctx.t2 = _ctx["catch"](99);
if (
!(
(0, _isError).default(_ctx.t2) &&
_ctx.t2.cancelled
)
) {
- _ctx.next = 150;
+ _ctx.next = 151;
break;
}
return _ctx.abrupt("return", false);
- case 150:
- throw _ctx.t2;
case 151:
+ throw _ctx.t2;
+ case 152:
case "end":
return _ctx.stop();
}
@@ -5205,8 +5209,8 @@
this,
[
[38, 48],
- [98, 146],
- [117, 123]
+ [99, 147],
+ [118, 124]
]
);
})
Diff for index.html
@@ -19,7 +19,7 @@
defer=""
></script>
<script
- src="/_next/static/chunks/main-1ca0ccbd7527884f.js"
+ src="/_next/static/chunks/main-6d578880106ad8e2.js"
defer=""
></script>
<script
Diff for link.html
@@ -19,7 +19,7 @@
defer=""
></script>
<script
- src="/_next/static/chunks/main-1ca0ccbd7527884f.js"
+ src="/_next/static/chunks/main-6d578880106ad8e2.js"
defer=""
></script>
<script
Diff for withRouter.html
@@ -19,7 +19,7 @@
defer=""
></script>
<script
- src="/_next/static/chunks/main-1ca0ccbd7527884f.js"
+ src="/_next/static/chunks/main-6d578880106ad8e2.js"
defer=""
></script>
<script
Default Build with SWC (Increase detected ⚠️ )
General Overall increase ⚠️
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
buildDuration | 19.6s | 19.2s | -471ms |
buildDurationCached | 3.3s | 3.4s | |
nodeModulesSize | 345 MB | 345 MB |
Page Load Tests Overall decrease ⚠️
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
/ failed reqs | 0 | 0 | ✓ |
/ total time (seconds) | 2.738 | 2.957 | |
/ avg req/sec | 913.18 | 845.5 | |
/error-in-render failed reqs | 0 | 0 | ✓ |
/error-in-render total time (seconds) | 1.349 | 1.405 | |
/error-in-render avg req/sec | 1852.72 | 1779.1 |
Client Bundles (main, webpack, commons) Overall increase ⚠️
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
450.HASH.js gzip | 179 B | 179 B | ✓ |
framework-HASH.js gzip | 42.3 kB | 42.3 kB | ✓ |
main-HASH.js gzip | 28.6 kB | 28.6 kB | |
webpack-HASH.js gzip | 1.44 kB | 1.44 kB | ✓ |
Overall change | 72.5 kB | 72.5 kB |
Legacy Client Bundles (polyfills)
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 31 kB | 31 kB | ✓ |
Overall change | 31 kB | 31 kB | ✓ |
Client Pages
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
_app-HASH.js gzip | 1.35 kB | 1.35 kB | ✓ |
_error-HASH.js gzip | 180 B | 180 B | ✓ |
amp-HASH.js gzip | 305 B | 305 B | ✓ |
css-HASH.js gzip | 321 B | 321 B | ✓ |
dynamic-HASH.js gzip | 2.37 kB | 2.37 kB | ✓ |
head-HASH.js gzip | 342 B | 342 B | ✓ |
hooks-HASH.js gzip | 622 B | 622 B | ✓ |
image-HASH.js gzip | 4.47 kB | 4.47 kB | ✓ |
index-HASH.js gzip | 256 B | 256 B | ✓ |
link-HASH.js gzip | 1.91 kB | 1.91 kB | ✓ |
routerDirect..HASH.js gzip | 314 B | 314 B | ✓ |
script-HASH.js gzip | 375 B | 375 B | ✓ |
withRouter-HASH.js gzip | 309 B | 309 B | ✓ |
85e02e95b279..7e3.css gzip | 107 B | 107 B | ✓ |
Overall change | 13.2 kB | 13.2 kB | ✓ |
Client Build Manifests
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
_buildManifest.js gzip | 458 B | 458 B | ✓ |
Overall change | 458 B | 458 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | javivelasco/next.js fix-hydration-middleware-effects | Change | |
---|---|---|---|
index.html gzip | 531 B | 532 B | |
link.html gzip | 545 B | 544 B | -1 B |
withRouter.html gzip | 526 B | 526 B | ✓ |
Overall change | 1.6 kB | 1.6 kB | ✓ |
Diffs
Diff for main-HASH.js
@@ -4857,7 +4857,11 @@
delBasePath(resolvedAs),
this.locale
);
- _ctx.next = 64;
+ if (!(options._h !== 1)) {
+ _ctx.next = 82;
+ break;
+ }
+ _ctx.next = 65;
return this._preflightRequest({
as: as,
cache: "production" === "production",
@@ -4865,10 +4869,10 @@
pathname: pathname,
query: query
});
- case 64:
+ case 65:
effect = _ctx.sent;
if (!(effect.type === "rewrite")) {
- _ctx.next = 69;
+ _ctx.next = 70;
break;
}
{
@@ -4882,13 +4886,13 @@
parsed.pathname = effect.resolvedHref;
url = (0, _utils).formatWithValidation(parsed);
}
- _ctx.next = 81;
+ _ctx.next = 82;
break;
- case 69:
+ case 70:
if (
!(effect.type === "redirect" && effect.newAs)
) {
- _ctx.next = 73;
+ _ctx.next = 74;
break;
}
return _ctx.abrupt(
@@ -4900,14 +4904,14 @@
options
)
);
- case 73:
+ case 74:
if (
!(
effect.type === "redirect" &&
effect.destination
)
) {
- _ctx.next = 78;
+ _ctx.next = 79;
break;
}
window.location.href = effect.destination;
@@ -4915,9 +4919,9 @@
"return",
new Promise(function() {})
);
- case 78:
+ case 79:
if (!(effect.type === "refresh")) {
- _ctx.next = 81;
+ _ctx.next = 82;
break;
}
window.location.href = as;
@@ -4925,13 +4929,13 @@
"return",
new Promise(function() {})
);
- case 81:
+ case 82:
route = (0,
_normalizeTrailingSlash).removePathTrailingSlash(
pathname
);
if (!(0, _isDynamic).isDynamicRoute(route)) {
- _ctx.next = 97;
+ _ctx.next = 98;
break;
}
parsedAs1 = (0,
@@ -4953,7 +4957,7 @@
(shouldInterpolate && !interpolatedAs.result)
)
) {
- _ctx.next = 96;
+ _ctx.next = 97;
break;
}
missingParams = Object.keys(
@@ -4962,7 +4966,7 @@
return !query[param];
});
if (!(missingParams.length > 0)) {
- _ctx.next = 94;
+ _ctx.next = 95;
break;
}
if (false) {
@@ -4990,10 +4994,10 @@
: "incompatible-href-as"
)
);
- case 94:
- _ctx.next = 97;
+ case 95:
+ _ctx.next = 98;
break;
- case 96:
+ case 97:
if (shouldInterpolate) {
as = (0, _utils).formatWithValidation(
Object.assign({}, parsedAs1, {
@@ -5008,14 +5012,14 @@
// Merge params into `query`, overwriting any specified in search
Object.assign(query, routeMatch);
}
- case 97:
+ case 98:
Router.events.emit(
"routeChangeStart",
as,
routeProps
);
- _ctx.prev = 98;
- _ctx.next = 102;
+ _ctx.prev = 99;
+ _ctx.next = 103;
return this.getRouteInfo(
route,
pathname,
@@ -5024,14 +5028,14 @@
resolvedAs,
routeProps
);
- case 102:
+ case 103:
routeInfo = _ctx.sent;
(error = routeInfo.error),
(props = routeInfo.props),
(__N_SSG = routeInfo.__N_SSG),
(__N_SSP = routeInfo.__N_SSP);
if (!((__N_SSG || __N_SSP) && props)) {
- _ctx.next = 129;
+ _ctx.next = 130;
break;
}
if (
@@ -5040,7 +5044,7 @@
props.pageProps.__N_REDIRECT
)
) {
- _ctx.next = 114;
+ _ctx.next = 115;
break;
}
destination = props.pageProps.__N_REDIRECT;
@@ -5051,7 +5055,7 @@
false
)
) {
- _ctx.next = 112;
+ _ctx.next = 113;
break;
}
parsedHref = (0,
@@ -5071,31 +5075,31 @@
"return",
this.change(method, newUrl, newAs, options)
);
- case 112:
+ case 113:
window.location.href = destination;
return _ctx.abrupt(
"return",
new Promise(function() {})
);
- case 114:
+ case 115:
this.isPreview = !!props.__N_PREVIEW;
if (!(props.notFound === SSG_DATA_NOT_FOUND)) {
- _ctx.next = 129;
+ _ctx.next = 130;
break;
}
- _ctx.prev = 117;
- _ctx.next = 120;
+ _ctx.prev = 118;
+ _ctx.next = 121;
return this.fetchComponent("/404");
- case 120:
+ case 121:
notFoundRoute = "/404";
- _ctx.next = 126;
+ _ctx.next = 127;
break;
- case 123:
- _ctx.prev = 123;
- _ctx.t1 = _ctx["catch"](117);
+ case 124:
+ _ctx.prev = 124;
+ _ctx.t1 = _ctx["catch"](118);
notFoundRoute = "/_error";
- case 126:
- _ctx.next = 128;
+ case 127:
+ _ctx.next = 129;
return this.getRouteInfo(
notFoundRoute,
notFoundRoute,
@@ -5106,9 +5110,9 @@
shallow: false
}
);
- case 128:
- routeInfo = _ctx.sent;
case 129:
+ routeInfo = _ctx.sent;
+ case 130:
Router.events.emit(
"beforeHistoryChange",
as,
@@ -5146,7 +5150,7 @@
y: 0
}
: null;
- _ctx.next = 138;
+ _ctx.next = 139;
return this.set(
route,
pathname,
@@ -5160,9 +5164,9 @@
if (e.cancelled) error = error || e;
else throw e;
});
- case 138:
+ case 139:
if (!error) {
- _ctx.next = 141;
+ _ctx.next = 142;
break;
}
Router.events.emit(
@@ -5172,7 +5176,7 @@
routeProps
);
throw error;
- case 141:
+ case 142:
if (false) {
}
Router.events.emit(
@@ -5181,22 +5185,22 @@
routeProps
);
return _ctx.abrupt("return", true);
- case 146:
- _ctx.prev = 146;
- _ctx.t2 = _ctx["catch"](98);
+ case 147:
+ _ctx.prev = 147;
+ _ctx.t2 = _ctx["catch"](99);
if (
!(
(0, _isError).default(_ctx.t2) &&
_ctx.t2.cancelled
)
) {
- _ctx.next = 150;
+ _ctx.next = 151;
break;
}
return _ctx.abrupt("return", false);
- case 150:
- throw _ctx.t2;
case 151:
+ throw _ctx.t2;
+ case 152:
case "end":
return _ctx.stop();
}
@@ -5205,8 +5209,8 @@
this,
[
[38, 48],
- [98, 146],
- [117, 123]
+ [99, 147],
+ [118, 124]
]
);
})
Diff for index.html
@@ -19,7 +19,7 @@
defer=""
></script>
<script
- src="/_next/static/chunks/main-1ca0ccbd7527884f.js"
+ src="/_next/static/chunks/main-6d578880106ad8e2.js"
defer=""
></script>
<script
Diff for link.html
@@ -19,7 +19,7 @@
defer=""
></script>
<script
- src="/_next/static/chunks/main-1ca0ccbd7527884f.js"
+ src="/_next/static/chunks/main-6d578880106ad8e2.js"
defer=""
></script>
<script
Diff for withRouter.html
@@ -19,7 +19,7 @@
defer=""
></script>
<script
- src="/_next/static/chunks/main-1ca0ccbd7527884f.js"
+ src="/_next/static/chunks/main-6d578880106ad8e2.js"
defer=""
></script>
<script
Whenever we trigger a route change in the client we check if there route we are navigating to is affected by a middleware. When this is the case we run a preflight and in case there is an effect that tells us that the middleware is responding with content we force a refresh. This is fine for navigation in general but it is not ok when the change is triggered for hydration. For example, in cases where the rendered page is a dynamic page this triggers an infinite reload.
In this PR we add a test where we add a
_middleware
that proxies to a dynamic path. When making a request to/interface/root-subrequest
there will be a middleware that simply performs a fetch against localhost for the same/interface/root-subrequest
. The new request will skip the middleware to avoid loops and then render the dynamic page. Then client will force a change for hydration resulting in a preflight request that tells that the client must refresh because for that path there is a middleware writing content.Then we add a fix which simply consist of checking the internal option that tells when a change is triggered for hydration and skip the preflight in such scenario.
Bug
fixes #number
contributing.md
Feature
fixes #number
contributing.md
Documentation / Examples
yarn lint