2020-11-25 20:56:18 +01:00
|
|
|
import devalue from 'next/dist/compiled/devalue'
|
|
|
|
import escapeRegexp from 'next/dist/compiled/escape-string-regexp'
|
|
|
|
import { join } from 'path'
|
|
|
|
import { parse } from 'querystring'
|
2021-01-14 02:59:08 +01:00
|
|
|
import { webpack } from 'next/dist/compiled/webpack/webpack'
|
2020-11-25 20:56:18 +01:00
|
|
|
import { API_ROUTE } from '../../../../lib/constants'
|
|
|
|
import { isDynamicRoute } from '../../../../next-server/lib/router/utils'
|
|
|
|
import { __ApiPreviewProps } from '../../../../next-server/server/api-utils'
|
|
|
|
import {
|
|
|
|
BUILD_MANIFEST,
|
|
|
|
ROUTES_MANIFEST,
|
|
|
|
REACT_LOADABLE_MANIFEST,
|
|
|
|
} from '../../../../next-server/lib/constants'
|
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
|
|
|
import { trace } from '../../../../telemetry/trace'
|
2020-11-25 20:56:18 +01:00
|
|
|
|
|
|
|
export type ServerlessLoaderQuery = {
|
|
|
|
page: string
|
|
|
|
distDir: string
|
|
|
|
absolutePagePath: string
|
|
|
|
absoluteAppPath: string
|
|
|
|
absoluteDocumentPath: string
|
|
|
|
absoluteErrorPath: string
|
|
|
|
absolute404Path: string
|
|
|
|
buildId: string
|
|
|
|
assetPrefix: string
|
|
|
|
generateEtags: string
|
|
|
|
poweredByHeader: string
|
|
|
|
canonicalBase: string
|
|
|
|
basePath: string
|
|
|
|
runtimeConfig: string
|
|
|
|
previewProps: string
|
|
|
|
loadedEnvFiles: string
|
|
|
|
i18n: string
|
|
|
|
}
|
|
|
|
|
2021-01-14 02:59:08 +01:00
|
|
|
const nextServerlessLoader: webpack.loader.Loader = function () {
|
Telemetry-compatible tracing (#22713)
A number of changes here. I recommend viewing the diff with the <a href="?w=1">whitespace flag enabled</a>.
- OpenTelemetry is replaced with a custom and lightweight tracing solution.
- Three trace targets are currently supported: console, Zipkin, and NextJS.
- Tracing is now governed by environment variables rather than `--require instrument.js`.
+ `TRACE_TARGET`: one of `CONSOLE`, `ZIPKIN`, or `TELEMETRY`; defaults to `TELEMETRY` if unset or invalid.
+ `TRACE_ID`: an 8-byte hex-encoded value used as the Zipkin trace ID; if not provided, this value will be randomly generated and passed down to subprocesses.
Other sundry:
- I'm missing something, probably a setup step, with the Zipkin target. Traces are captured successfully, but you have to manually enter the Trace ID in order to view the trace - it doesn't show up in queries.
- I'm generally unhappy with [this commit](https://github.com/vercel/next.js/pull/22713/commits/235cedcb3ead76b630b4c8aa695f904489da2831). It is... untidy to provide a telemetry object via `setGlobal`, but I don't have a ready alternative. Is `distDir` strictly required when creating a new Telemetry object? I didn't dig too deep here.
As noted, there are a lot of changes, so it'd be great if a reviewer could:
- [ ] pull down the branch and try to break it
- [ ] check the Zipkin traces and identify possible regressions in the functionality
Closes #22570
Fixes #22574
2021-03-10 22:00:20 +01:00
|
|
|
const loaderSpan = trace('next-serverless-loader')
|
|
|
|
return loaderSpan.traceFn(() => {
|
2020-12-29 22:21:35 +01:00
|
|
|
const {
|
|
|
|
distDir,
|
|
|
|
absolutePagePath,
|
|
|
|
page,
|
|
|
|
buildId,
|
|
|
|
canonicalBase,
|
|
|
|
assetPrefix,
|
|
|
|
absoluteAppPath,
|
|
|
|
absoluteDocumentPath,
|
|
|
|
absoluteErrorPath,
|
|
|
|
absolute404Path,
|
|
|
|
generateEtags,
|
|
|
|
poweredByHeader,
|
|
|
|
basePath,
|
|
|
|
runtimeConfig,
|
|
|
|
previewProps,
|
|
|
|
loadedEnvFiles,
|
|
|
|
i18n,
|
|
|
|
}: ServerlessLoaderQuery =
|
|
|
|
typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query
|
|
|
|
|
|
|
|
const buildManifest = join(distDir, BUILD_MANIFEST).replace(/\\/g, '/')
|
|
|
|
const reactLoadableManifest = join(
|
|
|
|
distDir,
|
|
|
|
REACT_LOADABLE_MANIFEST
|
|
|
|
).replace(/\\/g, '/')
|
|
|
|
const routesManifest = join(distDir, ROUTES_MANIFEST).replace(/\\/g, '/')
|
|
|
|
|
|
|
|
const escapedBuildId = escapeRegexp(buildId)
|
|
|
|
const pageIsDynamicRoute = isDynamicRoute(page)
|
|
|
|
|
|
|
|
const encodedPreviewProps = devalue(
|
|
|
|
JSON.parse(previewProps) as __ApiPreviewProps
|
|
|
|
)
|
|
|
|
|
|
|
|
const envLoading = `
|
|
|
|
const { processEnv } = require('@next/env')
|
|
|
|
processEnv(${Buffer.from(loadedEnvFiles, 'base64').toString()})
|
2020-11-25 20:56:18 +01:00
|
|
|
`
|
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
const runtimeConfigImports = runtimeConfig
|
|
|
|
? `
|
|
|
|
const { setConfig } = require('next/config')
|
|
|
|
`
|
|
|
|
: ''
|
|
|
|
|
|
|
|
const runtimeConfigSetter = runtimeConfig
|
|
|
|
? `
|
|
|
|
const runtimeConfig = ${runtimeConfig}
|
|
|
|
setConfig(runtimeConfig)
|
|
|
|
`
|
|
|
|
: 'const runtimeConfig = {}'
|
|
|
|
|
|
|
|
if (page.match(API_ROUTE)) {
|
|
|
|
return `
|
|
|
|
${envLoading}
|
|
|
|
${runtimeConfigImports}
|
|
|
|
${
|
|
|
|
/*
|
|
|
|
this needs to be called first so its available for any other imports
|
|
|
|
*/
|
|
|
|
runtimeConfigSetter
|
|
|
|
}
|
|
|
|
import 'next/dist/next-server/server/node-polyfill-fetch'
|
|
|
|
import routesManifest from '${routesManifest}'
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
import { getApiHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/api-handler'
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2021-03-26 16:19:48 +01:00
|
|
|
const combinedRewrites = Array.isArray(routesManifest.rewrites)
|
|
|
|
? routesManifest.rewrites
|
|
|
|
: []
|
|
|
|
|
|
|
|
if (!Array.isArray(routesManifest.rewrites)) {
|
|
|
|
combinedRewrites.push(...routesManifest.rewrites.beforeFiles)
|
|
|
|
combinedRewrites.push(...routesManifest.rewrites.afterFiles)
|
|
|
|
combinedRewrites.push(...routesManifest.rewrites.fallback)
|
|
|
|
}
|
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
const apiHandler = getApiHandler({
|
|
|
|
pageModule: require("${absolutePagePath}"),
|
2021-03-26 16:19:48 +01:00
|
|
|
rewrites: combinedRewrites,
|
2020-12-29 22:21:35 +01:00
|
|
|
i18n: ${i18n || 'undefined'},
|
|
|
|
page: "${page}",
|
|
|
|
basePath: "${basePath}",
|
|
|
|
pageIsDynamic: ${pageIsDynamicRoute},
|
2021-04-22 21:03:13 +02:00
|
|
|
encodedPreviewProps: ${encodedPreviewProps}
|
2020-12-29 22:21:35 +01:00
|
|
|
})
|
|
|
|
export default apiHandler
|
|
|
|
`
|
|
|
|
} else {
|
|
|
|
return `
|
|
|
|
import 'next/dist/next-server/server/node-polyfill-fetch'
|
|
|
|
import routesManifest from '${routesManifest}'
|
|
|
|
import buildManifest from '${buildManifest}'
|
|
|
|
import reactLoadableManifest from '${reactLoadableManifest}'
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-11-25 20:56:18 +01:00
|
|
|
${envLoading}
|
|
|
|
${runtimeConfigImports}
|
|
|
|
${
|
2020-12-29 22:21:35 +01:00
|
|
|
// this needs to be called first so its available for any other imports
|
2020-11-25 20:56:18 +01:00
|
|
|
runtimeConfigSetter
|
|
|
|
}
|
2020-12-29 22:21:35 +01:00
|
|
|
import { getPageHandler } from 'next/dist/build/webpack/loaders/next-serverless-loader/page-handler'
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2021-03-03 20:20:48 +01:00
|
|
|
const documentModule = require("${absoluteDocumentPath}")
|
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
const appMod = require('${absoluteAppPath}')
|
|
|
|
let App = appMod.default || appMod.then && appMod.then(mod => mod.default);
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
const compMod = require('${absolutePagePath}')
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
const Component = compMod.default || compMod.then && compMod.then(mod => mod.default)
|
|
|
|
export default Component
|
|
|
|
export const getStaticProps = compMod['getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['getStaticProp' + 's'])
|
|
|
|
export const getStaticPaths = compMod['getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['getStaticPath' + 's'])
|
|
|
|
export const getServerSideProps = compMod['getServerSideProp' + 's'] || compMod.then && compMod.then(mod => mod['getServerSideProp' + 's'])
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
// kept for detecting legacy exports
|
|
|
|
export const unstable_getStaticParams = compMod['unstable_getStaticParam' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticParam' + 's'])
|
|
|
|
export const unstable_getStaticProps = compMod['unstable_getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticProp' + 's'])
|
|
|
|
export const unstable_getStaticPaths = compMod['unstable_getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticPath' + 's'])
|
|
|
|
export const unstable_getServerProps = compMod['unstable_getServerProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getServerProp' + 's'])
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
export let config = compMod['confi' + 'g'] || (compMod.then && compMod.then(mod => mod['confi' + 'g'])) || {}
|
|
|
|
export const _app = App
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2021-03-26 16:19:48 +01:00
|
|
|
const combinedRewrites = Array.isArray(routesManifest.rewrites)
|
|
|
|
? routesManifest.rewrites
|
|
|
|
: []
|
|
|
|
|
|
|
|
if (!Array.isArray(routesManifest.rewrites)) {
|
|
|
|
combinedRewrites.push(...routesManifest.rewrites.beforeFiles)
|
|
|
|
combinedRewrites.push(...routesManifest.rewrites.afterFiles)
|
|
|
|
combinedRewrites.push(...routesManifest.rewrites.fallback)
|
|
|
|
}
|
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
const { renderReqToHTML, render } = getPageHandler({
|
|
|
|
pageModule: compMod,
|
|
|
|
pageComponent: Component,
|
|
|
|
pageConfig: config,
|
|
|
|
appModule: App,
|
2021-03-03 20:20:48 +01:00
|
|
|
documentModule: documentModule,
|
2020-12-29 22:21:35 +01:00
|
|
|
errorModule: require("${absoluteErrorPath}"),
|
|
|
|
notFoundModule: ${
|
|
|
|
absolute404Path ? `require("${absolute404Path}")` : undefined
|
|
|
|
},
|
|
|
|
pageGetStaticProps: getStaticProps,
|
|
|
|
pageGetStaticPaths: getStaticPaths,
|
|
|
|
pageGetServerSideProps: getServerSideProps,
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
assetPrefix: "${assetPrefix}",
|
|
|
|
canonicalBase: "${canonicalBase}",
|
|
|
|
generateEtags: ${generateEtags || 'false'},
|
|
|
|
poweredByHeader: ${poweredByHeader || 'false'},
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2020-12-29 22:21:35 +01:00
|
|
|
runtimeConfig,
|
|
|
|
buildManifest,
|
|
|
|
reactLoadableManifest,
|
2021-02-17 23:52:43 +01:00
|
|
|
|
2021-03-26 16:19:48 +01:00
|
|
|
rewrites: combinedRewrites,
|
2020-11-25 20:56:18 +01:00
|
|
|
i18n: ${i18n || 'undefined'},
|
|
|
|
page: "${page}",
|
2020-12-29 22:21:35 +01:00
|
|
|
buildId: "${buildId}",
|
|
|
|
escapedBuildId: "${escapedBuildId}",
|
2020-11-25 20:56:18 +01:00
|
|
|
basePath: "${basePath}",
|
|
|
|
pageIsDynamic: ${pageIsDynamicRoute},
|
2021-04-22 21:03:13 +02:00
|
|
|
encodedPreviewProps: ${encodedPreviewProps}
|
2020-11-25 20:56:18 +01:00
|
|
|
})
|
2020-12-29 22:21:35 +01:00
|
|
|
export { renderReqToHTML, render }
|
2020-11-25 20:56:18 +01:00
|
|
|
`
|
|
|
|
}
|
2020-12-29 22:21:35 +01:00
|
|
|
})
|
2020-11-25 20:56:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export default nextServerlessLoader
|