Skip to content

Commit 4282980

Browse files
committed
chore: Update babel types and do some light cleanup of babel loader
1 parent c9ceeb0 commit 4282980

File tree

10 files changed

+146
-124
lines changed

10 files changed

+146
-124
lines changed

packages/next/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@
188188
"@taskr/clear": "1.1.0",
189189
"@taskr/esnext": "1.1.0",
190190
"@types/amphtml-validator": "1.0.0",
191-
"@types/babel__code-frame": "7.0.2",
192-
"@types/babel__core": "7.1.12",
193-
"@types/babel__generator": "7.6.2",
194-
"@types/babel__template": "7.4.0",
195-
"@types/babel__traverse": "7.11.0",
191+
"@types/babel__code-frame": "7.0.6",
192+
"@types/babel__core": "7.20.5",
193+
"@types/babel__generator": "7.27.0",
194+
"@types/babel__template": "7.4.4",
195+
"@types/babel__traverse": "7.20.7",
196196
"@types/bytes": "3.1.1",
197197
"@types/ci-info": "2.0.0",
198198
"@types/compression": "0.0.36",

packages/next/src/build/babel/loader/get-config.ts

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,31 @@ import { readFileSync } from 'fs'
22
import JSON5 from 'next/dist/compiled/json5'
33

44
import { createConfigItem, loadOptions } from 'next/dist/compiled/babel/core'
5-
import loadConfig from 'next/dist/compiled/babel/core-lib-config'
5+
import loadFullConfig from 'next/dist/compiled/babel/core-lib-config'
66

77
import type { NextBabelLoaderOptions, NextJsLoaderContext } from './types'
8-
import { consumeIterator } from './util'
8+
import {
9+
consumeIterator,
10+
type SourceMap,
11+
type BabelLoaderTransformOptions,
12+
} from './util'
913
import * as Log from '../../output/log'
1014
import jsx from 'next/dist/compiled/babel/plugin-syntax-jsx'
1115
import { isReactCompilerRequired } from '../../swc'
1216

17+
/**
18+
* An internal (non-exported) type used by babel.
19+
*/
20+
export type ResolvedBabelConfig = {
21+
options: BabelLoaderTransformOptions
22+
passes: BabelPluginPasses
23+
externalDependencies: ReadonlyArray<string>
24+
}
25+
26+
export type BabelPlugin = unknown
27+
export type BabelPluginPassList = ReadonlyArray<BabelPlugin>
28+
export type BabelPluginPasses = ReadonlyArray<BabelPluginPassList>
29+
1330
const nextDistPath =
1431
/(next[\\/]dist[\\/]shared[\\/]lib)|(next[\\/]dist[\\/]client)|(next[\\/]dist[\\/]pages)/
1532

