Skip to content

feat: support 'use cache' #2862

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

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

pieh
Copy link
Contributor

@pieh pieh commented Apr 22, 2025

Description

This is work in progress to support upcoming 'use cache' directive

Notes:
The primary need for custom Netlify cache handler implementation (the new one, that is used by 'use cache' directive) is that default implementation is in-memory only. While it seems like at least default handler for use cache doesn't need entries to be actually persisted - it still need to support tags (see cacheTag) properly and in serverless environment it means that we can't use in-memory only tag manifest like the default implementation does and will need to check with some persisted source of truth.

Review notes:
This PR contains also changes from following refactor PRs that it depends on.

To check just "use cache" specific changes without polluting diff with refactors use this compare view

Documentation

Tests

Primarily integration tests are being added for various use cache scenarios:

  • Is response cacheable on cdn? (static/dynamic page)
  • What use cache is used on (data fetching function, non-page react component, page react component, whole page module)

And test check behavior when executing against same serverless function instance, different serverless function instances (default cache is in-memory only, so to test behaviors it forces use of integration tests as you can't ensure hitting same or different serverless function in e2e), checking behaviors after tag invalidation (also depending on wether same serverless instance is used or not and that it should work the same in both cases because tags are shared, while cache entries themselves are not) and finally checking that expiry behavior works.

Tests failing on their own in https://github.com/opennextjs/opennextjs-netlify/actions/runs/14674525410/job/41267496397 (comment about most of tests passing - lot of test cases there do NOT test primary difference between Next.js's default cache handler and Netlify's implementation - only test related to revalidating tags on different lambda that is checked later - this is somewhat intentional because the whole cache handler is implemented here and doesn't reuse Next.js code - this is intentional to make sure any potentially future changes to default cache handler don't break any assumptions - and because we don't actually share code I added test cases just for overall cache handler behavior to make sure it works as expected)

Relevant links (GitHub issues, etc.) or a picture of cute animal

https://linear.app/netlify/issue/FRB-1405/[next15]-use-cache-not-persisted

Copy link
Contributor

github-actions bot commented Apr 22, 2025

📊 Package size report   2%↑

File Before (Size / Gzip) After (Size / Gzip)
dist/build/content/server.js 8.6 kB / 2.8 kB 6%↑9.1 kB / 7%↑3.0 kB
dist/run/config.js 1.3 kB / 644 B 0.8%↑1.3 kB / 0.8%↑649 B
dist/run/constants.js 516 B / 313 B 2%↑526 B / 2%↑319 B
dist/run/handlers/server.js 142.4 kB / 33.4 kB 0.08%↑142.6 kB / 0.08%↑33.5 kB
dist/run/handlers/tags-handler.cjs 9.7 kB / 3.2 kB 7%↑10.3 kB / 3%↑3.3 kB
dist/run/handlers/use-cache-handler.js 48.0 kB / 10.8 kB
package.json 3.0 kB / 1.1 kB 5%↑3.1 kB / 5%↑1.2 kB
Total (Includes all files) 2.8 MB / 803.8 kB 2%↑2.9 MB / 1%↑815.0 kB
Tarball size 761.9 kB 1%↑772.5 kB
Unchanged files
File Size (Size / Gzip)
dist/build/advanced-api-routes.js 4.3 kB / 1.4 kB
dist/build/cache.js 1.0 kB / 416 B
dist/build/content/next-shims/telemetry-storage.cjs 1.6 kB / 659 B
dist/build/content/prerendered.js 9.3 kB / 2.8 kB
dist/build/content/static.js 4.1 kB / 1.3 kB
dist/build/functions/edge.js 20.8 kB / 5.6 kB
dist/build/functions/server.js 4.9 kB / 1.6 kB
dist/build/image-cdn.js 54.0 kB / 11.1 kB
dist/build/plugin-context.js 10.1 kB / 3.0 kB
dist/build/templates/handler-monorepo.tmpl.js 1.6 kB / 643 B
dist/build/templates/handler.tmpl.js 1.4 kB / 596 B
dist/build/verification.js 4.5 kB / 1.6 kB
dist/esm-chunks/chunk-6BT4RYQJ.js 1.9 kB / 862 B
dist/esm-chunks/chunk-FKDTZJRV.js 27.0 kB / 5.4 kB
dist/esm-chunks/chunk-PFLHY2KD.js 61.2 kB / 11.1 kB
dist/esm-chunks/chunk-YUXQHOYO.js 187.9 kB / 33.2 kB
dist/index.js 3.4 kB / 1.1 kB
dist/run/handlers/cache.cjs 14.5 kB / 3.7 kB
dist/run/handlers/request-context.cjs 6.2 kB / 1.9 kB
dist/run/handlers/tracer.cjs 30.2 kB / 6.3 kB
dist/run/handlers/wait-until.cjs 1.4 kB / 665 B
dist/run/headers.js 8.2 kB / 2.6 kB
dist/run/next.cjs 23.5 kB / 5.8 kB
dist/run/revalidate.js 1.0 kB / 479 B
dist/run/storage/regional-blob-store.cjs 21.3 kB / 6.1 kB
dist/run/storage/request-scoped-in-memory-cache.cjs 47.4 kB / 10.9 kB
dist/run/storage/storage.cjs 4.0 kB / 1.3 kB
dist/shared/blob-types.cjs 1.6 kB / 640 B
dist/shared/blobkey.js 742 B / 400 B
dist/shared/cache-types.cjs 1.3 kB / 566 B
edge-runtime/lib/headers.ts 1.9 kB / 841 B
edge-runtime/lib/logging.ts 115 B / 121 B
edge-runtime/lib/middleware.test.ts 3.3 kB / 645 B
edge-runtime/lib/middleware.ts 3.3 kB / 1.3 kB
edge-runtime/lib/next-request.ts 3.3 kB / 1.1 kB
edge-runtime/lib/response.ts 10.0 kB / 3.0 kB
edge-runtime/lib/routing.ts 15.1 kB / 3.9 kB
edge-runtime/lib/util.test.ts 1.6 kB / 356 B
edge-runtime/lib/util.ts 3.7 kB / 1.3 kB
edge-runtime/matchers.json 3 B / 23 B
edge-runtime/middleware.ts 2.4 kB / 1.0 kB
edge-runtime/next.config.json 3 B / 23 B
edge-runtime/README.md 992 B / 509 B
edge-runtime/shim/index.js 1.5 kB / 717 B
edge-runtime/vendor.ts 745 B / 312 B
edge-runtime/vendor/deno.land/[email protected]/_util/asserts.ts 854 B / 461 B
edge-runtime/vendor/deno.land/[email protected]/_util/os.ts 644 B / 355 B
edge-runtime/vendor/deno.land/[email protected]/async/abortable.ts 4.0 kB / 1.0 kB
edge-runtime/vendor/deno.land/[email protected]/async/deadline.ts 974 B / 544 B
edge-runtime/vendor/deno.land/[email protected]/async/debounce.ts 2.2 kB / 956 B
edge-runtime/vendor/deno.land/[email protected]/async/deferred.ts 1.5 kB / 798 B
edge-runtime/vendor/deno.land/[email protected]/async/delay.ts 1.8 kB / 845 B
edge-runtime/vendor/deno.land/[email protected]/async/mod.ts 465 B / 241 B
edge-runtime/vendor/deno.land/[email protected]/async/mux_async_iterator.ts 2.5 kB / 1.1 kB
edge-runtime/vendor/deno.land/[email protected]/async/pool.ts 3.2 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/async/retry.ts 2.4 kB / 1.0 kB
edge-runtime/vendor/deno.land/[email protected]/async/tee.ts 2.1 kB / 924 B
edge-runtime/vendor/deno.land/[email protected]/bytes/index_of_needle.ts 1.4 kB / 668 B
edge-runtime/vendor/deno.land/[email protected]/crypto/timing_safe_equal.ts 875 B / 442 B
edge-runtime/vendor/deno.land/[email protected]/datetime/to_imf.ts 1.3 kB / 681 B
edge-runtime/vendor/deno.land/[email protected]/encoding/base64.ts 2.5 kB / 1.0 kB
edge-runtime/vendor/deno.land/[email protected]/encoding/base64url.ts 2.0 kB / 872 B
edge-runtime/vendor/deno.land/[email protected]/flags/mod.ts 22.6 kB / 5.9 kB
edge-runtime/vendor/deno.land/[email protected]/fmt/colors.ts 12.4 kB / 2.7 kB
edge-runtime/vendor/deno.land/[email protected]/fmt/printf.ts 27.7 kB / 7.7 kB
edge-runtime/vendor/deno.land/[email protected]/http/cookie.ts 11.5 kB / 3.6 kB
edge-runtime/vendor/deno.land/[email protected]/node/_core.ts 2.3 kB / 716 B
edge-runtime/vendor/deno.land/[email protected]/node/_events.d.ts 27.2 kB / 5.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/_events.mjs 28.0 kB / 7.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/_global.d.ts 1.7 kB / 650 B
edge-runtime/vendor/deno.land/[email protected]/node/_next_tick.ts 5.0 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/_process/exiting.ts 138 B / 138 B
edge-runtime/vendor/deno.land/[email protected]/node/_process/process.ts 3.8 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/_process/stdio.mjs 336 B / 233 B
edge-runtime/vendor/deno.land/[email protected]/node/_process/streams.mjs 4.0 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/_stream.d.ts 53.2 kB / 11.9 kB
edge-runtime/vendor/deno.land/[email protected]/node/_stream.mjs 91.2 kB / 25.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/_util/_util_callbackify.ts 4.3 kB / 1.7 kB
edge-runtime/vendor/deno.land/[email protected]/node/_utils.ts 5.9 kB / 2.0 kB
edge-runtime/vendor/deno.land/[email protected]/node/assert.ts 23.1 kB / 4.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/assertion_error.ts 19.6 kB / 6.1 kB
edge-runtime/vendor/deno.land/[email protected]/node/async_hooks.ts 7.7 kB / 2.1 kB
edge-runtime/vendor/deno.land/[email protected]/node/buffer.ts 262 B / 204 B
edge-runtime/vendor/deno.land/[email protected]/node/events.ts 303 B / 221 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/_libuv_winerror.ts 7.8 kB / 1.9 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/_listen.ts 561 B / 342 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/_node.ts 443 B / 335 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/_timingSafeEqual.ts 479 B / 268 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/_utils.ts 2.4 kB / 938 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/_winerror.ts 354.4 kB / 64.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/ares.ts 2.4 kB / 1.1 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/async_wrap.ts 4.0 kB / 1.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/buffer.ts 3.5 kB / 1.3 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/cares_wrap.ts 15.2 kB / 3.9 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/config.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/connection_wrap.ts 2.6 kB / 1.3 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/constants.ts 21.5 kB / 5.1 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/contextify.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/credentials.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/crypto.ts 448 B / 244 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/errors.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/fs_dir.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/fs_event_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/fs.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/handle_wrap.ts 1.8 kB / 1.0 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/heap_utils.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/http_parser.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/icu.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/inspector.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/js_stream.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/messaging.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/mod.ts 3.1 kB / 955 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/module_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/native_module.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/natives.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/node_file.ts 2.9 kB / 1.5 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/node_options.ts 1.8 kB / 989 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/options.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/os.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/performance.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/pipe_wrap.ts 10.4 kB / 3.3 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/process_methods.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/report.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/serdes.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/signal_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/spawn_sync.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/stream_wrap.ts 9.3 kB / 2.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/string_decoder.ts 504 B / 261 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/symbols.ts 1.4 kB / 828 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/task_queue.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/tcp_wrap.ts 13.1 kB / 3.7 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/timers.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/tls_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/trace_events.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/tty_wrap.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/types.ts 5.7 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/udp_wrap.ts 12.4 kB / 3.6 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/url.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/util.ts 4.0 kB / 1.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/uv.ts 20.1 kB / 3.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/v8.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/worker.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal_binding/zlib.ts 87 B / 104 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/buffer.d.ts 73.6 kB / 12.1 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/buffer.mjs 66.1 kB / 10.6 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/crypto/_keys.ts 463 B / 262 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/crypto/constants.ts 252 B / 173 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/error_codes.ts 322 B / 250 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/errors.ts 78.9 kB / 17.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/fixed_queue.ts 4.4 kB / 1.2 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/hide_stack_frames.ts 550 B / 377 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/net.ts 3.1 kB / 1.5 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/normalize_encoding.mjs 2.1 kB / 500 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/options.ts 1.7 kB / 959 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/primordials.mjs 1.8 kB / 431 B
edge-runtime/vendor/deno.land/[email protected]/node/internal/process/per_thread.mjs 7.8 kB / 2.3 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/readline/callbacks.mjs 3.8 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/readline/utils.mjs 14.3 kB / 3.7 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/streams/destroy.mjs 6.9 kB / 1.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/streams/end-of-stream.mjs 7.1 kB / 1.9 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/streams/utils.mjs 5.9 kB / 1.2 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/util.mjs 4.0 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/util/comparisons.ts 16.6 kB / 3.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/util/debuglog.ts 3.2 kB / 1.4 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/util/inspect.mjs 71.5 kB / 19.8 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/util/types.ts 3.7 kB / 1.3 kB
edge-runtime/vendor/deno.land/[email protected]/node/internal/validators.mjs 8.0 kB / 2.1 kB
edge-runtime/vendor/deno.land/[email protected]/node/process.ts 19.4 kB / 5.2 kB
edge-runtime/vendor/deno.land/[email protected]/node/stream.ts 671 B / 346 B
edge-runtime/vendor/deno.land/[email protected]/node/string_decoder.ts 10.3 kB / 3.3 kB
edge-runtime/vendor/deno.land/[email protected]/node/util.ts 7.8 kB / 2.2 kB
edge-runtime/vendor/deno.land/[email protected]/node/util/types.ts 199 B / 153 B
edge-runtime/vendor/deno.land/[email protected]/path/_constants.ts 2.0 kB / 727 B
edge-runtime/vendor/deno.land/[email protected]/path/_interface.ts 728 B / 369 B
edge-runtime/vendor/deno.land/[email protected]/path/_util.ts 5.0 kB / 1.6 kB
edge-runtime/vendor/deno.land/[email protected]/path/common.ts 1.2 kB / 607 B
edge-runtime/vendor/deno.land/[email protected]/path/glob.ts 12.7 kB / 3.9 kB
edge-runtime/vendor/deno.land/[email protected]/path/mod.ts 1.4 kB / 690 B
edge-runtime/vendor/deno.land/[email protected]/path/posix.ts 13.9 kB / 3.7 kB
edge-runtime/vendor/deno.land/[email protected]/path/separator.ts 259 B / 209 B
edge-runtime/vendor/deno.land/[email protected]/path/win32.ts 28.5 kB / 6.4 kB
edge-runtime/vendor/deno.land/[email protected]/streams/write_all.ts 2.2 kB / 598 B
edge-runtime/vendor/deno.land/[email protected]/testing/_diff.ts 11.6 kB / 3.6 kB
edge-runtime/vendor/deno.land/[email protected]/testing/_format.ts 705 B / 462 B
edge-runtime/vendor/deno.land/[email protected]/testing/asserts.ts 25.5 kB / 5.7 kB
edge-runtime/vendor/deno.land/[email protected]/types.d.ts 4.2 kB / 1.2 kB
edge-runtime/vendor/deno.land/x/[email protected]/pkg/htmlrewriter_bg.wasm 573.2 kB / 262.7 kB
edge-runtime/vendor/deno.land/x/[email protected]/pkg/htmlrewriter.js 31.0 kB / 4.7 kB
edge-runtime/vendor/deno.land/x/[email protected]/src/index.ts 2.6 kB / 989 B
edge-runtime/vendor/deno.land/x/[email protected]/src/types.d.ts 2.1 kB / 446 B
edge-runtime/vendor/deno.land/x/[email protected]/index.ts 15.4 kB / 4.2 kB
edge-runtime/vendor/import_map.json 148 B / 111 B
edge-runtime/vendor/v1-7-0--edge-utils.netlify.app/logger/logger.ts 3.2 kB / 747 B
edge-runtime/vendor/v1-7-0--edge-utils.netlify.app/logger/mod.ts 29 B / 49 B
LICENSE 1.1 kB / 661 B
manifest.yml 31 B / 51 B
README.md 2.8 kB / 1.2 kB

🤖 This report was automatically generated by pkg-size-action

@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch 3 times, most recently from de692a4 to 3b2a0f2 Compare April 22, 2025 15:16
@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch from 7fa0925 to 81fd1b4 Compare April 22, 2025 21:45
@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch 2 times, most recently from 4cd7931 to d51d811 Compare April 24, 2025 13:25
@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch 3 times, most recently from 7888b9a to 04d4a9b Compare April 24, 2025 20:56
@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch 2 times, most recently from 6b28b3b to a929442 Compare April 25, 2025 21:26
@pieh pieh added the test all versions Run e2e tests against old and canary versions of Next.js label Apr 25, 2025
@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch 2 times, most recently from 0e477cf to ecab0b9 Compare April 28, 2025 11:35
package.json Outdated
@@ -77,6 +77,7 @@
"msw": "^2.0.7",
"netlify-cli": "^20.1.1",
"next": "^15.0.0-canary.28",
"next-next": "npm:next@^15.3.1-canary.7",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is to get types for new use cache handler. I didn't want to touch next version we already use to not increase scope of this PR, as there is a lot of next types issues to solve in general.

Maybe this alias should be named better to indicate it's for use cache specifically (at least as of now)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This alias is now renamed

"next-with-cache-handler-v2": "npm:[email protected]",
, but leaving this comment open for visibility that another next version is being added here for types

Comment on lines 136 to 153
const writeRunConfig = async (ctx: PluginContext, standaloneNextConfig: NextConfigComplete) => {
// write our run-config.json to the root dir so that we can easily get the runtime config of the required-server-files.json
// without the need to know about the monorepo or distDir configuration upfront.
await writeFile(
join(ctx.serverHandlerDir, RUN_CONFIG_FILE),
JSON.stringify({
nextConfig: standaloneNextConfig,
// only enable setting up 'use cache' handler when Next.js supports CacheHandlerV2 as we don't have V1 compatible implementation
// see https://github.com/vercel/next.js/pull/76687 first released in v15.3.0-canary.13
enableUseCacheHandler: ctx.nextVersion
? satisfies(ctx.nextVersion, '>=15.3.0-canary.13', {
includePrerelease: true,
})
: false,
} satisfies RunConfig),
'utf-8',
)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is to make run-config.json file to also contain next-runtime toggles and not just Next.js config to allow us to conditionally enable some setups - in this case conditionally setup our use cache handler depending on version because using implementation in this PR that does not implement V1 variant is resulting in crashes due to some methods from V1 interface not being implemented

Copy link
Contributor Author

@pieh pieh Apr 29, 2025

Choose a reason for hiding this comment

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

This was moved since initially commented on, but leaving comment up for visibility as same change is still in this PR, just in slightly different place (to reduce amount of changes initial commits adding it introduced)

Comment on lines +28 to +48
/**
* Get the most recent revalidation timestamp for a list of tags
*/
export async function getMostRecentTagRevalidationTimestamp(tags: string[]) {
if (tags.length === 0) {
return 0
}

const cacheStore = getMemoizedKeyValueStoreBackedByRegionalBlobStore({ consistency: 'strong' })

const timestampsOrNulls = await Promise.all(
tags.map((tag) => getTagRevalidatedAt(tag, cacheStore)),
)

const timestamps = timestampsOrNulls.filter((timestamp) => timestamp !== null)
if (timestamps.length === 0) {
return 0
}
return Math.max(...timestamps)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To support interface of use cache handler we need method that will return most recent tag expiration timestamp .. or 0 if none of tags were ever revalidated (as opposed to just checking if tag is stale that is used in response cache handler)

Comment on lines 34 to 35
isErrored: boolean // pieh: this doesn't seem to be actually used in the default implementation
errorRetryCount: number // pieh: this doesn't seem to be actually used in the default implementation
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Those are only ever set, but never actually read, so possibly those should be removed. This interface is copied as-is from Next.js default implementation, so I did want to include this intentionally here for awareness

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was removed in 8a23cea

// eslint-disable-next-line @typescript-eslint/no-empty-function
const tmpResolvePendingBeforeCreatingAPromise = () => {}

export const NetlifyDefaultUseCacheHandler = {
Copy link
Contributor Author

@pieh pieh Apr 28, 2025

Choose a reason for hiding this comment

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

This is mostly copy & paste from Next.js default cache handler except for tags handling and added OTEL

Copy link
Contributor

@mrstork mrstork Apr 28, 2025

Choose a reason for hiding this comment

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

Could we please add a reference comment to what this was modelled after?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I should clear this up -

// copied from default implementation
// packages/next/src/server/lib/cache-handlers/default.ts
refers to most of this module (not just immediate surrounding) - but I should probably do bigger explainer there and do some separation from code immediately after this comment (and also link to some specific version of it with github link with SHA so it's clear what version this was originally modeled after)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hopefully added more clear description in 8a23cea

@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch 2 times, most recently from 1679b5e to e8eb0c1 Compare April 28, 2025 17:56
}

// eslint-disable-next-line @typescript-eslint/no-empty-function
const tmpResolvePendingBeforeCreatingAPromise = () => {}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is our temp variable, or was this also copy pasted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it was originally same as in https://github.com/vercel/next.js/blob/0eb78fd629858858a5a31591b3b3de294762f870/packages/next/src/server/lib/cache-handlers/default.ts#L101, just our lintings rule didn't like defining this temporary no-op function in the same place:

image

and to me, the rule mede sense so I did move it to outer scope

the purpose of tmp function there that we re-assign in the new Promise callback in the first place is to make typescript happy, because otherwise resolvePending is either nullable or we have to force a type, so none of the options are really great and I just thought the way it currently is was the least worst option

Comment on lines +120 to +119
if (ttl < 0) {
// In-memory caches should expire after revalidate time because it is
// unlikely that a new entry will be able to be used before it is dropped
// from the cache.
Copy link
Contributor

@mrstork mrstork Apr 28, 2025

Choose a reason for hiding this comment

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

Is there any handling around the "stale while revalidate" case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

return undefined
}

if (await isAnyTagStale(entry.tags, entry.timestamp)) {
Copy link
Contributor

@mrstork mrstork Apr 28, 2025

Choose a reason for hiding this comment

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

Learning - If any tag is stale, then the entry is stale? So if for example _n_t_/layout became stale then every page using that tag would also be stale? (since it's often the top level tag for an entry)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's correct - so if you mark layout as stale - then all pages that use that layout are stale and should be regenerated on next opportunity

useCacheTagPrefix: 'data',
expectedCachingBehaviorWhenUseCacheRegenerates: {
// getData function has 'use cache' so it should report same generation time, everything else is dynamically regenerated on each request
getDataTimeShouldShouldBeEqual: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't believe the double Should is intentional

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed typo in e18b9b8 🤞

@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch 2 times, most recently from 2bac965 to 359cc10 Compare April 29, 2025 10:56
@pieh pieh force-pushed the michalpiechowiak/frb-1405-next15-use-cache-not-persisted branch from 359cc10 to 8a23cea Compare April 29, 2025 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
test all versions Run e2e tests against old and canary versions of Next.js
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants