This commit is contained in:
Kismet Hasanaj
2026-05-02 20:07:02 +02:00
parent ce8672e283
commit 34dc9aec52
9428 changed files with 1733330 additions and 0 deletions
+373
View File
@@ -0,0 +1,373 @@
import { readFileSync } from 'node:fs';
import { inspect } from 'node:util';
import JSON5 from 'next/dist/compiled/json5';
import { createConfigItem, loadOptions } from 'next/dist/compiled/babel/core';
import loadFullConfig from 'next/dist/compiled/babel/core-lib-config';
import { consumeIterator } from './util';
import * as Log from '../../output/log';
import { isReactCompilerRequired } from '../../swc';
import { installBindings } from '../../swc/install-bindings';
const nextDistPath = /(next[\\/]dist[\\/]shared[\\/]lib)|(next[\\/]dist[\\/]client)|(next[\\/]dist[\\/]pages)/;
function shouldSkipBabel(transformMode, configFilePath, hasReactCompiler) {
return transformMode === 'standalone' && configFilePath == null && !hasReactCompiler;
}
const fileExtensionRegex = /\.([a-z]+)$/;
async function getCacheCharacteristics(loaderOptions, source, filename) {
var _fileExtensionRegex_exec;
let isStandalone, isServer, pagesDir;
switch(loaderOptions.transformMode){
case 'default':
isStandalone = false;
isServer = loaderOptions.isServer;
pagesDir = loaderOptions.pagesDir;
break;
case 'standalone':
isStandalone = true;
break;
default:
throw Object.defineProperty(new Error(`unsupported transformMode in loader options: ${inspect(loaderOptions)}`), "__NEXT_ERROR_CODE", {
value: "E811",
enumerable: false,
configurable: true
});
}
const isPageFile = pagesDir != null && filename.startsWith(pagesDir);
const isNextDist = nextDistPath.test(filename);
const hasModuleExports = source.indexOf('module.exports') !== -1;
const fileExt = ((_fileExtensionRegex_exec = fileExtensionRegex.exec(filename)) == null ? void 0 : _fileExtensionRegex_exec[1]) || 'unknown';
let { reactCompilerPlugins, reactCompilerExclude, configFile: configFilePath, transformMode } = loaderOptions;
// Compute `hasReactCompiler` as part of the cache characteristics / key,
// rather than inside of `getFreshConfig`:
// - `isReactCompilerRequired` depends on the file contents
// - `node_modules` and `reactCompilerExclude` depend on the file path, which
// isn't part of the cache characteristics
let hasReactCompiler = reactCompilerPlugins != null && reactCompilerPlugins.length !== 0 && !loaderOptions.isServer && !/[/\\]node_modules[/\\]/.test(filename) && // Assumption: `reactCompilerExclude` is cheap because it should only
// operate on the file path and *not* the file contents (it's sync)
!(reactCompilerExclude == null ? void 0 : reactCompilerExclude(filename));
// `isReactCompilerRequired` is expensive to run (parses/visits with SWC), so
// only run it if there's a good chance we might be able to skip calling Babel
// entirely (speculatively call `shouldSkipBabel`).
//
// Otherwise, we can let react compiler handle this logic for us. It should
// behave equivalently.
if (hasReactCompiler && shouldSkipBabel(transformMode, configFilePath, /*hasReactCompiler*/ false)) {
hasReactCompiler &&= await isReactCompilerRequired(filename);
}
return {
isStandalone,
isServer,
isPageFile,
isNextDist,
hasModuleExports,
hasReactCompiler,
fileExt,
configFilePath
};
}
/**
* Return an array of Babel plugins, conditioned upon loader options and
* source file characteristics.
*/ function getPlugins(loaderOptions, cacheCharacteristics) {
const { isServer, isPageFile, isNextDist, hasModuleExports } = cacheCharacteristics;
const { development, hasReactRefresh } = loaderOptions;
const applyCommonJsItem = hasModuleExports ? createConfigItem(require('../plugins/commonjs'), {
type: 'plugin'
}) : null;
const reactRefreshItem = hasReactRefresh ? createConfigItem([
require('next/dist/compiled/react-refresh/babel'),
{
skipEnvCheck: true
}
], {
type: 'plugin'
}) : null;
const pageConfigItem = !isServer && isPageFile ? createConfigItem([
require('../plugins/next-page-config')
], {
type: 'plugin'
}) : null;
const disallowExportAllItem = !isServer && isPageFile ? createConfigItem([
require('../plugins/next-page-disallow-re-export-all-exports')
], {
type: 'plugin'
}) : null;
const transformDefineItem = createConfigItem([
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'
], {
type: 'plugin'
});
const nextSsgItem = !isServer && isPageFile ? createConfigItem([
require.resolve('../plugins/next-ssg-transform')
], {
type: 'plugin'
}) : null;
const commonJsItem = isNextDist ? createConfigItem(require('next/dist/compiled/babel/plugin-transform-modules-commonjs'), {
type: 'plugin'
}) : null;
const nextFontUnsupported = createConfigItem([
require('../plugins/next-font-unsupported')
], {
type: 'plugin'
});
return [
reactRefreshItem,
pageConfigItem,
disallowExportAllItem,
applyCommonJsItem,
transformDefineItem,
nextSsgItem,
commonJsItem,
nextFontUnsupported
].filter(Boolean);
}
const isJsonFile = /\.(json|babelrc)$/;
const isJsFile = /\.js$/;
/**
* While this function does block execution while reading from disk, it
* should not introduce any issues. The function is only invoked when
* generating a fresh config, and only a small handful of configs should
* be generated during compilation.
*/ function getCustomBabelConfig(configFilePath) {
if (isJsonFile.exec(configFilePath)) {
const babelConfigRaw = readFileSync(configFilePath, 'utf8');
return JSON5.parse(babelConfigRaw);
} else if (isJsFile.exec(configFilePath)) {
return require(configFilePath);
}
throw Object.defineProperty(new Error('The Next.js Babel loader does not support .mjs or .cjs config files.'), "__NEXT_ERROR_CODE", {
value: "E477",
enumerable: false,
configurable: true
});
}
let babelConfigWarned = false;
/**
* Check if custom babel configuration from user only contains options that
* can be migrated into latest Next.js features supported by SWC.
*
* This raises soft warning messages only, not making any errors yet.
*/ function checkCustomBabelConfigDeprecation(config) {
if (!config || Object.keys(config).length === 0) {
return;
}
const { plugins, presets, ...otherOptions } = config;
if (Object.keys(otherOptions ?? {}).length > 0) {
return;
}
if (babelConfigWarned) {
return;
}
babelConfigWarned = true;
const isPresetReadyToDeprecate = !presets || presets.length === 0 || presets.length === 1 && presets[0] === 'next/babel';
const pluginReasons = [];
const unsupportedPlugins = [];
if (Array.isArray(plugins)) {
for (const plugin of plugins){
const pluginName = Array.isArray(plugin) ? plugin[0] : plugin;
// [NOTE]: We cannot detect if the user uses babel-plugin-macro based transform plugins,
// such as `styled-components/macro` in here.
switch(pluginName){
case 'styled-components':
case 'babel-plugin-styled-components':
pluginReasons.push(`\t- 'styled-components' can be enabled via 'compiler.styledComponents' in 'next.config.js'`);
break;
case '@emotion/babel-plugin':
pluginReasons.push(`\t- '@emotion/babel-plugin' can be enabled via 'compiler.emotion' in 'next.config.js'`);
break;
case 'babel-plugin-relay':
pluginReasons.push(`\t- 'babel-plugin-relay' can be enabled via 'compiler.relay' in 'next.config.js'`);
break;
case 'react-remove-properties':
pluginReasons.push(`\t- 'react-remove-properties' can be enabled via 'compiler.reactRemoveProperties' in 'next.config.js'`);
break;
case 'transform-remove-console':
pluginReasons.push(`\t- 'transform-remove-console' can be enabled via 'compiler.removeConsole' in 'next.config.js'`);
break;
default:
unsupportedPlugins.push(pluginName);
break;
}
}
}
if (isPresetReadyToDeprecate && unsupportedPlugins.length === 0) {
Log.warn(`It looks like there is a custom Babel configuration that can be removed${pluginReasons.length > 0 ? ':' : '.'}`);
if (pluginReasons.length > 0) {
Log.warn(`Next.js supports the following features natively: `);
Log.warn(pluginReasons.join(''));
Log.warn(`For more details configuration options, please refer https://nextjs.org/docs/architecture/nextjs-compiler#supported-features`);
}
}
}
/**
* Generate a new, flat Babel config, ready to be handed to Babel-traverse.
* This config should have no unresolved overrides, presets, etc.
*
* The config returned by this function is cached, so the function should not
* depend on file-specific configuration or configuration that could change
* across invocations without a process restart.
*/ async function getFreshConfig(ctx, cacheCharacteristics, loaderOptions, target) {
const { transformMode } = loaderOptions;
const { hasReactCompiler, configFilePath, fileExt } = cacheCharacteristics;
let customConfig = configFilePath && getCustomBabelConfig(configFilePath);
if (shouldSkipBabel(transformMode, configFilePath, hasReactCompiler)) {
// Optimization: There's nothing useful to do, bail out and skip babel on
// this file
return null;
}
checkCustomBabelConfigDeprecation(customConfig);
// We can assume that `reactCompilerPlugins` does not change without a process
// restart (it's safe to cache), as it's specified in the `next.config.js`,
// which always causes a full restart of `next dev` if changed.
const reactCompilerPluginsIfEnabled = hasReactCompiler ? loaderOptions.reactCompilerPlugins ?? [] : [];
let isServer, pagesDir, srcDir, development;
if (transformMode === 'default') {
isServer = loaderOptions.isServer;
pagesDir = loaderOptions.pagesDir;
srcDir = loaderOptions.srcDir;
development = loaderOptions.development;
}
let options = {
babelrc: false,
cloneInputAst: false,
// Use placeholder file info. `updateBabelConfigWithFileDetails` will
// replace this after caching.
filename: `basename.${fileExt}`,
inputSourceMap: undefined,
sourceFileName: `basename.${fileExt}`,
// Set the default sourcemap behavior based on Webpack's mapping flag,
// but allow users to override if they want.
sourceMaps: loaderOptions.sourceMaps === undefined ? ctx.sourceMap : loaderOptions.sourceMaps
};
const baseCaller = {
name: 'next-babel-turbo-loader',
supportsStaticESM: true,
supportsDynamicImport: true,
// Provide plugins with insight into webpack target.
// https://github.com/babel/babel-loader/issues/787
target,
// Webpack 5 supports TLA behind a flag. We enable it by default
// for Babel, and then webpack will throw an error if the experimental
// flag isn't enabled.
supportsTopLevelAwait: true,
isServer,
srcDir,
pagesDir,
isDev: development,
transformMode,
...loaderOptions.caller
};
options.plugins = [
...transformMode === 'default' ? getPlugins(loaderOptions, cacheCharacteristics) : [],
...reactCompilerPluginsIfEnabled,
...(customConfig == null ? void 0 : customConfig.plugins) || []
];
// target can be provided in babelrc
options.target = isServer ? undefined : customConfig == null ? void 0 : customConfig.target;
// env can be provided in babelrc
options.env = customConfig == null ? void 0 : customConfig.env;
options.presets = (()=>{
// If presets is defined the user will have next/babel in their babelrc
if (customConfig == null ? void 0 : customConfig.presets) {
return customConfig.presets;
}
// If presets is not defined the user will likely have "env" in their babelrc
if (customConfig) {
return undefined;
}
// If no custom config is provided the default is to use next/babel
return [
'next/babel'
];
})();
options.overrides = loaderOptions.overrides;
options.caller = {
...baseCaller,
hasJsxRuntime: transformMode === 'default' ? loaderOptions.hasJsxRuntime : undefined
};
// Babel does strict checks on the config so undefined is not allowed
if (typeof options.target === 'undefined') {
delete options.target;
}
Object.defineProperty(options.caller, 'onWarning', {
enumerable: false,
writable: false,
value: (reason)=>{
if (!(reason instanceof Error)) {
reason = Object.defineProperty(new Error(reason), "__NEXT_ERROR_CODE", {
value: "E394",
enumerable: false,
configurable: true
});
}
ctx.emitWarning(reason);
}
});
const loadedOptions = loadOptions(options);
const config = consumeIterator(loadFullConfig(loadedOptions));
return config;
}
/**
* Each key returned here corresponds with a Babel config that can be shared.
* The conditions of permissible sharing between files is dependent on specific
* file attributes and Next.js compiler states: `CharacteristicsGermaneToCaching`.
*/ function getCacheKey(cacheCharacteristics) {
const { isStandalone, isServer, isPageFile, isNextDist, hasModuleExports, hasReactCompiler, fileExt, configFilePath } = cacheCharacteristics;
const flags = 0 | (isStandalone ? 1 : 0) | (isServer ? 2 : 0) | (isPageFile ? 4 : 0) | (isNextDist ? 8 : 0) | (hasModuleExports ? 16 : 0) | (hasReactCompiler ? 32 : 0);
// separate strings with null bytes, assuming null bytes are not valid in file
// paths
return `${configFilePath || ''}\x00${fileExt}\x00${flags}`;
}
const configCache = new Map();
const configFiles = new Set();
/**
* Applies file-specific values to a potentially-cached configuration object.
*/ function updateBabelConfigWithFileDetails(cachedConfig, loaderOptions, filename, inputSourceMap) {
if (cachedConfig == null) {
return null;
}
return {
...cachedConfig,
options: {
...cachedConfig.options,
cwd: loaderOptions.cwd,
root: loaderOptions.cwd,
filename,
inputSourceMap,
// Ensure that Webpack will get a full absolute path in the sourcemap
// so that it can properly map the module back to its internal cached
// modules.
sourceFileName: filename
}
};
}
export default async function getConfig(ctx, { source, target, loaderOptions, filename, inputSourceMap }) {
// Install bindings early so they are definitely available to the loader.
// When run by webpack in next this is already done with correct configuration so this is a no-op.
// In turbopack loaders are run in a subprocess so it may or may not be done.
await installBindings();
const cacheCharacteristics = await getCacheCharacteristics(loaderOptions, source, filename);
if (loaderOptions.configFile) {
// Ensures webpack invalidates the cache for this loader when the config file changes
ctx.addDependency(loaderOptions.configFile);
}
const cacheKey = getCacheKey(cacheCharacteristics);
const cachedConfig = configCache.get(cacheKey);
if (cachedConfig !== undefined) {
return updateBabelConfigWithFileDetails(cachedConfig, loaderOptions, filename, inputSourceMap);
}
if (loaderOptions.configFile && !configFiles.has(loaderOptions.configFile)) {
configFiles.add(loaderOptions.configFile);
Log.info(`Using external babel configuration from ${loaderOptions.configFile}`);
}
const freshConfig = await getFreshConfig(ctx, cacheCharacteristics, loaderOptions, target);
configCache.set(cacheKey, freshConfig);
return updateBabelConfigWithFileDetails(freshConfig, loaderOptions, filename, inputSourceMap);
}
//# sourceMappingURL=get-config.js.map
File diff suppressed because one or more lines are too long
+41
View File
@@ -0,0 +1,41 @@
import transform from './transform';
async function nextBabelLoader(ctx, parentTrace, inputSource, inputSourceMap) {
const filename = ctx.resourcePath;
// Ensure `.d.ts` are not processed.
if (filename.endsWith('.d.ts')) {
return [
inputSource,
inputSourceMap
];
}
const target = ctx.target;
const loaderOptions = parentTrace.traceChild('get-options')// @ts-ignore TODO: remove ignore once webpack 5 types are used
.traceFn(()=>ctx.getOptions());
if (loaderOptions.exclude && loaderOptions.exclude(filename)) {
return [
inputSource,
inputSourceMap
];
}
const loaderSpanInner = parentTrace.traceChild('next-babel-turbo-transform');
const { code: transformedSource, map: outputSourceMap } = await loaderSpanInner.traceAsyncFn(async ()=>await transform(ctx, inputSource, inputSourceMap, loaderOptions, filename, target, loaderSpanInner));
return [
transformedSource,
outputSourceMap
];
}
function nextBabelLoaderOuter(inputSource, // webpack's source map format is compatible with babel, but the type signature doesn't match
inputSourceMap) {
const callback = this.async();
const loaderSpan = this.currentTraceSpan.traceChild('next-babel-turbo-loader');
loaderSpan.traceAsyncFn(()=>nextBabelLoader(this, loaderSpan, inputSource, inputSourceMap)).then(([transformedSource, outputSourceMap])=>callback == null ? void 0 : callback(/* err */ null, transformedSource, outputSourceMap ?? inputSourceMap), (err)=>{
callback == null ? void 0 : callback(err);
});
}
// check this type matches `webpack.LoaderDefinitionFunction`, but be careful
// not to publicly rely on the webpack type since the generated typescript
// declarations will be wrong.
const _nextBabelLoaderOuter = nextBabelLoaderOuter;
export default nextBabelLoaderOuter;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/build/babel/loader/index.ts"],"sourcesContent":["import type { Span } from '../../../trace'\nimport transform from './transform'\nimport type { NextJsLoaderContext } from './types'\nimport type { SourceMap } from './util'\nimport type { webpack } from 'next/dist/compiled/webpack/webpack'\n\nasync function nextBabelLoader(\n ctx: NextJsLoaderContext,\n parentTrace: Span,\n inputSource: string,\n inputSourceMap: SourceMap | null | undefined\n): Promise<[string, SourceMap | null | undefined]> {\n const filename = ctx.resourcePath\n\n // Ensure `.d.ts` are not processed.\n if (filename.endsWith('.d.ts')) {\n return [inputSource, inputSourceMap]\n }\n\n const target = ctx.target\n const loaderOptions: any = parentTrace\n .traceChild('get-options')\n // @ts-ignore TODO: remove ignore once webpack 5 types are used\n .traceFn(() => ctx.getOptions())\n\n if (loaderOptions.exclude && loaderOptions.exclude(filename)) {\n return [inputSource, inputSourceMap]\n }\n\n const loaderSpanInner = parentTrace.traceChild('next-babel-turbo-transform')\n const { code: transformedSource, map: outputSourceMap } =\n await loaderSpanInner.traceAsyncFn(\n async () =>\n await transform(\n ctx,\n inputSource,\n inputSourceMap,\n loaderOptions,\n filename,\n target,\n loaderSpanInner\n )\n )\n\n return [transformedSource, outputSourceMap]\n}\n\nfunction nextBabelLoaderOuter(\n this: NextJsLoaderContext,\n inputSource: string,\n // webpack's source map format is compatible with babel, but the type signature doesn't match\n inputSourceMap?: any\n) {\n const callback = this.async()\n\n const loaderSpan = this.currentTraceSpan.traceChild('next-babel-turbo-loader')\n loaderSpan\n .traceAsyncFn(() =>\n nextBabelLoader(this, loaderSpan, inputSource, inputSourceMap)\n )\n .then(\n ([transformedSource, outputSourceMap]) =>\n callback?.(\n /* err */ null,\n transformedSource,\n outputSourceMap ?? inputSourceMap\n ),\n (err) => {\n callback?.(err)\n }\n )\n}\n\n// check this type matches `webpack.LoaderDefinitionFunction`, but be careful\n// not to publicly rely on the webpack type since the generated typescript\n// declarations will be wrong.\nconst _nextBabelLoaderOuter: webpack.LoaderDefinitionFunction<\n {},\n NextJsLoaderContext\n> = nextBabelLoaderOuter\n\nexport default nextBabelLoaderOuter\n"],"names":["transform","nextBabelLoader","ctx","parentTrace","inputSource","inputSourceMap","filename","resourcePath","endsWith","target","loaderOptions","traceChild","traceFn","getOptions","exclude","loaderSpanInner","code","transformedSource","map","outputSourceMap","traceAsyncFn","nextBabelLoaderOuter","callback","async","loaderSpan","currentTraceSpan","then","err","_nextBabelLoaderOuter"],"mappings":"AACA,OAAOA,eAAe,cAAa;AAKnC,eAAeC,gBACbC,GAAwB,EACxBC,WAAiB,EACjBC,WAAmB,EACnBC,cAA4C;IAE5C,MAAMC,WAAWJ,IAAIK,YAAY;IAEjC,oCAAoC;IACpC,IAAID,SAASE,QAAQ,CAAC,UAAU;QAC9B,OAAO;YAACJ;YAAaC;SAAe;IACtC;IAEA,MAAMI,SAASP,IAAIO,MAAM;IACzB,MAAMC,gBAAqBP,YACxBQ,UAAU,CAAC,cACZ,+DAA+D;KAC9DC,OAAO,CAAC,IAAMV,IAAIW,UAAU;IAE/B,IAAIH,cAAcI,OAAO,IAAIJ,cAAcI,OAAO,CAACR,WAAW;QAC5D,OAAO;YAACF;YAAaC;SAAe;IACtC;IAEA,MAAMU,kBAAkBZ,YAAYQ,UAAU,CAAC;IAC/C,MAAM,EAAEK,MAAMC,iBAAiB,EAAEC,KAAKC,eAAe,EAAE,GACrD,MAAMJ,gBAAgBK,YAAY,CAChC,UACE,MAAMpB,UACJE,KACAE,aACAC,gBACAK,eACAJ,UACAG,QACAM;IAIR,OAAO;QAACE;QAAmBE;KAAgB;AAC7C;AAEA,SAASE,qBAEPjB,WAAmB,EACnB,6FAA6F;AAC7FC,cAAoB;IAEpB,MAAMiB,WAAW,IAAI,CAACC,KAAK;IAE3B,MAAMC,aAAa,IAAI,CAACC,gBAAgB,CAACd,UAAU,CAAC;IACpDa,WACGJ,YAAY,CAAC,IACZnB,gBAAgB,IAAI,EAAEuB,YAAYpB,aAAaC,iBAEhDqB,IAAI,CACH,CAAC,CAACT,mBAAmBE,gBAAgB,GACnCG,4BAAAA,SACE,OAAO,GAAG,MACVL,mBACAE,mBAAmBd,iBAEvB,CAACsB;QACCL,4BAAAA,SAAWK;IACb;AAEN;AAEA,6EAA6E;AAC7E,0EAA0E;AAC1E,8BAA8B;AAC9B,MAAMC,wBAGFP;AAEJ,eAAeA,qBAAoB","ignoreList":[0]}
+88
View File
@@ -0,0 +1,88 @@
/*
* Partially adapted from @babel/core (MIT license).
*/ import traverse from 'next/dist/compiled/babel/traverse';
import generate from 'next/dist/compiled/babel/generator';
import normalizeFile from 'next/dist/compiled/babel/core-lib-normalize-file';
import normalizeOpts from 'next/dist/compiled/babel/core-lib-normalize-opts';
import loadBlockHoistPlugin from 'next/dist/compiled/babel/core-lib-block-hoist-plugin';
import PluginPass from 'next/dist/compiled/babel/core-lib-plugin-pass';
import getConfig from './get-config';
import { consumeIterator } from './util';
function getTraversalParams(file, pluginPairs) {
const passPairs = [];
const passes = [];
const visitors = [];
for (const plugin of pluginPairs.concat(loadBlockHoistPlugin())){
const pass = new PluginPass(file, plugin.key, plugin.options);
passPairs.push([
plugin,
pass
]);
passes.push(pass);
visitors.push(plugin.visitor);
}
return {
passPairs,
passes,
visitors
};
}
function invokePluginPre(file, passPairs) {
for (const [{ pre }, pass] of passPairs){
if (pre) {
pre.call(pass, file);
}
}
}
function invokePluginPost(file, passPairs) {
for (const [{ post }, pass] of passPairs){
if (post) {
post.call(pass, file);
}
}
}
function transformAstPass(file, pluginPairs, parentSpan) {
const { passPairs, passes, visitors } = getTraversalParams(file, pluginPairs);
invokePluginPre(file, passPairs);
const visitor = traverse.visitors.merge(visitors, passes, // @ts-ignore - the exported types are incorrect here
file.opts.wrapPluginVisitorMethod);
parentSpan.traceChild('babel-turbo-traverse').traceFn(()=>traverse(file.ast, visitor, file.scope));
invokePluginPost(file, passPairs);
}
function transformAst(file, babelConfig, parentSpan) {
for (const pluginPairs of babelConfig.passes){
transformAstPass(file, pluginPairs, parentSpan);
}
}
export default async function transform(ctx, source, inputSourceMap, loaderOptions, filename, target, parentSpan) {
const getConfigSpan = parentSpan.traceChild('babel-turbo-get-config');
const babelConfig = await getConfig(ctx, {
source,
loaderOptions,
inputSourceMap: inputSourceMap ?? undefined,
target,
filename
});
if (!babelConfig) {
return {
code: source,
map: inputSourceMap ?? null
};
}
getConfigSpan.stop();
const normalizeSpan = parentSpan.traceChild('babel-turbo-normalize-file');
const file = consumeIterator(normalizeFile(babelConfig.passes, normalizeOpts(babelConfig), source));
normalizeSpan.stop();
const transformSpan = parentSpan.traceChild('babel-turbo-transform');
transformAst(file, babelConfig, transformSpan);
transformSpan.stop();
const generateSpan = parentSpan.traceChild('babel-turbo-generate');
const { code, map } = generate(file.ast, file.opts.generatorOpts, file.code);
generateSpan.stop();
return {
code,
map
};
}
//# sourceMappingURL=transform.js.map
File diff suppressed because one or more lines are too long
+77
View File
@@ -0,0 +1,77 @@
import type { webpack } from 'next/dist/compiled/webpack/webpack'
import type { JSONValue } from '../../../server/config-shared'
import type { Span } from '../../../trace'
export interface NextJsLoaderContext extends webpack.LoaderContext<{}> {
currentTraceSpan: Span
target: string
}
export interface NextBabelLoaderBaseOptions {
cwd: string
/**
* Should we read the user-provided custom babel config? Used in both `transformMode`s.
*/
configFile?: string
/**
* Custom plugins to be added to the generated babel options.
*/
reactCompilerPlugins?: Array<JSONValue>
/**
* Paths that the loader should not apply the react-compiler to.
*/
reactCompilerExclude?: (excludePath: string) => boolean
overrides?: any
/**
* Extra fields to pass to presets/plugins via the Babel 'caller' API.
*/
caller?: any
/**
* Advanced: Can override webpack's sourcemap behavior (see `NextJsLoaderContext["sourceMap"]`).
*/
sourceMaps?: boolean | 'inline' | 'both' | null | undefined
}
/**
* Options to create babel loader for the default transformations.
*
* This is primary usecase of babel-loader configuration for running
* all of the necessary transforms for the ecmascript instead of swc loader.
*/
export type NextBabelLoaderOptionDefaultPresets = NextBabelLoaderBaseOptions & {
transformMode: 'default'
isServer: boolean
distDir: string
pagesDir: string | undefined
srcDir: string
development: boolean
hasJsxRuntime: boolean
hasReactRefresh: boolean
}
/**
* Options to create babel loader for 'standalone' transformations.
*
* This'll create a babel loader does not enable any of the default Next.js
* presets or plugins that perform transformations. Non-transforming syntax
* plugins (e.g. Typescript) will still be enabled.
*
* This is useful when Babel is used in combination with SWC, and we expect SWC
* to perform downleveling and Next.js-specific transforms. Standalone mode is
* used in Turbopack and when React Compiler is used with webpack.
*/
export type NextBabelLoaderOptionStandalone = NextBabelLoaderBaseOptions & {
transformMode: 'standalone'
isServer: boolean
}
export type NextBabelLoaderOptions =
| NextBabelLoaderOptionDefaultPresets
| NextBabelLoaderOptionStandalone
+10
View File
@@ -0,0 +1,10 @@
export function consumeIterator(iter) {
while(true){
const { value, done } = iter.next();
if (done) {
return value;
}
}
}
//# sourceMappingURL=util.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/build/babel/loader/util.ts"],"sourcesContent":["import type { TransformOptions } from 'next/dist/compiled/babel/core'\n\nexport function consumeIterator(iter: Iterator<any>) {\n while (true) {\n const { value, done } = iter.next()\n if (done) {\n return value\n }\n }\n}\n\n/**\n * Source map standard format as to revision 3.\n *\n * `TransformOptions` uses this type, but doesn't export it separately\n */\nexport type SourceMap = NonNullable<TransformOptions['inputSourceMap']>\n\n/**\n * An extension of the normal babel configuration, with extra `babel-loader`-specific fields that transforms can read.\n *\n * See: https://github.com/babel/babel-loader/blob/main/src/injectCaller.js\n */\nexport type BabelLoaderTransformOptions = TransformOptions & {\n target?: string\n}\n"],"names":["consumeIterator","iter","value","done","next"],"mappings":"AAEA,OAAO,SAASA,gBAAgBC,IAAmB;IACjD,MAAO,KAAM;QACX,MAAM,EAAEC,KAAK,EAAEC,IAAI,EAAE,GAAGF,KAAKG,IAAI;QACjC,IAAID,MAAM;YACR,OAAOD;QACT;IACF;AACF","ignoreList":[0]}