import { getModuleBuildInfo } from '../get-module-build-info'
import { stringifyRequest } from '../../stringify-request'
import type { webpack } from 'next/dist/compiled/webpack/webpack'
import { WEBPACK_RESOURCE_QUERIES } from '../../../../lib/constants'
import type { ProxyConfig } from '../../../analysis/get-page-static-info'
import { loadEntrypoint } from '../../../load-entrypoint'
import { isMetadataRoute } from '../../../../lib/metadata/is-metadata-route'
export type EdgeAppRouteLoaderQuery = {
absolutePagePath: string
page: string
appDirLoader: string
preferredRegion: string | string[] | undefined
middlewareConfig: string
cacheHandler?: string
cacheHandlers: string
}
function getCacheHandlersSetup(
cacheHandlersStringified: string,
contextifyImportPath: (path: string) => string
): {
cacheHandlerImports: string
edgeCacheHandlersRegistration: string
} {
const cacheHandlers = JSON.parse(cacheHandlersStringified || '{}') as Record<
string,
string | undefined
>
const definedCacheHandlers = Object.entries(cacheHandlers).filter(
(entry): entry is [string, string] => Boolean(entry[1])
)
const cacheHandlerImports: string[] = []
const edgeCacheHandlersRegistration: string[] = []
for (const [index, [kind, handlerPath]] of definedCacheHandlers.entries()) {
const cacheHandlerVarName = `edgeCacheHandler_${index}`
const cacheHandlerImportPath = contextifyImportPath(handlerPath)
cacheHandlerImports.push(
`import ${cacheHandlerVarName} from ${JSON.stringify(
cacheHandlerImportPath
)}`
)
edgeCacheHandlersRegistration.push(
`edgeCacheHandlers[${JSON.stringify(kind)}] = ${cacheHandlerVarName}`
)
}
return {
cacheHandlerImports: cacheHandlerImports.join('\n') || '\n',
edgeCacheHandlersRegistration:
edgeCacheHandlersRegistration.join('\n') || '\n',
}
}
const EdgeAppRouteLoader: webpack.LoaderDefinitionFunction<EdgeAppRouteLoaderQuery> =
async function (this) {
const {
page,
absolutePagePath,
preferredRegion,
appDirLoader: appDirLoaderBase64 = '',
middlewareConfig: middlewareConfigBase64 = '',
cacheHandler,
cacheHandlers: cacheHandlersStringified,
} = this.getOptions()
const appDirLoader = Buffer.from(appDirLoaderBase64, 'base64').toString()
const middlewareConfig: ProxyConfig = JSON.parse(
Buffer.from(middlewareConfigBase64, 'base64').toString()
)
const cacheHandlersSetup = getCacheHandlersSetup(
cacheHandlersStringified,
(handlerPath) =>
this.utils.contextify(this.context || this.rootContext, handlerPath)
)
const incrementalCacheHandler = cacheHandler
? this.utils.contextify(this.context || this.rootContext, cacheHandler)
: null
// Ensure we only run this loader for as a module.
if (!this._module) throw new Error('This loader is only usable as a module')
const buildInfo = getModuleBuildInfo(this._module)
buildInfo.nextEdgeSSR = {
isServerComponent: !isMetadataRoute(page), // Needed for 'use cache'.
page: page,
isAppDir: true,
}
buildInfo.route = {
page,
absolutePagePath,
preferredRegion,
middlewareConfig,
}
const stringifiedPagePath = stringifyRequest(this, absolutePagePath)
const modulePath = `${appDirLoader}${stringifiedPagePath.substring(
1,
stringifiedPagePath.length - 1
)}?${WEBPACK_RESOURCE_QUERIES.edgeSSREntry}`
return await loadEntrypoint(
'edge-app-route',
{
VAR_USERLAND: modulePath,
VAR_PAGE: page,
},
cacheHandlersSetup,
{
incrementalCacheHandler,
}
)
}
export default EdgeAppRouteLoader