UNPKG

next

Version:

The React Framework

179 lines (178 loc) 8.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "probeUseCache", { enumerable: true, get: function() { return probeUseCache; } }); require("../require-hook"); require("../node-environment"); const _aftercontext = require("../after/after-context"); const _loadcomponents = require("../load-components"); const _setuphttpagentenv = require("../setup-http-agent-env"); const _workasyncstorageexternal = require("../app-render/work-async-storage.external"); const _workunitasyncstorageexternal = require("../app-render/work-unit-async-storage.external"); const _manifestssingleton = require("../app-render/manifests-singleton"); const _asynclocalstorage = require("../app-render/async-local-storage"); const _requeststore = require("../async-storage/request-store"); const _server = require("react-server-dom-webpack/server"); async function probeUseCache(msg) { try { (0, _setuphttpagentenv.setHttpClientAndAgentOptions)({ httpAgentOptions: msg.nextConfigSerializable.httpAgentOptions }); // Populates the manifests singleton for the route via // `setManifestsSingleton` inside the compiled app-page module — same // mechanism a real request uses. The dev server tears the pool down // whenever it invalidates its own require/manifest caches (HMR, route // recompile) so the next probe lazy-spawns a worker with empty // `require.cache` and `loadManifest` caches. Without that teardown, a // second probe in the same worker would resolve user modules and manifests // from the first probe's cached state. // // Narrowed to `AppPageModule` because the probe is only set up from the dev // block in `generateCacheEntryImpl`, which is gated on // `outerWorkUnitStore.cacheSignal` — currently only set for app pages. // `'use cache'` in route handlers has no dev-mode hang protection at all // today (no probe, no dev-fill timeout); when that gate is broadened, this // loader will need to handle `AppRouteModule` and a different require // mechanism (route handlers don't expose `__next_app__`). const { ComponentMod } = await (0, _loadcomponents.loadComponents)({ distDir: msg.distDir, page: msg.page, isAppPath: true, isDev: true, sriEnabled: false, needsManifestsForLegacyReasons: true }); // Resolve the wrapped `'use cache'` function by its server reference // id. Same path `action-handler.ts` takes for server actions: server // module map → bundler module id → `__next_app__.require` → exported // function keyed by the action id. const serverModuleMap = (0, _manifestssingleton.getServerModuleMap)(); const entry = serverModuleMap[msg.id]; if (!entry) { return false; } const actionMod = await ComponentMod.__next_app__.require(entry.id); const wrappedFn = actionMod[msg.id]; if (typeof wrappedFn !== 'function') { return false; } // Decode the args with the worker's own server module map. See the // `EncodedArgumentsForProbe` comment for why we don't use the cache-map key // string here. const temporaryReferences = (0, _server.createTemporaryReferenceSet)(); let decoded; if (msg.encodedArguments.kind === 'string') { decoded = await (0, _server.decodeReply)(msg.encodedArguments.data, serverModuleMap, { temporaryReferences }); } else { const entries = msg.encodedArguments.entries.map(([key, value])=>{ if (typeof value === 'string') { return [ key, value ]; } const bytes = Buffer.from(value.bytes, 'base64'); return [ key, new File([ bytes ], '', { type: value.type }) ]; }); decoded = await (0, _server.decodeReplyFromAsyncIterable)({ async *[Symbol.asyncIterator] () { for (const pair of entries){ yield pair; } } }, serverModuleMap, { temporaryReferences }); } const args = decoded[2]; const workStore = buildProbeWorkStore(msg); // The outer store is `'request'`-typed and built from the forwarded // snapshot so the cache body sees the same `headers` / `cookies` / // `draftMode` it would in a real fill. `cacheSignal` defaults to undefined, // which disables the dev-timeout/probe block in `generateCacheEntryImpl` — // the primary guard against a probe inside the worker spawning another // probe. const workUnitStore = (0, _requeststore.createRequestStore)({ phase: 'render', headers: new Headers(msg.request.headers), onUpdateCookies: undefined, url: { pathname: msg.request.urlPathname, search: msg.request.urlSearch }, rootParams: msg.request.rootParams, implicitTags: { tags: [], expirationsByCacheKind: new Map() }, resumeDataCache: null, previewProps: undefined, isHmrRefresh: msg.request.isHmrRefresh, serverComponentsHmrCache: undefined, hmrRefreshHash: msg.request.hmrRefreshHash, fallbackParams: null }); await _workasyncstorageexternal.workAsyncStorage.run(workStore, ()=>_workunitasyncstorageexternal.workUnitAsyncStorage.run(workUnitStore, wrappedFn.bind(null, ...args))); return true; } catch { // Any error along the way — module resolution, decode, the actual run — // collapses to "the probe didn't complete in isolation," so the main thread // won't false-positive a deadlock. return false; } } function buildProbeWorkStore(msg) { // `after()` callbacks would duplicate the real fill's side effects — the // probe is a throwaway re-execution, not a second request. Same shape as the // validation-render `AfterContext` in `app-render.tsx`. const afterContext = new _aftercontext.AfterContext({ waitUntil (promise) { promise.catch(()=>{}); }, onClose () {}, onTaskError () {} }); return { isStaticGeneration: false, page: msg.page, route: msg.route, useCacheProbeMode: { timeoutMs: msg.timeoutMs }, isDraftMode: msg.request.isDraftMode, useCacheTimeout: msg.nextConfigSerializable.useCacheTimeout, staticPageGenerationTimeout: msg.nextConfigSerializable.staticPageGenerationTimeout, cacheLifeProfiles: msg.nextConfigSerializable.cacheLifeProfiles, buildId: msg.buildId, deploymentId: msg.deploymentId, // Empty values for cache-handler / RDC bookkeeping. The `useCacheProbeMode` // branch in `cache()` returns before any code that reads or writes these // fields, so the values can never be observed. previouslyRevalidatedTags: [], refreshTagsByCacheKind: new Map(), runInCleanSnapshot: (0, _asynclocalstorage.createSnapshot)(), shouldTrackFetchMetrics: false, reactServerErrorsByDigest: new Map(), afterContext, cacheComponentsEnabled: true, // In the probe the validation level is irrelevant because we do not perform validation // in this context. validationLevel: 'warning' }; } //# sourceMappingURL=use-cache-probe-worker.js.map