import { PluginObj, types as BabelTypes } from 'next/dist/compiled/babel/core' import chalk from 'next/dist/compiled/chalk' export default function NoAnonymousDefaultExport({ types: t, ...babel }: { types: typeof BabelTypes caller: (callerCallback: (caller: any) => any) => any }): PluginObj { let onWarning: ((reason: string | Error) => void) | null = null babel.caller((caller) => { onWarning = caller.onWarning return '' // Intentionally empty to not invalidate cache }) if (typeof onWarning !== 'function') { return { visitor: {} } } const warn = onWarning! return { visitor: { ExportDefaultDeclaration(path) { const def = path.node.declaration if ( !( def.type === 'ArrowFunctionExpression' || def.type === 'FunctionDeclaration' ) ) { return } switch (def.type) { case 'ArrowFunctionExpression': { warn( [ chalk.yellow.bold( 'Anonymous arrow functions cause Fast Refresh to not preserve local component state.' ), 'Please add a name to your function, for example:', '', chalk.bold('Before'), chalk.cyan('export default () =>
;'), '', chalk.bold('After'), chalk.cyan('const Named = () =>
;'), chalk.cyan('export default Named;'), '', `A codemod is available to fix the most common cases: ${chalk.cyan( 'https://nextjs.link/codemod-ndc' )}`, ].join('\n') ) break } case 'FunctionDeclaration': { const isAnonymous = !Boolean(def.id) if (isAnonymous) { warn( [ chalk.yellow.bold( 'Anonymous function declarations cause Fast Refresh to not preserve local component state.' ), 'Please add a name to your function, for example:', '', chalk.bold('Before'), chalk.cyan('export default function () { /* ... */ }'), '', chalk.bold('After'), chalk.cyan('export default function Named() { /* ... */ }'), '', `A codemod is available to fix the most common cases: ${chalk.cyan( 'https://nextjs.link/codemod-ndc' )}`, ].join('\n') ) } break } default: { // eslint-disable-next-line @typescript-eslint/no-unused-vars const _: never = def } } }, }, } }