Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
750 changes: 657 additions & 93 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@
"@netlify/build": "^35.1.7",
"@netlify/config": "^24.0.4",
"@netlify/edge-bundler": "^14.5.5",
"@netlify/edge-functions-bootstrap": "^2.14.0",
"@netlify/edge-functions": "^2.17.1",
"@netlify/edge-functions-bootstrap": "^2.14.0",
"@netlify/eslint-config-node": "^7.0.1",
"@netlify/functions": "^4.2.7",
"@netlify/otel": "^4.3.0",
"@netlify/serverless-functions-api": "^2.5.0",
"@netlify/zip-it-and-ship-it": "^14.1.8",
"@opentelemetry/api": "^1.8.0",
"@playwright/test": "^1.43.1",
"@types/node": "^20.12.7",
"@types/picomatch": "^3.0.0",
Expand Down
7 changes: 3 additions & 4 deletions src/build/content/prerendered.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { existsSync } from 'node:fs'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { join } from 'node:path'

import { trace } from '@opentelemetry/api'
import { wrapTracer } from '@opentelemetry/api/experimental'
import { getTracer, withActiveSpan } from '@netlify/otel'
import { glob } from 'fast-glob'
import type { RouteMetadata } from 'next-with-cache-handler-v2/dist/export/routes/types.js'
import pLimit from 'p-limit'
Expand All @@ -21,7 +20,7 @@ import type {
import type { PluginContext } from '../plugin-context.js'
import { verifyNetlifyForms } from '../verification.js'

const tracer = wrapTracer(trace.getTracer('Next runtime'))
const tracer = getTracer('Next runtime')

/**
* Write a cache entry to the blob upload directory.
Expand Down Expand Up @@ -158,7 +157,7 @@ const buildFetchCacheValue = async (
* Upload prerendered content to the blob store
*/
export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void> => {
return tracer.withActiveSpan('copyPrerenderedContent', async () => {
return withActiveSpan(tracer, 'copyPrerenderedContent', async () => {
try {
// ensure the blob directory exists
await mkdir(ctx.blobDir, { recursive: true })
Expand Down
9 changes: 4 additions & 5 deletions src/build/content/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import { createRequire } from 'node:module'
import { dirname, join, resolve, sep } from 'node:path'
import { join as posixJoin, sep as posixSep } from 'node:path/posix'

import { trace } from '@opentelemetry/api'
import { wrapTracer } from '@opentelemetry/api/experimental'
import { getTracer, withActiveSpan } from '@netlify/otel'
import glob from 'fast-glob'
import type { MiddlewareManifest } from 'next/dist/build/webpack/plugins/middleware-plugin.js'
import type { FunctionsConfigManifest } from 'next-with-cache-handler-v2/dist/build/index.js'
Expand All @@ -24,7 +23,7 @@ import type { RunConfig } from '../../run/config.js'
import { RUN_CONFIG_FILE } from '../../run/constants.js'
import type { PluginContext, RequiredServerFilesManifest } from '../plugin-context.js'

const tracer = wrapTracer(trace.getTracer('Next runtime'))
const tracer = getTracer('Next runtime')

const toPosixPath = (path: string) => path.split(sep).join(posixSep)

Expand All @@ -36,7 +35,7 @@ function isError(error: unknown): error is NodeJS.ErrnoException {
* Copy App/Pages Router Javascript needed by the server handler
*/
export const copyNextServerCode = async (ctx: PluginContext): Promise<void> => {
await tracer.withActiveSpan('copyNextServerCode', async () => {
await withActiveSpan(tracer, 'copyNextServerCode', async () => {
// update the dist directory inside the required-server-files.json to work with
// nx monorepos and other setups where the dist directory is modified
const reqServerFilesPath = join(
Expand Down Expand Up @@ -289,7 +288,7 @@ async function patchNextModules(
}

export const copyNextDependencies = async (ctx: PluginContext): Promise<void> => {
await tracer.withActiveSpan('copyNextDependencies', async () => {
await withActiveSpan(tracer, 'copyNextDependencies', async () => {
const entries = await readdir(ctx.standaloneDir)
const filter = ctx.constants.IS_LOCAL ? undefined : nodeModulesFilter

Expand Down
13 changes: 6 additions & 7 deletions src/build/content/static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@ import { existsSync } from 'node:fs'
import { cp, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'
import { basename, join } from 'node:path'

import { trace } from '@opentelemetry/api'
import { wrapTracer } from '@opentelemetry/api/experimental'
import { getTracer, withActiveSpan } from '@netlify/otel'
import glob from 'fast-glob'

import type { HtmlBlob } from '../../shared/blob-types.cjs'
import { encodeBlobKey } from '../../shared/blobkey.js'
import { PluginContext } from '../plugin-context.js'
import { verifyNetlifyForms } from '../verification.js'

const tracer = wrapTracer(trace.getTracer('Next runtime'))
const tracer = getTracer('Next runtime')

/**
* Assemble the static content for being uploaded to the blob storage
*/
export const copyStaticContent = async (ctx: PluginContext): Promise<void> => {
return tracer.withActiveSpan('copyStaticContent', async () => {
return withActiveSpan(tracer, 'copyStaticContent', async () => {
const srcDir = join(ctx.publishDir, 'server/pages')
const destDir = ctx.blobDir

Expand Down Expand Up @@ -58,7 +57,7 @@ export const copyStaticContent = async (ctx: PluginContext): Promise<void> => {
* Copy static content to the static dir so it is uploaded to the CDN
*/
export const copyStaticAssets = async (ctx: PluginContext): Promise<void> => {
return tracer.withActiveSpan('copyStaticAssets', async (span): Promise<void> => {
return withActiveSpan(tracer, 'copyStaticAssets', async (span): Promise<void> => {
try {
await rm(ctx.staticDir, { recursive: true, force: true })
const { basePath } = await ctx.getRoutesManifest()
Expand All @@ -73,7 +72,7 @@ export const copyStaticAssets = async (ctx: PluginContext): Promise<void> => {
})
}
} catch (error) {
span.end()
span?.end()
ctx.failBuild('Failed copying static assets', error)
}
})
Expand All @@ -94,7 +93,7 @@ export const setHeadersConfig = async (ctx: PluginContext): Promise<void> => {
}

export const copyStaticExport = async (ctx: PluginContext): Promise<void> => {
await tracer.withActiveSpan('copyStaticExport', async () => {
await withActiveSpan(tracer, 'copyStaticExport', async () => {
if (!ctx.exportDetail?.outDirectory) {
ctx.failBuild('Export directory not found')
}
Expand Down
11 changes: 5 additions & 6 deletions src/build/functions/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
import { join, relative } from 'node:path'
import { join as posixJoin } from 'node:path/posix'

import { trace } from '@opentelemetry/api'
import { wrapTracer } from '@opentelemetry/api/experimental'
import { getTracer, withActiveSpan } from '@netlify/otel'
import { glob } from 'fast-glob'

import {
Expand All @@ -13,11 +12,11 @@ import {
} from '../content/server.js'
import { PluginContext, SERVER_HANDLER_NAME } from '../plugin-context.js'

const tracer = wrapTracer(trace.getTracer('Next runtime'))
const tracer = getTracer('Next runtime')

/** Copies the runtime dist folder to the lambda */
const copyHandlerDependencies = async (ctx: PluginContext) => {
await tracer.withActiveSpan('copyHandlerDependencies', async (span) => {
await withActiveSpan(tracer, 'copyHandlerDependencies', async (span) => {
const promises: Promise<void>[] = []
// if the user specified some files to include in the lambda
// we need to copy them to the functions-internal folder
Expand All @@ -31,7 +30,7 @@ const copyHandlerDependencies = async (ctx: PluginContext) => {
posixJoin(ctx.relativeAppDir, '.env.production.local'),
)

span.setAttribute('next.includedFiles', includedFiles.join(','))
span?.setAttribute('next.includedFiles', includedFiles.join(','))

const resolvedFiles = await Promise.all(
includedFiles.map((globPattern) => glob(globPattern, { cwd: process.cwd() })),
Expand Down Expand Up @@ -137,7 +136,7 @@ export const clearStaleServerHandlers = async (ctx: PluginContext) => {
* Create a Netlify function to run the Next.js server
*/
export const createServerHandler = async (ctx: PluginContext) => {
await tracer.withActiveSpan('createServerHandler', async () => {
await withActiveSpan(tracer, 'createServerHandler', async () => {
await mkdir(join(ctx.serverHandlerRuntimeModulesDir), { recursive: true })

await copyNextServerCode(ctx)
Expand Down
8 changes: 4 additions & 4 deletions src/build/templates/handler-monorepo.tmpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
createRequestContext,
runWithRequestContext,
} from '{{cwd}}/.netlify/dist/run/handlers/request-context.cjs'
import { getTracer } from '{{cwd}}/.netlify/dist/run/handlers/tracer.cjs'
import { getTracer, withActiveSpan } from '{{cwd}}/.netlify/dist/run/handlers/tracer.cjs'

process.chdir('{{cwd}}')

Expand All @@ -15,8 +15,8 @@ export default async function (req, context) {
const tracer = getTracer()

const handlerResponse = await runWithRequestContext(requestContext, () => {
return tracer.withActiveSpan('Next.js Server Handler', async (span) => {
span.setAttributes({
return withActiveSpan(tracer, 'Next.js Server Handler', async (span) => {
span?.setAttributes({
'account.id': context.account.id,
'deploy.id': context.deploy.id,
'request.id': context.requestId,
Expand All @@ -32,7 +32,7 @@ export default async function (req, context) {
cachedHandler = handler
}
const response = await cachedHandler(req, context, span, requestContext)
span.setAttributes({
span?.setAttributes({
'http.status_code': response.status,
})
return response
Expand Down
8 changes: 4 additions & 4 deletions src/build/templates/handler.tmpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
runWithRequestContext,
} from './.netlify/dist/run/handlers/request-context.cjs'
import serverHandler from './.netlify/dist/run/handlers/server.js'
import { getTracer } from './.netlify/dist/run/handlers/tracer.cjs'
import { getTracer, withActiveSpan } from './.netlify/dist/run/handlers/tracer.cjs'

// Set feature flag for regional blobs
process.env.USE_REGIONAL_BLOBS = '{{useRegionalBlobs}}'
Expand All @@ -13,8 +13,8 @@ export default async function handler(req, context) {
const tracer = getTracer()

const handlerResponse = await runWithRequestContext(requestContext, () => {
return tracer.withActiveSpan('Next.js Server Handler', async (span) => {
span.setAttributes({
return withActiveSpan(tracer, 'Next.js Server Handler', async (span) => {
span?.setAttributes({
'account.id': context.account.id,
'deploy.id': context.deploy.id,
'request.id': context.requestId,
Expand All @@ -26,7 +26,7 @@ export default async function handler(req, context) {
cwd: process.cwd(),
})
const response = await serverHandler(req, context, span, requestContext)
span.setAttributes({
span?.setAttributes({
'http.status_code': response.status,
})
return response
Expand Down
19 changes: 9 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { rm } from 'fs/promises'

import type { NetlifyPluginOptions } from '@netlify/build'
import { trace } from '@opentelemetry/api'
import { wrapTracer } from '@opentelemetry/api/experimental'
import { getTracer, withActiveSpan } from '@netlify/otel'

import { restoreBuildCache, saveBuildCache } from './build/cache.js'
import { copyPrerenderedContent } from './build/content/prerendered.js'
Expand All @@ -27,15 +26,15 @@ import {
const skipPlugin =
process.env.NETLIFY_NEXT_PLUGIN_SKIP === 'true' || process.env.NETLIFY_NEXT_PLUGIN_SKIP === '1'
const skipText = 'Skipping Next.js plugin due to NETLIFY_NEXT_PLUGIN_SKIP environment variable.'
const tracer = wrapTracer(trace.getTracer('Next.js runtime'))
const tracer = getTracer('Next.js runtime')

export const onPreDev = async (options: NetlifyPluginOptions) => {
if (skipPlugin) {
console.warn(skipText)
return
}

await tracer.withActiveSpan('onPreDev', async () => {
await withActiveSpan(tracer, 'onPreDev', async () => {
const context = new PluginContext(options)

// Blob files left over from `ntl build` interfere with `ntl dev` when working with regional blobs
Expand All @@ -49,7 +48,7 @@ export const onPreBuild = async (options: NetlifyPluginOptions) => {
return
}

await tracer.withActiveSpan('onPreBuild', async () => {
await withActiveSpan(tracer, 'onPreBuild', async () => {
// Enable Next.js standalone mode at build time
process.env.NEXT_PRIVATE_STANDALONE = 'true'
const ctx = new PluginContext(options)
Expand All @@ -71,12 +70,12 @@ export const onBuild = async (options: NetlifyPluginOptions) => {
return
}

await tracer.withActiveSpan('onBuild', async (span) => {
await withActiveSpan(tracer, 'onBuild', async (span) => {
const ctx = new PluginContext(options)

verifyPublishDir(ctx)

span.setAttribute('next.buildConfig', JSON.stringify(ctx.buildConfig))
span?.setAttribute('next.buildConfig', JSON.stringify(ctx.buildConfig))

// only save the build cache if not run via the CLI
if (!options.constants.IS_LOCAL) {
Expand Down Expand Up @@ -109,7 +108,7 @@ export const onPostBuild = async (options: NetlifyPluginOptions) => {
return
}

await tracer.withActiveSpan('onPostBuild', async () => {
await withActiveSpan(tracer, 'onPostBuild', async () => {
await publishStaticDir(new PluginContext(options))
})
}
Expand All @@ -120,7 +119,7 @@ export const onSuccess = async () => {
return
}

await tracer.withActiveSpan('onSuccess', async () => {
await withActiveSpan(tracer, 'onSuccess', async () => {
const prewarm = [process.env.DEPLOY_URL, process.env.DEPLOY_PRIME_URL, process.env.URL].filter(
// If running locally then the deploy ID is a placeholder value. Filtering for `https://0--` removes it.
(url?: string): url is string => Boolean(url && !url.startsWith('https://0--')),
Expand All @@ -135,7 +134,7 @@ export const onEnd = async (options: NetlifyPluginOptions) => {
return
}

await tracer.withActiveSpan('onEnd', async () => {
await withActiveSpan(tracer, 'onEnd', async () => {
await unpublishStaticDir(new PluginContext(options))
})
}
Loading
Loading