import path from 'path' import { NextConfigComplete } from '../../server/config-shared' const EVENT_VERSION = 'NEXT_CLI_SESSION_STARTED' type EventCliSessionStarted = { nextVersion: string nodeVersion: string cliCommand: string isSrcDir: boolean | null hasNowJson: boolean isCustomServer: boolean | null hasNextConfig: boolean buildTarget: string hasWebpackConfig: boolean hasBabelConfig: boolean basePathEnabled: boolean i18nEnabled: boolean imageEnabled: boolean imageFutureEnabled: boolean locales: string | null localeDomainsCount: number | null localeDetectionEnabled: boolean | null imageDomainsCount: number | null imageRemotePatternsCount: number | null imageSizes: string | null imageLoader: string | null imageFormats: string | null trailingSlashEnabled: boolean reactStrictMode: boolean webpackVersion: number | null turboFlag: boolean appDir: boolean | null pagesDir: boolean | null } function hasBabelConfig(dir: string): boolean { try { const noopFile = path.join(dir, 'noop.js') const res = require('next/dist/compiled/babel/core').loadPartialConfig({ cwd: dir, filename: noopFile, sourceFileName: noopFile, }) as any const isForTooling = res.options?.presets?.every( (e: any) => e?.file?.request === 'next/babel' ) && res.options?.plugins?.length === 0 return res.hasFilesystemConfig() && !isForTooling } catch { return false } } export function eventCliSession( dir: string, nextConfig: NextConfigComplete, event: Omit< EventCliSessionStarted, | 'nextVersion' | 'nodeVersion' | 'hasNextConfig' | 'buildTarget' | 'hasWebpackConfig' | 'hasBabelConfig' | 'basePathEnabled' | 'i18nEnabled' | 'imageEnabled' | 'imageFutureEnabled' | 'locales' | 'localeDomainsCount' | 'localeDetectionEnabled' | 'imageDomainsCount' | 'imageRemotePatternsCount' | 'imageSizes' | 'imageLoader' | 'imageFormats' | 'trailingSlashEnabled' | 'reactStrictMode' > ): { eventName: string; payload: EventCliSessionStarted }[] { // This should be an invariant, if it fails our build tooling is broken. if (typeof process.env.__NEXT_VERSION !== 'string') { return [] } const { images, i18n } = nextConfig || {} const payload: EventCliSessionStarted = { nextVersion: process.env.__NEXT_VERSION, nodeVersion: process.version, cliCommand: event.cliCommand, isSrcDir: event.isSrcDir, hasNowJson: event.hasNowJson, isCustomServer: event.isCustomServer, hasNextConfig: nextConfig.configOrigin !== 'default', buildTarget: 'default', hasWebpackConfig: typeof nextConfig?.webpack === 'function', hasBabelConfig: hasBabelConfig(dir), imageEnabled: !!images, imageFutureEnabled: !!images, basePathEnabled: !!nextConfig?.basePath, i18nEnabled: !!i18n, locales: i18n?.locales ? i18n.locales.join(',') : null, localeDomainsCount: i18n?.domains ? i18n.domains.length : null, localeDetectionEnabled: !i18n ? null : i18n.localeDetection !== false, imageDomainsCount: images?.domains ? images.domains.length : null, imageRemotePatternsCount: images?.remotePatterns ? images.remotePatterns.length : null, imageSizes: images?.imageSizes ? images.imageSizes.join(',') : null, imageLoader: images?.loader, imageFormats: images?.formats ? images.formats.join(',') : null, trailingSlashEnabled: !!nextConfig?.trailingSlash, reactStrictMode: !!nextConfig?.reactStrictMode, webpackVersion: event.webpackVersion || null, turboFlag: event.turboFlag || false, appDir: event.appDir, pagesDir: event.pagesDir, } return [{ eventName: EVENT_VERSION, payload }] }