Skip to content

Commit

Permalink
Re-enable sandbox cache and update AsyncLocalStorage usage (#42547)
Browse files Browse the repository at this point in the history
Follow-up to #41402 this
re-enables the sandbox cache and updates to leverage our global
`AsyncLocalStorage` for isolating request meta in both the edge and
Node.js runtime.

Closes: #42349
Closes: #38235
Closes: #42225
Closes: #42351

## Bug

- [x] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have a 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 a helpful link attached, see `contributing.md`

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm build && pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
  • Loading branch information
ijjk committed Nov 6, 2022
1 parent 48dbdf9 commit 98106ba
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 81 deletions.
4 changes: 4 additions & 0 deletions packages/next/build/utils.ts
Expand Up @@ -59,6 +59,10 @@ if (process.env.NEXT_PREBUNDLED_REACT) {
overrideBuiltInReactPackages()
}

// expose AsyncLocalStorage on global for react usage
const { AsyncLocalStorage } = require('async_hooks')
;(global as any).AsyncLocalStorage = AsyncLocalStorage

export type ROUTER_TYPE = 'pages' | 'app'

const RESERVED_PAGE = /^\/(_app|_error|_document|api(\/|$))/
Expand Down
6 changes: 4 additions & 2 deletions packages/next/client/components/request-async-storage.ts
Expand Up @@ -13,6 +13,8 @@ export interface RequestStore {
export let requestAsyncStorage: AsyncLocalStorage<RequestStore> | RequestStore =
{} as any

if (process.env.NEXT_RUNTIME !== 'edge' && typeof window === 'undefined') {
requestAsyncStorage = new (require('async_hooks').AsyncLocalStorage)()
// @ts-expect-error we provide this on global in
// the edge and node runtime
if (global.AsyncLocalStorage) {
requestAsyncStorage = new (global as any).AsyncLocalStorage()
}
23 changes: 19 additions & 4 deletions packages/next/client/components/static-generation-async-storage.ts
@@ -1,4 +1,19 @@
export {
staticGenerationAsyncStorage,
StaticGenerationStore,
} from './static-generation-async-storage/storage.js'
import type { AsyncLocalStorage } from 'async_hooks'

export interface StaticGenerationStore {
inUse?: boolean
pathname?: string
revalidate?: number
fetchRevalidate?: number
isStaticGeneration?: boolean
}

export let staticGenerationAsyncStorage:
| AsyncLocalStorage<StaticGenerationStore>
| StaticGenerationStore = {}

// @ts-expect-error we provide this on global in
// the edge and node runtime
if (global.AsyncLocalStorage) {

This comment has been minimized.

Copy link
@sokra

sokra Nov 8, 2022

Member

Using global breaks turbopack, we need to fix that before this is released...

staticGenerationAsyncStorage = new (global as any).AsyncLocalStorage()
}

This file was deleted.

This file was deleted.

This file was deleted.

4 changes: 4 additions & 0 deletions packages/next/export/worker.ts
Expand Up @@ -100,6 +100,10 @@ interface RenderOpts {
supportsDynamicHTML?: boolean
}

// expose AsyncLocalStorage on global for react usage
const { AsyncLocalStorage } = require('async_hooks')
;(global as any).AsyncLocalStorage = AsyncLocalStorage

export default async function exportPage({
parentSpanId,
path,
Expand Down
4 changes: 4 additions & 0 deletions packages/next/server/dev/static-paths-worker.ts
Expand Up @@ -22,6 +22,10 @@ if (process.env.NEXT_PREBUNDLED_REACT) {

let workerWasUsed = false

// expose AsyncLocalStorage on global for react usage
const { AsyncLocalStorage } = require('async_hooks')
;(global as any).AsyncLocalStorage = AsyncLocalStorage

// we call getStaticPaths in a separate process to ensure
// side-effects aren't relied on in dev that will break
// during a production build
Expand Down
13 changes: 6 additions & 7 deletions packages/next/server/next-server.ts
Expand Up @@ -256,11 +256,10 @@ export default class NextNodeServer extends BaseServer {
}).catch(() => {})
}

if (this.nextConfig.experimental.appDir) {
// expose AsyncLocalStorage on global for react usage
const { AsyncLocalStorage } = require('async_hooks')
;(global as any).AsyncLocalStorage = AsyncLocalStorage
}
// expose AsyncLocalStorage on global for react usage
const { AsyncLocalStorage } = require('async_hooks')
;(global as any).AsyncLocalStorage = AsyncLocalStorage

// ensure options are set when loadConfig isn't called
setHttpClientAndAgentOptions(this.nextConfig)
}
Expand Down Expand Up @@ -1775,7 +1774,7 @@ export default class NextNodeServer extends BaseServer {
page: page,
body: getRequestMeta(params.request, '__NEXT_CLONABLE_BODY'),
},
useCache: false,
useCache: !this.renderOpts.dev,
onWarning: params.onWarning,
})

Expand Down Expand Up @@ -2132,7 +2131,7 @@ export default class NextNodeServer extends BaseServer {
},
body: getRequestMeta(params.req, '__NEXT_CLONABLE_BODY'),
},
useCache: false,
useCache: !this.renderOpts.dev,
onWarning: params.onWarning,
})

