Skip to content

Commit

Permalink
Merge branch 'canary' into patch-3
Browse files Browse the repository at this point in the history
  • Loading branch information
miki-tebe authored Dec 24, 2024
2 parents 3345380 + 7a47ed5 commit a64b5f0
Show file tree
Hide file tree
Showing 31 changed files with 382 additions and 230 deletions.
95 changes: 50 additions & 45 deletions docs/01-app/03-building-your-application/10-deploying/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,15 @@ module.exports = class CacheHandler {
// Iterate over all entries in the cache
for (let [key, value] of cache) {
// If the value's tags include the specified tag, delete this entry
if (value.tags.some((tag) => tags.include(tag))) {
if (value.tags.some((tag) => tags.includes(tag))) {
cache.delete(key)
}
}
}

// If you want to have temporary in memory cache for a single request that is reset
// before the next request you can leverage this method
public resetRequestCache() {}
}
```

Expand Down Expand Up @@ -310,50 +314,51 @@ If you want to use `after` on custom infrastructure, check your provider documen
<details id="after-serverless">
<summary>Reference: supporting `after` for serverless platforms</summary>
Using `after` in a serverless context requires waiting for asynchronous tasks to finish after the response has been sent. In Next.js and Vercel, this is achieved using a primitive called `waitUntil(promise)`, which extends the lifetime of a serverless invocation until all promises passed to [`waitUntil`](https://vercel.com/docs/functions/functions-api-reference#waituntil) have settled.

If you want your users to be able to run `after`, you will have to provide your implementation of `waitUntil` that behaves in an analogous way.

When `after` is called, Next.js will access `waitUntil` like this:

```jsx
const RequestContext = globalThis[Symbol.for('@next/request-context')]
const contextValue = RequestContext?.get()
const waitUntil = context?.waitUntil
```
Which means that `globalThis[Symbol.for('@next/request-context')]` is expected to contain an object like this:
```tsx
type NextRequestContext = {
get(): NextRequestContextValue | undefined
}

type NextRequestContextValue = {
waitUntil?: (promise: Promise<any>) => void
}
```
Here is an example of the implementation.
```tsx
import { AsyncLocalStorage } from 'node:async_hooks'

const RequestContextStorage = new AsyncLocalStorage<NextRequestContextValue>()

// Define and inject the accessor that next.js will use
const RequestContext: NextRequestContext = {
get() {
return RequestContextStorage.getStore()
},
}
globalThis[Symbol.for('@next/request-context')] = RequestContext

const handler = (req, res) => {
const contextValue = { waitUntil: YOUR_WAITUNTIL }
// Provide the value
return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}
```

If you want your users to be able to run `after`, you will have to provide your implementation of `waitUntil` that behaves in an analogous way.

When `after` is called, Next.js will access `waitUntil` like this:

```jsx
const RequestContext = globalThis[Symbol.for('@next/request-context')]
const contextValue = RequestContext?.get()
const waitUntil = contextValue?.waitUntil
```
Which means that `globalThis[Symbol.for('@next/request-context')]` is expected to contain an object like this:
```tsx
type NextRequestContext = {
get(): NextRequestContextValue | undefined
}

type NextRequestContextValue = {
waitUntil?: (promise: Promise<any>) => void
}
```
Here is an example of the implementation.
```tsx
import { AsyncLocalStorage } from 'node:async_hooks'

const RequestContextStorage = new AsyncLocalStorage<NextRequestContextValue>()

// Define and inject the accessor that next.js will use
const RequestContext: NextRequestContext = {
get() {
return RequestContextStorage.getStore()
},
}
globalThis[Symbol.for('@next/request-context')] = RequestContext

