import { join } from 'path' import * as Log from '../../output/log' import babelLoader from './babel-loader/src/index' // increment 'p' to invalidate cache // eslint-disable-next-line no-useless-concat const cacheKey = 'babel-cache-' + 'p' + '-' const nextBabelPreset = require('../../babel/preset') const customBabelLoader = babelLoader((babel) => { const presetItem = babel.createConfigItem(nextBabelPreset, { type: 'preset', }) const applyCommonJs = babel.createConfigItem( require('../../babel/plugins/commonjs'), { type: 'plugin' } ) const commonJsItem = babel.createConfigItem( require('next/dist/compiled/babel/plugin-transform-modules-commonjs'), { type: 'plugin' } ) const configs = new Set() return { customOptions(opts) { const custom = { isServer: opts.isServer, pagesDir: opts.pagesDir, development: opts.development, hasReactRefresh: opts.hasReactRefresh, hasJsxRuntime: opts.hasJsxRuntime, } const filename = join(opts.cwd, 'noop.js') const loader = Object.assign( opts.cache ? { cacheDirectory: join(opts.distDir, 'cache', 'next-babel-loader'), cacheIdentifier: cacheKey + (opts.isServer ? '-server' : '') + '-new-polyfills' + (opts.development ? '-development' : '-production') + (opts.hasReactRefresh ? '-react-refresh' : '') + (opts.hasJsxRuntime ? '-jsx-runtime' : '') + JSON.stringify( babel.loadPartialConfig({ filename, cwd: opts.cwd, sourceFileName: filename, }).options ), } : { cacheDirectory: false, }, opts ) delete loader.isServer delete loader.cache delete loader.distDir delete loader.pagesDir delete loader.development delete loader.hasReactRefresh delete loader.hasJsxRuntime return { loader, custom } }, config( cfg, { source, customOptions: { isServer, pagesDir, development, hasReactRefresh, hasJsxRuntime, }, } ) { const filename = this.resourcePath const options = Object.assign({}, cfg.options) const isPageFile = filename.startsWith(pagesDir) if (cfg.hasFilesystemConfig()) { for (const file of [cfg.babelrc, cfg.config]) { // We only log for client compilation otherwise there will be double output if (file && !isServer && !configs.has(file)) { configs.add(file) Log.info(`Using external babel configuration from ${file}`) } } } else { // Add our default preset if the no "babelrc" found. options.presets = [...options.presets, presetItem] } options.caller.isServer = isServer options.caller.isDev = development options.caller.hasJsxRuntime = hasJsxRuntime options.caller.pagesDir = pagesDir const emitWarning = this.emitWarning.bind(this) Object.defineProperty(options.caller, 'onWarning', { enumerable: false, writable: false, value: (options.caller.onWarning = function (reason) { if (!(reason instanceof Error)) { reason = new Error(reason) } emitWarning(reason) }), }) options.plugins = options.plugins || [] if (hasReactRefresh) { const reactRefreshPlugin = babel.createConfigItem( [require('react-refresh/babel'), { skipEnvCheck: true }], { type: 'plugin' } ) options.plugins.unshift(reactRefreshPlugin) if (!isServer) { const noAnonymousDefaultExportPlugin = babel.createConfigItem( [require('../../babel/plugins/no-anonymous-default-export'), {}], { type: 'plugin' } ) options.plugins.unshift(noAnonymousDefaultExportPlugin) } } if (!isServer && isPageFile) { const pageConfigPlugin = babel.createConfigItem( [require('../../babel/plugins/next-page-config')], { type: 'plugin' } ) options.plugins.push(pageConfigPlugin) const diallowExportAll = babel.createConfigItem( [ require('../../babel/plugins/next-page-disallow-re-export-all-exports'), ], { type: 'plugin' } ) options.plugins.push(diallowExportAll) } // If the file has `module.exports` we have to transpile commonjs because Babel adds `import` statements // That break webpack, since webpack doesn't support combining commonjs and esmodules if (source.indexOf('module.exports') !== -1) { options.plugins.push(applyCommonJs) } options.plugins.push([ require.resolve('next/dist/compiled/babel/plugin-transform-define'), { 'process.env.NODE_ENV': development ? 'development' : 'production', 'typeof window': isServer ? 'undefined' : 'object', 'process.browser': isServer ? false : true, }, 'next-js-transform-define-instance', ]) if (isPageFile) { if (!isServer) { options.plugins.push([ require.resolve('../../babel/plugins/next-ssg-transform'), {}, ]) } } // As shared/lib has stateful modules we have to transpile commonjs options.overrides = [ ...(options.overrides || []), { test: [ /next[\\/]dist[\\/]shared[\\/]lib/, /next[\\/]dist[\\/]client/, /next[\\/]dist[\\/]pages/, ], plugins: [commonJsItem], }, ] return options }, } }) export default customBabelLoader