Expand Down
22 changes: 18 additions & 4 deletions packages/next/server/web/sandbox/context.ts
Expand Up @@ -14,6 +14,7 @@ import { validateURL } from '../utils'
import { pick } from '../../../lib/pick'
import { fetchInlineAsset } from './fetch-inline-assets'
import type { EdgeFunctionDefinition } from '../../../build/webpack/plugins/middleware-plugin'
import { UnwrapPromise } from '../../../lib/coalesced-function'

const WEBPACK_HASH_REGEX =
/__webpack_require__\.h = function\(\) \{ return "[0-9a-f]+"; \}/g
Expand Down Expand Up @@ -319,8 +320,15 @@ interface ModuleContextOptions {
edgeFunctionEntry: Pick<EdgeFunctionDefinition, 'assets' | 'wasm'>
}

const pendingModuleCaches = new Map<string, Promise<ModuleContext>>()

function getModuleContextShared(options: ModuleContextOptions) {
return createModuleContext(options)
let deferredModuleContext = pendingModuleCaches.get(options.moduleName)
if (!deferredModuleContext) {
deferredModuleContext = createModuleContext(options)
pendingModuleCaches.set(options.moduleName, deferredModuleContext)
}
return deferredModuleContext
}

/**
Expand All @@ -335,9 +343,15 @@ export async function getModuleContext(options: ModuleContextOptions): Promise<{
paths: Map<string, string>
warnedEvals: Set<string>
}> {
let moduleContext = options.useCache
? moduleContexts.get(options.moduleName)
: await getModuleContextShared(options)
let moduleContext:
| UnwrapPromise<ReturnType<typeof getModuleContextShared>>
| undefined

if (options.useCache) {
moduleContext =
moduleContexts.get(options.moduleName) ||
(await getModuleContextShared(options))
}

if (!moduleContext) {
moduleContext = await createModuleContext(options)
Expand Down
29 changes: 1 addition & 28 deletions packages/next/taskfile.js
Expand Up @@ -2108,11 +2108,7 @@ export async function compile(task, opts) {
],
opts
)
await task.serial([
'ncc_react_refresh_utils',
'ncc_next__react_dev_overlay',
'copy_package_json',
])
await task.serial(['ncc_react_refresh_utils', 'ncc_next__react_dev_overlay'])
}

export async function bin(task, opts) {
Expand Down Expand Up @@ -2199,29 +2195,6 @@ export async function nextbuildjest(task, opts) {
notify('Compiled build/jest files')
}

export async function copy_package_json(task, opts) {
await fs.copy(
join(
__dirname,
'client/components/static-generation-async-storage/package.json'
),
join(
__dirname,
'dist/client/components/static-generation-async-storage/package.json'
)
)
await fs.copy(
join(
__dirname,
'client/components/static-generation-async-storage/package.json'
),
join(
__dirname,
'dist/esm/client/components/static-generation-async-storage/package.json'
)
)
}

export async function client(task, opts) {
await task
.source(opts.src || 'client/**/*.+(js|ts|tsx)')
Expand Down

0 comments on commit 98106ba

Please sign in to comment.