-
Notifications
You must be signed in to change notification settings - Fork 87
test: add test cases for unexpected permanent cdn cache control cases #2935
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
base: main
Are you sure you want to change the base?
test: add test cases for unexpected permanent cdn cache control cases #2935
Conversation
📊 Package size report 0.06%↑
Unchanged files
🤖 This report was automatically generated by pkg-size-action |
3c33a68
to
d7b02eb
Compare
d7b02eb
to
744891a
Compare
744891a
to
9fe6763
Compare
…s not during server initialization AND when read html is Next produced fully static html
let failBuildMock: Mock< | ||
Parameters<PluginContext['utils']['build']['failBuild']>, | ||
ReturnType<PluginContext['utils']['build']['failBuild']> | ||
> | ||
let failBuildMock: Mock<PluginContext['utils']['build']['failBuild']> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated, but as some point Vitest.Mock
type changed and instead of requiring separate params and return type, it now wants just mocked function type so while I was here I adjusted type
pagesManifest: { | ||
'/blog/[slug]': 'pages/blog/[slug].js', | ||
'/test': 'pages/test.html', | ||
'/test2': 'pages/test2.html', | ||
'/test3': 'pages/test3.js', | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
example of important piece of the fix which is using server/pages-manifest.json
to get pages paths that end with .html
which indicate fully static pages router page
|
||
try { | ||
await mkdir(destDir, { recursive: true }) | ||
await Promise.all( | ||
paths | ||
.filter((path) => !paths.includes(`${path.slice(0, -5)}.json`)) | ||
.filter((path) => !path.endsWith('.json') && !paths.includes(`${path.slice(0, -5)}.json`)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just small optim to return false early for json and avoid array search, doesn't change results, because if path
ends with .json
then paths will also include ${path.slice(0, -5)}.json
as it will be same path
const isFallback = fallbacks.includes(path.slice(0, -5)) | ||
const isFullyStaticPage = !isFallback && fullyStaticPages.includes(path) | ||
|
||
await writeFile( | ||
join(destDir, await encodeBlobKey(path)), | ||
JSON.stringify({ html, isFallback } satisfies HtmlBlob), | ||
JSON.stringify({ html, isFullyStaticPage } satisfies HtmlBlob), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we are no longer storing wether html blob is fallback, but we still use it to determine isFullyStaticPage
(this is probably not needed anymore, but doesn't seem to hurt to be doubly sure)
// modifying the next internals. | ||
// See https://github.com/vercel/next.js/blob/592401bb7fec83079716b2c9b090db580a63483f/packages/next/src/server/next-server.ts#L321-L327 | ||
// which starts NOT awaited async work | ||
await new Promise((resolve) => setTimeout(resolve, 5_000)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without some kind of sleep in function, it was VERY hit'n'miss wether issue was reproducable - with this sleep, at this locally it was always reprodicable - but because the whole issue is timing/async - this is not 100% test scenario, but I couldn't figure out anything better without doing some kind of modifications to next.js code itself
// load netlify.toml if it exists | ||
if (existsSync(join(ctx.cwd, 'netlify.toml'))) { | ||
const resolvedNetlifyConfig = await resolveNetlifyConfig({ cwd: ctx.cwd }) | ||
if (resolvedNetlifyConfig.config) { | ||
netlifyConfig = resolvedNetlifyConfig.config | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added this to support one of added test route handlers that reads non-nextjs produced html file and for that to work, we need to pass netlifyConfig produced from netlify.toml
which instructs bundling to include some external files
timeoutMs: 4_000, | ||
timeoutMs: 10_000, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bumped function invocation timeout to allow for 5s sleep in added test scenarios
if (!file.isFallback) { | ||
if (file.isFullyStaticPage) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isFullyStaticPage will be false for fallbacks, but also additionally it somewhat inverts the check to only set usedFsReadForNonFallback
for KNOWN static pages instead of not setting for fallbacks (but still setting it for everything else even if it's not pages router page)
@@ -51,6 +51,7 @@ | |||
"@fastly/http-compute-js": "1.1.5", | |||
"@netlify/blobs": "^8.2.0", | |||
"@netlify/build": "^32.2.0", | |||
"@netlify/config": "^23.0.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added dev dependency is used only in integration tests fixture setup - it's not being used otherwise
Description
We are catching fs.readFile for .html to set permanent caching header for fully static pages router pages (those that DON'T have
getStaticProps
orgetServerSideProps
). However this is quite leaky and it might catch cases when we should NOT do that:getStaticProps
orgetServerSideProps
- it will result in reading an.html
file (which as our trigger)This adds needed tracking to prevent second case from happening while preserving first one:
Documentation
Tests
Adding some tests that seems to catch problematic cases of not cacheable route handler getting cdn cache control set. Note that there is no great way to reproduce the problem - there is timing and async work involved - in added test I did add some "sleep" in route handler to allow that background work to hopefully finish which without any fixes reproduce problem of setting caching headers for responses that shouldn't have them
Relevant links (GitHub issues, etc.) or a picture of cute animal
https://linear.app/netlify/issue/FRB-1707/next-runtime-is-sending-cdn-cache-control-headers-unexpectedly