const handler = (req, res) => {
const contextValue = { waitUntil: YOUR_WAITUNTIL }
// Provide the value
return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}
```
</details>
</AppOnly>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Create a `next.config.mjs` at the root of your project. This file will hold your
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // Outputs a Single-Page Application (SPA).
distDir: './build', // Changes the build output directory to `./dist`.
distDir: './build', // Changes the build output directory to `./build`.
}

export default nextConfig
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "15.1.1-canary.14"
"version": "15.1.1-canary.18"
}
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"keywords": [
"react",
"next",
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-config-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-config-next",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"description": "ESLint configuration used by Next.js.",
"main": "index.js",
"license": "MIT",
Expand All @@ -10,7 +10,7 @@
},
"homepage": "https://nextjs.org/docs/app/api-reference/config/eslint",
"dependencies": {
"@next/eslint-plugin-next": "15.1.1-canary.14",
"@next/eslint-plugin-next": "15.1.1-canary.18",
"@rushstack/eslint-patch": "^1.10.3",
"@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
"@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"description": "ESLint plugin for Next.js.",
"main": "dist/index.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/font/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@next/font",
"private": true,
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"repository": {
"url": "vercel/next.js",
"directory": "packages/font"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"main": "index.js",
"types": "index.d.ts",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-codemod/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-env/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/env",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-mdx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-plugin-storybook/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/plugin-storybook",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"repository": {
"url": "vercel/next.js",
"directory": "packages/next-plugin-storybook"
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-module/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-module",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)",
"main": "dist/polyfill-module.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-polyfill-nomodule/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/polyfill-nomodule",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"description": "A polyfill for non-dead, nomodule browsers.",
"main": "dist/polyfill-nomodule.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-swc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/swc",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"private": true,
"scripts": {
"clean": "node ../../scripts/rm.mjs native",
Expand Down
14 changes: 7 additions & 7 deletions packages/next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next",
"version": "15.1.1-canary.14",
"version": "15.1.1-canary.18",
"description": "The React Framework",
"main": "./dist/server/next.js",
"license": "MIT",
Expand Down Expand Up @@ -99,7 +99,7 @@
]
},
"dependencies": {
"@next/env": "15.1.1-canary.14",
"@next/env": "15.1.1-canary.18",
"@swc/counter": "0.1.3",
"@swc/helpers": "0.5.15",
"busboy": "1.6.0",
Expand Down Expand Up @@ -164,11 +164,11 @@
"@jest/types": "29.5.0",
"@mswjs/interceptors": "0.23.0",
"@napi-rs/triples": "1.2.0",
"@next/font": "15.1.1-canary.14",
"@next/polyfill-module": "15.1.1-canary.14",
"@next/polyfill-nomodule": "15.1.1-canary.14",
"@next/react-refresh-utils": "15.1.1-canary.14",
"@next/swc": "15.1.1-canary.14",
"@next/font": "15.1.1-canary.18",
"@next/polyfill-module": "15.1.1-canary.18",
"@next/polyfill-nomodule": "15.1.1-canary.18",
"@next/react-refresh-utils": "15.1.1-canary.18",
"@next/swc": "15.1.1-canary.18",
"@opentelemetry/api": "1.6.0",
"@playwright/test": "1.41.2",
"@storybook/addon-essentials": "^8.4.7",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export function Base() {
return (
<style>
{css`
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;900&family=Geist+Mono:wght@400;900&display=swap');
:host {
--size-gap-half: 4px;
--size-gap: 8px;
Expand Down Expand Up @@ -35,9 +37,10 @@ export function Base() {
--color-text-color-red-1: #ff5555;
--color-text-background-red-1: #fff9f9;
--font-stack-monospace: 'SFMono-Regular', Consolas, 'Liberation Mono',
Menlo, Courier, monospace;
--font-stack-sans: -apple-system, 'Source Sans Pro', sans-serif;
--font-stack-monospace: 'Geist Mono', 'SFMono-Regular', Consolas,
'Liberation Mono', Menlo, Courier, monospace;
--font-stack-sans: 'Geist', -apple-system, 'Source Sans Pro',
sans-serif;
--color-ansi-selection: rgba(95, 126, 151, 0.48);
--color-ansi-bg: #111111;
Expand All @@ -59,6 +62,8 @@ export function Base() {
--color-ansi-bright-magenta: #cebbff;
--color-ansi-bright-red: #ff8888;
--color-ansi-bright-yellow: #ffd966;
font-family: var(--font-stack-sans);
}
@media (prefers-color-scheme: dark) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export function updateCacheNodeOnNavigation(
oldRouterState: FlightRouterState,
newRouterState: FlightRouterState,
prefetchData: CacheNodeSeedData | null,
prefetchHead: HeadData,
prefetchHead: HeadData | null,
isPrefetchHeadPartial: boolean
): Task | null {
// Diff the old and new trees to reuse the shared layouts.
Expand Down Expand Up @@ -286,7 +286,7 @@ export function updateCacheNodeOnNavigation(
function createCacheNodeOnNavigation(
routerState: FlightRouterState,
prefetchData: CacheNodeSeedData | null,
possiblyPartialPrefetchHead: HeadData,
possiblyPartialPrefetchHead: HeadData | null,
isPrefetchHeadPartial: boolean
): Task {
// Same traversal as updateCacheNodeNavigation, but we switch to this path
Expand Down Expand Up @@ -387,7 +387,10 @@ function createCacheNodeOnNavigation(
// `prefetchRsc` field.
rsc,
prefetchRsc: null,
head: isLeafSegment ? possiblyPartialPrefetchHead : [null, null],
head: (isLeafSegment ? possiblyPartialPrefetchHead : null) ?? [
null,
null,
],
prefetchHead: null,
loading,
parallelRoutes: cacheNodeChildren,
Expand Down Expand Up @@ -422,7 +425,7 @@ function patchRouterStateWithNewChildren(
function spawnPendingTask(
routerState: FlightRouterState,
prefetchData: CacheNodeSeedData | null,
prefetchHead: React.ReactNode | null,
prefetchHead: HeadData | null,
isPrefetchHeadPartial: boolean
): Task {
// Create a task that will later be fulfilled by data from the server.
Expand Down Expand Up @@ -645,7 +648,7 @@ function finishTaskUsingDynamicDataPayload(
function createPendingCacheNode(
routerState: FlightRouterState,
prefetchData: CacheNodeSeedData | null,
prefetchHead: React.ReactNode | null,
prefetchHead: HeadData | null,
isPrefetchHeadPartial: boolean
): ReadyCacheNode {
const routerStateChildren = routerState[1]
Expand Down Expand Up @@ -685,7 +688,7 @@ function createPendingCacheNode(
parallelRoutes: parallelRoutes,

prefetchRsc: maybePrefetchRsc !== undefined ? maybePrefetchRsc : null,
prefetchHead: isLeafSegment ? prefetchHead : null,
prefetchHead: isLeafSegment ? prefetchHead : [null, null],

// TODO: Technically, a loading boundary could contain dynamic data. We must
// have separate `loading` and `prefetchLoading` fields to handle this, like
Expand Down Expand Up @@ -940,7 +943,7 @@ export function updateCacheNodeOnPopstateRestoration(
rsc,
head: oldCacheNode.head,

prefetchHead: shouldUsePrefetch ? oldCacheNode.prefetchHead : null,
prefetchHead: shouldUsePrefetch ? oldCacheNode.prefetchHead : [null, null],
prefetchRsc: shouldUsePrefetch ? oldCacheNode.prefetchRsc : null,
loading: oldCacheNode.loading,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function navigateUsingPrefetchedRouteTree(
currentFlightRouterState: FlightRouterState,
prefetchFlightRouterState: FlightRouterState,
prefetchSeedData: CacheNodeSeedData | null,
prefetchHead: HeadData,
prefetchHead: HeadData | null,
isPrefetchHeadPartial: boolean,
canonicalUrl: string
): SuccessfulNavigationResult | NoOpNavigationResult {
Expand Down Expand Up @@ -302,7 +302,7 @@ async function navigateDynamicallyWithNoPrefetch(
// In our simulated prefetch payload, we pretend that there's no seed data
// nor a prefetch head.
const prefetchSeedData = null
const prefetchHead: [null, null] = [null, null]
const prefetchHead = null
const isPrefetchHeadPartial = true

const canonicalUrl = createCanonicalUrl(
Expand Down
Loading

0 comments on commit a64b5f0

Please sign in to comment.