1
+ import { readFileSync } from 'fs'
2
+
1
3
import { createConfigItem , loadOptions } from 'next/dist/compiled/babel/core'
2
4
import loadConfig from 'next/dist/compiled/babel/core-lib-config'
3
5
4
- import nextBabelPreset from '../preset'
5
6
import { NextBabelLoaderOptions , NextJsLoaderContext } from './types'
6
7
import { consumeIterator } from './util'
7
8
@@ -31,8 +32,10 @@ interface CharacteristicsGermaneToCaching {
31
32
isPageFile : boolean
32
33
isNextDist : boolean
33
34
hasModuleExports : boolean
35
+ fileExt : string
34
36
}
35
37
38
+ const fileExtensionRegex = / \. ( [ a - z ] + ) $ /
36
39
function getCacheCharacteristics (
37
40
loaderOptions : NextBabelLoaderOptions ,
38
41
source : string ,
@@ -42,12 +45,14 @@ function getCacheCharacteristics(
42
45
const isPageFile = filename . startsWith ( pagesDir )
43
46
const isNextDist = nextDistPath . test ( filename )
44
47
const hasModuleExports = source . indexOf ( 'module.exports' ) !== - 1
48
+ const fileExt = fileExtensionRegex . exec ( filename ) ?. [ 1 ] || 'unknown'
45
49
46
50
return {
47
51
isServer,
48
52
isPageFile,
49
53
isNextDist,
50
54
hasModuleExports,
55
+ fileExt,
51
56
}
52
57
}
53
58
@@ -134,6 +139,46 @@ function getPlugins(
134
139
] . filter ( Boolean )
135
140
}
136
141
142
+ const isJsonFile = / \. ( j s o n | b a b e l r c ) $ /
143
+ const isJsFile = / \. j s $ /
144
+
145
+ /**
146
+ * While this function does block execution while reading from disk, it
147
+ * should not introduce any issues. The function is only invoked when
148
+ * generating a fresh config, and only a small handful of configs should
149
+ * be generated during compilation.
150
+ */
151
+ function getCustomBabelConfig ( configFilePath : string ) {
152
+ if ( isJsonFile . exec ( configFilePath ) ) {
153
+ const babelConfigRaw = readFileSync ( configFilePath , 'utf8' )
154
+ return JSON . parse ( babelConfigRaw )
155
+ } else if ( isJsFile . exec ( configFilePath ) ) {
156
+ return require ( configFilePath )
157
+ }
158
+ throw new Error (
159
+ 'The Next Babel loader does not support MJS or CJS config files.'
160
+ )
161
+ }
162
+
163
+ function getCustomPresets ( presets : any [ ] , customConfig : any ) {
164
+ presets = [ ...presets , ...customConfig ?. presets ]
165
+
166
+ const hasNextBabelPreset = ( customConfig ?. presets || [ ] )
167
+ . filter ( ( preset : any ) => {
168
+ return (
169
+ preset === 'next/babel' ||
170
+ ( Array . isArray ( preset ) && preset [ 0 ] === 'next/babel' )
171
+ )
172
+ } )
173
+ . reduce ( ( memo : boolean , presetFound : boolean ) => memo || presetFound , false )
174
+
175
+ if ( ! hasNextBabelPreset ) {
176
+ presets . push ( 'next/babel' )
177
+ }
178
+
179
+ return presets
180
+ }
181
+
137
182
/**
138
183
* Generate a new, flat Babel config, ready to be handed to Babel-traverse.
139
184
* This config should have no unresolved overrides, presets, etc.
@@ -146,19 +191,28 @@ function getFreshConfig(
146
191
filename : string ,
147
192
inputSourceMap ?: object | null
148
193
) {
149
- const {
194
+ let {
150
195
presets = [ ] ,
151
196
isServer,
152
197
pagesDir,
153
198
development,
154
- hasReactRefresh,
155
199
hasJsxRuntime,
156
- babelrc ,
200
+ configFile ,
157
201
} = loaderOptions
158
- const nextPresetItem = createConfigItem ( nextBabelPreset , { type : 'preset' } )
202
+
203
+ let customPlugins = [ ]
204
+ if ( configFile ) {
205
+ const customConfig = getCustomBabelConfig ( configFile )
206
+ presets = getCustomPresets ( presets , customConfig )
207
+ if ( customConfig . plugins ) {
208
+ customPlugins = customConfig . plugins
209
+ }
210
+ } else {
211
+ presets = [ ...presets , 'next/babel' ]
212
+ }
159
213
160
214
let options = {
161
- babelrc,
215
+ babelrc : false ,
162
216
cloneInputAst : false ,
163
217
filename,
164
218
inputSourceMap : inputSourceMap || undefined ,
@@ -167,17 +221,20 @@ function getFreshConfig(
167
221
// but allow users to override if they want.
168
222
sourceMaps :
169
223
loaderOptions . sourceMaps === undefined
170
- ? inputSourceMap
224
+ ? this . sourceMap
171
225
: loaderOptions . sourceMaps ,
172
226
173
227
// Ensure that Webpack will get a full absolute path in the sourcemap
174
228
// so that it can properly map the module back to its internal cached
175
229
// modules.
176
230
sourceFileName : filename ,
177
231
178
- plugins : getPlugins ( loaderOptions , cacheCharacteristics ) ,
232
+ plugins : [
233
+ ...getPlugins ( loaderOptions , cacheCharacteristics ) ,
234
+ ...customPlugins ,
235
+ ] ,
179
236
180
- presets : [ ... presets , nextPresetItem ] ,
237
+ presets,
181
238
182
239
overrides : loaderOptions . overrides ,
183
240
@@ -197,8 +254,7 @@ function getFreshConfig(
197
254
198
255
isServer,
199
256
pagesDir,
200
- development,
201
- hasReactRefresh,
257
+ isDev : development ,
202
258
hasJsxRuntime,
203
259
204
260
...loaderOptions . caller ,
@@ -233,19 +289,21 @@ function getCacheKey(cacheCharacteristics: CharacteristicsGermaneToCaching) {
233
289
isPageFile,
234
290
isNextDist,
235
291
hasModuleExports,
292
+ fileExt,
236
293
} = cacheCharacteristics
237
294
238
- return (
295
+ const flags =
239
296
0 |
240
297
( isServer ? 0b0001 : 0 ) |
241
298
( isPageFile ? 0b0010 : 0 ) |
242
299
( isNextDist ? 0b0100 : 0 ) |
243
300
( hasModuleExports ? 0b1000 : 0 )
244
- )
301
+
302
+ return fileExt + flags
245
303
}
246
304
247
305
type BabelConfig = any
248
- const configCache : Map < number , BabelConfig > = new Map ( )
306
+ const configCache : Map < any , BabelConfig > = new Map ( )
249
307
250
308
export default function getConfig (
251
309
this : NextJsLoaderContext ,
@@ -271,10 +329,17 @@ export default function getConfig(
271
329
272
330
const cacheKey = getCacheKey ( cacheCharacteristics )
273
331
if ( configCache . has ( cacheKey ) ) {
332
+ const cachedConfig = configCache . get ( cacheKey )
333
+
274
334
return {
275
- ...configCache . get ( cacheKey ) ,
276
- filename,
277
- sourceFileName : filename ,
335
+ ...cachedConfig ,
336
+ options : {
337
+ ...cachedConfig . options ,
338
+ cwd : loaderOptions . cwd ,
339
+ root : loaderOptions . cwd ,
340
+ filename,
341
+ sourceFileName : filename ,
342
+ } ,
278
343
}
279
344
}
280
345
0 commit comments