From 39efdf3a0059cbc103c196dc7f844d0b4fe3efb9 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Wed, 23 Dec 2020 03:59:56 +0100 Subject: [PATCH] perf(gatsby): cache babel partial config and babel custom options --- packages/gatsby/src/utils/babel-loader.js | 39 ++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/packages/gatsby/src/utils/babel-loader.js b/packages/gatsby/src/utils/babel-loader.js index 6694210c8c520..a9911d91a888c 100644 --- a/packages/gatsby/src/utils/babel-loader.js +++ b/packages/gatsby/src/utils/babel-loader.js @@ -23,8 +23,12 @@ const { getBrowsersList } = require(`./browserslist`) * * You can find documentation for the custom loader here: https://babeljs.io/docs/en/next/babel-core.html#loadpartialconfig */ + +const customOptionsCache = new Map() +const configCache = new Map() + module.exports = babelLoader.custom(babel => { - const toReturn = { + return { // Passed the loader options. customOptions({ stage = `test`, @@ -32,7 +36,11 @@ module.exports = babelLoader.custom(babel => { rootDir = process.cwd(), ...options }) { - return { + if (customOptionsCache.has(stage)) { + return customOptionsCache.get(stage) + } + + const toReturn = { custom: { stage, reactRuntime, @@ -49,11 +57,27 @@ module.exports = babelLoader.custom(babel => { ...options, }, } + + customOptionsCache.set(stage, toReturn) + + return toReturn }, // Passed Babel's 'PartialConfig' object. config(partialConfig, { customOptions }) { + let configCacheKey = customOptions.stage + if (partialConfig.hasFilesystemConfig()) { + // partialConfig.files is a Set that accumulates used config files (absolute paths) + partialConfig.files.forEach(configFilePath => { + configCacheKey += `_${configFilePath}` + }) + } + let { options } = partialConfig + if (configCache.has(configCacheKey)) { + return { ...options, ...configCache.get(configCacheKey) } + } + const [ reduxPresets, reduxPlugins, @@ -101,9 +125,16 @@ module.exports = babelLoader.custom(babel => { }) }) + // cache just plugins and presets, because config also includes things like + // filenames - this is mostly to not call `mergeConfigItemOptions` for each file + // as that function call `babel.createConfigItem` and is quite expensive but also + // skips quite a few nested loops on top of that + configCache.set(configCacheKey, { + plugins: options.plugins, + presets: options.presets, + }) + return options }, } - - return toReturn })