@@ -275,13 +292,13 @@ function checkCustomBabelConfigDeprecation(
275292
* This config should have no unresolved overrides, presets, etc.
276293
*/
277294
async function getFreshConfig(
278-
this: NextJsLoaderContext,
295+
ctx: NextJsLoaderContext,
279296
cacheCharacteristics: CharacteristicsGermaneToCaching,
280297
loaderOptions: NextBabelLoaderOptions,
281298
target: string,
282299
filename: string,
283-
inputSourceMap?: object | null
284-
) {
300+
inputSourceMap?: SourceMap
301+
): Promise<ResolvedBabelConfig | null> {
285302
const hasReactCompiler = await (async () => {
286303
if (
287304
loaderOptions.reactCompilerPlugins &&
@@ -314,18 +331,18 @@ async function getFreshConfig(
314331

315332
let { isServer, pagesDir, srcDir, development } = loaderOptions
316333

317-
let options = {
334+
let options: BabelLoaderTransformOptions = {
318335
babelrc: false,
319336
cloneInputAst: false,
320337
filename,
321-
inputSourceMap: inputSourceMap || undefined,
338+
inputSourceMap,
322339

323340
// Ensure that Webpack will get a full absolute path in the sourcemap
324341
// so that it can properly map the module back to its internal cached
325342
// modules.
326343
sourceFileName: filename,
327-
sourceMaps: this.sourceMap,
328-
} as any
344+
sourceMaps: ctx.sourceMap,
345+
}
329346

330347
const baseCaller = {
331348
name: 'next-babel-turbo-loader',
@@ -334,7 +351,7 @@ async function getFreshConfig(
334351

335352
// Provide plugins with insight into webpack target.
336353
// https://github.com/babel/babel-loader/issues/787
337-
target: target,
354+
target,
338355

339356
// Webpack 5 supports TLA behind a flag. We enable it by default
340357
// for Babel, and then webpack will throw an error if the experimental
@@ -374,7 +391,7 @@ async function getFreshConfig(
374391
// but allow users to override if they want.
375392
options.sourceMaps =
376393
loaderOptions.sourceMaps === undefined
377-
? this.sourceMap
394+
? ctx.sourceMap
378395
: loaderOptions.sourceMaps
379396

380397
options.plugins = [
@@ -424,12 +441,12 @@ async function getFreshConfig(
424441
if (!(reason instanceof Error)) {
425442
reason = new Error(reason)
426443
}
427-
this.emitWarning(reason)
444+
ctx.emitWarning(reason)
428445
},
429446
})
430447

431448
const loadedOptions = loadOptions(options)
432-
const config = consumeIterator(loadConfig(loadedOptions))
449+
const config = consumeIterator(loadFullConfig(loadedOptions))
433450

434451
return config
435452
}
@@ -453,12 +470,11 @@ function getCacheKey(cacheCharacteristics: CharacteristicsGermaneToCaching) {
453470
return fileNameOrExt + flags
454471
}
455472

456-
type BabelConfig = any
457-
const configCache: Map<any, BabelConfig> = new Map()
473+
const configCache: Map<any, ResolvedBabelConfig | null> = new Map()
458474
const configFiles: Set<string> = new Set()
459475

460476
export default async function getConfig(
461-
this: NextJsLoaderContext,
477+
ctx: NextJsLoaderContext,
462478
{
463479
source,
464480
target,
@@ -470,9 +486,9 @@ export default async function getConfig(
470486
loaderOptions: NextBabelLoaderOptions
471487
target: string
472488
filename: string
473-
inputSourceMap?: object | null
489+
inputSourceMap?: SourceMap | undefined
474490
}
475-
): Promise<BabelConfig> {
491+
): Promise<ResolvedBabelConfig | null> {
476492
const cacheCharacteristics = getCacheCharacteristics(
477493
loaderOptions,
478494
source,
@@ -482,7 +498,7 @@ export default async function getConfig(
482498

483499
if (loaderOptions.transformMode === 'default' && loaderOptions.configFile) {
484500
// Ensures webpack invalidates the cache for this loader when the config file changes
485-
this.addDependency(loaderOptions.configFile)
501+
ctx.addDependency(loaderOptions.configFile)
486502
}
487503

488504
const cacheKey = getCacheKey(cacheCharacteristics)
@@ -515,8 +531,8 @@ export default async function getConfig(
515531
)
516532
}
517533

518-
const freshConfig = await getFreshConfig.call(
519-
this,
534+
const freshConfig = await getFreshConfig(
535+
ctx,
520536
cacheCharacteristics,
521537
loaderOptions,
522538
target,
Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
import type { Span } from '../../../trace'
22
import transform from './transform'
33
import type { NextJsLoaderContext } from './types'
4+
import type { SourceMap } from './util'
5+
import type { webpack } from 'next/dist/compiled/webpack/webpack'
46

57
async function nextBabelLoader(
6-
this: NextJsLoaderContext,
8+
ctx: NextJsLoaderContext,
79
parentTrace: Span,
810
inputSource: string,
9-
inputSourceMap: object | null | undefined
10-
) {
11-
const filename = this.resourcePath
11+
inputSourceMap: SourceMap | null | undefined
12+
): Promise<[string, SourceMap | null | undefined]> {
13+
const filename = ctx.resourcePath
1214

1315
// Ensure `.d.ts` are not processed.
1416
if (filename.endsWith('.d.ts')) {
1517
return [inputSource, inputSourceMap]
1618
}
1719

18-
const target = this.target
20+
const target = ctx.target
1921
const loaderOptions: any = parentTrace
2022
.traceChild('get-options')
2123
// @ts-ignore TODO: remove ignore once webpack 5 types are used
22-
.traceFn(() => this.getOptions())
24+
.traceFn(() => ctx.getOptions())
2325

2426
if (loaderOptions.exclude && loaderOptions.exclude(filename)) {
2527
return [inputSource, inputSourceMap]
@@ -29,8 +31,8 @@ async function nextBabelLoader(
2931
const { code: transformedSource, map: outputSourceMap } =
3032
await loaderSpanInner.traceAsyncFn(
3133
async () =>
32-
await transform.call(
33-
this,
34+
await transform(
35+
ctx,
3436
inputSource,
3537
inputSourceMap,
3638
loaderOptions,
@@ -43,25 +45,38 @@ async function nextBabelLoader(
4345
return [transformedSource, outputSourceMap]
4446
}
4547

46-
const nextBabelLoaderOuter = function nextBabelLoaderOuter(
48+
function nextBabelLoaderOuter(
4749
this: NextJsLoaderContext,
4850
inputSource: string,
49-
inputSourceMap: object | null | undefined
51+
// webpack's source map format is compatible with babel, but the type signature doesn't match
52+
inputSourceMap?: any
5053
) {
5154
const callback = this.async()
5255

5356
const loaderSpan = this.currentTraceSpan.traceChild('next-babel-turbo-loader')
5457
loaderSpan
5558
.traceAsyncFn(() =>
56-
nextBabelLoader.call(this, loaderSpan, inputSource, inputSourceMap)
59+
nextBabelLoader(this, loaderSpan, inputSource, inputSourceMap)
5760
)
5861
.then(
59-
([transformedSource, outputSourceMap]: any) =>
60-
callback?.(null, transformedSource, outputSourceMap || inputSourceMap),
62+
([transformedSource, outputSourceMap]) =>
63+
callback?.(
64+
/* err */ null,
65+
transformedSource,
66+
outputSourceMap ?? inputSourceMap
67+
),
6168
(err) => {
6269
callback?.(err)
6370
}
6471
)
6572
}
6673

74+
// check this type matches `webpack.LoaderDefinitionFunction`, but be careful
75+
// not to publicly rely on the webpack type since the generated typescript
76+
// declarations will be wrong.
77+
const _nextBabelLoaderOuter: webpack.LoaderDefinitionFunction<
78+
{},
79+
NextJsLoaderContext
80+
> = nextBabelLoaderOuter
81+
6782
export default nextBabelLoaderOuter

packages/next/src/build/babel/loader/transform.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
*/
44

55
import traverse from 'next/dist/compiled/babel/traverse'
6-
import generate from 'next/dist/compiled/babel/generator'
6+
import generate, {
7+
type GeneratorResult,
8+
} from 'next/dist/compiled/babel/generator'
79
import normalizeFile from 'next/dist/compiled/babel/core-lib-normalize-file'
810
import normalizeOpts from 'next/dist/compiled/babel/core-lib-normalize-opts'
911
import loadBlockHoistPlugin from 'next/dist/compiled/babel/core-lib-block-hoist-plugin'
@@ -13,6 +15,7 @@ import getConfig from './get-config'
1315
import { consumeIterator } from './util'
1416
import type { Span } from '../../../trace'
1517
import type { NextJsLoaderContext } from './types'
18+
import type { SourceMap } from './util'
1619

1720
function getTraversalParams(file: any, pluginPairs: any[]) {
1821
const passPairs = []
@@ -70,16 +73,21 @@ function transformAst(file: any, babelConfig: any, parentSpan: Span) {
7073
}
7174

7275
export default async function transform(
73-
this: NextJsLoaderContext,
76+
ctx: NextJsLoaderContext,
7477
source: string,
75-
inputSourceMap: object | null | undefined,
78+
inputSourceMap: SourceMap | null | undefined,
7679
loaderOptions: any,
7780
filename: string,
7881
target: string,
7982
parentSpan: Span
80-
) {
83+
): Promise<GeneratorResult> {
8184
const getConfigSpan = parentSpan.traceChild('babel-turbo-get-config')
82-
const babelConfig = await getConfig.call(this, {
85+
86+
// N.B. babel has a runtime validator that requires that `inputSourceMap` is
87+
// not `null` (`undefined` is okay)
88+
inputSourceMap = inputSourceMap ?? undefined
89+
90+
const babelConfig = await getConfig(ctx, {
8391
source,
8492
loaderOptions,
8593
inputSourceMap,

packages/next/src/build/babel/loader/types.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export type NextBabelLoaderOptionDefaultPresets = NextBabelLoaderBaseOptions & {
3030
transformMode: 'default'
3131
hasJsxRuntime: boolean
3232
hasReactRefresh: boolean
33-
sourceMaps?: any[]
33+
sourceMaps?: boolean | 'inline' | 'both' | null | undefined
3434
overrides: any
3535
configFile: string | undefined
3636
}

packages/next/src/build/babel/loader/util.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { TransformOptions } from 'next/dist/compiled/babel/core'
2+
13
export function consumeIterator(iter: Iterator<any>) {
24
while (true) {
35
const { value, done } = iter.next()
@@ -6,3 +8,19 @@ export function consumeIterator(iter: Iterator<any>) {
68
}
79
}
810
}
11+
12+
/**
13+
* Source map standard format as to revision 3.
14+
*
15+
* `TransformOptions` uses this type, but doesn't export it separately
16+
*/
17+
export type SourceMap = NonNullable<TransformOptions['inputSourceMap']>
18+
19+
/**
20+
* An extension of the normal babel configuration, with extra `babel-loader`-specific fields that transforms can read.
21+
*
22+
* See: https://github.com/babel/babel-loader/blob/main/src/injectCaller.js
23+
*/
24+
export type BabelLoaderTransformOptions = TransformOptions & {
25+
target?: string
26+
}

packages/next/src/build/babel/plugins/jsx-pragma.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,7 @@ export default function ({
7070
;[newPath] = path.unshiftContainer('body', mapping)
7171
}
7272

73-
for (const declar of newPath.get('declarations')) {
74-
path.scope.registerBinding(
75-
newPath.node.kind,
76-
declar as NodePath<BabelTypes.Node>
77-
)
78-
}
73+
path.scope.registerDeclaration(newPath)
7974
}
8075

8176
if (!existingBinding) {

packages/next/src/build/babel/plugins/react-loadable-plugin.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export default function ({
6262
let callExpression = refPath.parentPath
6363

6464
if (
65-
callExpression.isMemberExpression() &&
65+
callExpression?.isMemberExpression() &&
6666
callExpression.node.computed === false
6767
) {
6868
const property = callExpression.get('property')
@@ -74,14 +74,11 @@ export default function ({
7474
}
7575
}
7676

77-
if (!callExpression.isCallExpression()) return
77+
if (!callExpression?.isCallExpression()) return
7878

79-
const callExpression_ =
80-
callExpression as NodePath<BabelTypes.CallExpression>
81-
82-
let args = callExpression_.get('arguments')
79+
let args = callExpression.get('arguments')
8380
if (args.length > 2) {
84-
throw callExpression_.buildCodeFrameError(
81+
throw callExpression.buildCodeFrameError(
8582
'next/dynamic only accepts 2 arguments'
8683
)
8784
}
@@ -97,10 +94,10 @@ export default function ({
9794
options = args[0]
9895
} else {
9996
if (!args[1]) {
100-
callExpression_.node.arguments.push(t.objectExpression([]))
97+
callExpression.node.arguments.push(t.objectExpression([]))
10198
}
10299
// This is needed as the code is modified above
103-
args = callExpression_.get('arguments')
100+
args = callExpression.get('arguments')
104101
loader = args[0]
105102
options = args[1]
106103
}

0 commit comments

Comments
 (0)