diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index d724083f4d32b..103d845df9d06 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -156,6 +156,7 @@ "devDependencies": { "@babel/cli": "^7.10.1", "@babel/runtime": "^7.10.2", + "@types/babel-core": "^6.25.6", "@types/hapi__joi": "^16.0.12", "@types/reach__router": "^1.3.5", "@types/semver": "^7.1.0", diff --git a/packages/gatsby/src/redux/__tests__/__snapshots__/babelrc.ts.snap b/packages/gatsby/src/redux/__tests__/__snapshots__/babelrc.ts.snap index 5d666619c69cf..bdf06c2c3ba07 100644 --- a/packages/gatsby/src/redux/__tests__/__snapshots__/babelrc.ts.snap +++ b/packages/gatsby/src/redux/__tests__/__snapshots__/babelrc.ts.snap @@ -137,20 +137,26 @@ Array [ exports[`Babelrc actions/reducer allows merging config items 2`] = ` Array [ Object { + "dirname": "hi", "file": Object { + "request": "hello", "resolved": "hi", }, "options": Object { "wat": 1, }, + "value": [Function], }, Object { + "dirname": "hi2", "file": Object { + "request": "hello2", "resolved": "hi2", }, "options": Object { "wat": 2, }, + "value": [Function], }, ] `; diff --git a/packages/gatsby/src/redux/__tests__/babelrc.ts b/packages/gatsby/src/redux/__tests__/babelrc.ts index 69413460f7fa2..8874e775ed5e5 100644 --- a/packages/gatsby/src/redux/__tests__/babelrc.ts +++ b/packages/gatsby/src/redux/__tests__/babelrc.ts @@ -76,9 +76,9 @@ describe(`Babelrc actions/reducer`, () => { it(`sets default presets/plugins if there's no userland babelrc`, () => { const fakeResolver = (moduleName): string => `/path/to/module/${moduleName}` - const babel = { createConfigItem: jest.fn() } + const babel = { createConfigItem: jest.fn() } as any - prepareOptions(babel, { stage: `test` }, fakeResolver) + prepareOptions(babel, { stage: `test` as any }, fakeResolver as any) expect(babel.createConfigItem.mock.calls).toMatchSnapshot() }) @@ -89,7 +89,7 @@ describe(`Babelrc actions/reducer`, () => { { name: `test` } ) let state = babelrcReducer(undefined, action) - expect(state.stages.develop.options.sourceMaps).toBe(`inline`) + expect(state.stages.develop.options!.sourceMaps).toBe(`inline`) const updateAction = actions.setBabelOptions( { options: { sourceMaps: true } }, @@ -97,7 +97,7 @@ describe(`Babelrc actions/reducer`, () => { ) state = babelrcReducer(state, updateAction) - expect(state.stages.develop.options.sourceMaps).toBe(true) + expect(state.stages.develop.options!.sourceMaps).toBe(true) }) it(`allows setting options on a particular stage`, () => { @@ -106,16 +106,28 @@ describe(`Babelrc actions/reducer`, () => { { name: `test` } ) const state = babelrcReducer(undefined, action) - expect(state.stages.develop.options.sourceMaps).toBe(`inline`) - expect(state.stages[`develop-html`].options.sourceMaps).toBe(undefined) + expect(state.stages.develop.options!.sourceMaps).toBe(`inline`) + expect(state.stages[`develop-html`].options!.sourceMaps).toBe(undefined) }) it(`allows merging config items`, () => { - const babel = { createConfigItem: jest.fn() } + const babel = { createConfigItem: jest.fn() } as any // This merges in new change. mergeConfigItemOptions({ - items: [{ options: { wat: 1 }, file: { resolved: `hi` } }], - itemToMerge: { options: { wat: 2 }, file: { resolved: `hi` } }, + items: [ + { + value: (): null => null, + dirname: `hi`, + options: { wat: 1 }, + file: { resolved: `hi`, request: `hello` }, + }, + ], + itemToMerge: { + value: (): null => null, + dirname: `hi`, + options: { wat: 2 }, + file: { resolved: `hi`, request: `hello` }, + }, type: `plugin`, babel, }) @@ -123,8 +135,20 @@ describe(`Babelrc actions/reducer`, () => { expect( mergeConfigItemOptions({ - items: [{ options: { wat: 1 }, file: { resolved: `hi` } }], - itemToMerge: { options: { wat: 2 }, file: { resolved: `hi2` } }, + items: [ + { + value: (): null => null, + dirname: `hi`, + options: { wat: 1 }, + file: { resolved: `hi`, request: `hello` }, + }, + ], + itemToMerge: { + value: (): null => null, + dirname: `hi2`, + options: { wat: 2 }, + file: { resolved: `hi2`, request: `hello2` }, + }, type: `plugin`, babel, }) diff --git a/packages/gatsby/src/redux/types.ts b/packages/gatsby/src/redux/types.ts index 65944d9b8fedb..5d8d789b8622a 100644 --- a/packages/gatsby/src/redux/types.ts +++ b/packages/gatsby/src/redux/types.ts @@ -1,4 +1,4 @@ -import { IProgram } from "../commands/types" +import { IProgram, Stage } from "../commands/types" import { GraphQLFieldExtensionDefinition } from "../schema/extensions" import { DocumentNode, GraphQLSchema } from "graphql" import { SchemaComposer } from "graphql-compose" @@ -120,22 +120,16 @@ export interface IPlugin { options: Record } -interface IBabelStage { +export interface IBabelStage { plugins: IPlugin[] presets: IPlugin[] - options: { + options?: { cacheDirectory: boolean sourceType: string sourceMaps?: string } } -type BabelStageKeys = - | "develop" - | "develop-html" - | "build-html" - | "build-javascript" - export interface IStateProgram extends IProgram { extensions: string[] } @@ -217,7 +211,7 @@ export interface IGatsbyState { redirects: IRedirect[] babelrc: { stages: { - [key in BabelStageKeys]: IBabelStage + [key in Stage]: IBabelStage } } schemaCustomization: { @@ -319,7 +313,7 @@ export type ActionsUnion = interface ISetBabelPluginAction { type: `SET_BABEL_PLUGIN` payload: { - stage: BabelStageKeys + stage: Stage name: IPlugin["name"] options: IPlugin["options"] } @@ -328,7 +322,7 @@ interface ISetBabelPluginAction { interface ISetBabelPresetAction { type: `SET_BABEL_PRESET` payload: { - stage: BabelStageKeys + stage: Stage name: IPlugin["name"] options: IPlugin["options"] } @@ -337,7 +331,7 @@ interface ISetBabelPresetAction { interface ISetBabelOptionsAction { type: `SET_BABEL_OPTIONS` payload: { - stage: BabelStageKeys + stage: Stage name: IPlugin["name"] options: IPlugin["options"] } diff --git a/packages/gatsby/src/utils/babel-loader-helpers.js b/packages/gatsby/src/utils/babel-loader-helpers.ts similarity index 53% rename from packages/gatsby/src/utils/babel-loader-helpers.js rename to packages/gatsby/src/utils/babel-loader-helpers.ts index 5e4a45516d7ce..3ae1446bb424f 100644 --- a/packages/gatsby/src/utils/babel-loader-helpers.js +++ b/packages/gatsby/src/utils/babel-loader-helpers.ts @@ -1,7 +1,21 @@ -const path = require(`path`) -const _ = require(`lodash`) +import path from "path" +import _ from "lodash" +import Babel, { + ConfigItem, + PluginItem, + CreateConfigItemOptions, +} from "@babel/core" + +import { IBabelStage } from "../redux/types" +import { Stage } from "../commands/types" + +interface ILoadCachedConfigReturnType { + stages: { + test: IBabelStage + } +} -const loadCachedConfig = () => { +const loadCachedConfig = (): ILoadCachedConfigReturnType => { let pluginBabelConfig = { stages: { test: { plugins: [], presets: [] }, @@ -16,13 +30,17 @@ const loadCachedConfig = () => { return pluginBabelConfig } -const getCustomOptions = stage => { +export const getCustomOptions = (stage: Stage): IBabelStage["options"] => { const pluginBabelConfig = loadCachedConfig() return pluginBabelConfig.stages[stage].options } -const prepareOptions = (babel, options = {}, resolve = require.resolve) => { - let pluginBabelConfig = loadCachedConfig() +export const prepareOptions = ( + babel: typeof Babel, + options: { stage?: Stage } = {}, + resolve: RequireResolve = require.resolve +): Array => { + const pluginBabelConfig = loadCachedConfig() const { stage } = options @@ -32,7 +50,7 @@ const prepareOptions = (babel, options = {}, resolve = require.resolve) => { type: `plugin`, }), ] - const requiredPresets = [] + const requiredPresets: PluginItem[] = [] // Stage specific plugins to add if (stage === `build-html` || stage === `develop-html`) { @@ -53,7 +71,7 @@ const prepareOptions = (babel, options = {}, resolve = require.resolve) => { } // Fallback preset - const fallbackPresets = [] + const fallbackPresets: ConfigItem[] = [] fallbackPresets.push( babel.createConfigItem( @@ -70,24 +88,27 @@ const prepareOptions = (babel, options = {}, resolve = require.resolve) => { ) // Go through babel state and create config items for presets/plugins from. - const reduxPlugins = [] - const reduxPresets = [] - pluginBabelConfig.stages[stage].plugins.forEach(plugin => { - reduxPlugins.push( - babel.createConfigItem([resolve(plugin.name), plugin.options], { - name: plugin.name, - type: `plugin`, - }) - ) - }) - pluginBabelConfig.stages[stage].presets.forEach(preset => { - reduxPresets.push( - babel.createConfigItem([resolve(preset.name), preset.options], { - name: preset.name, - type: `preset`, - }) - ) - }) + const reduxPlugins: PluginItem[] = [] + const reduxPresets: PluginItem[] = [] + + if (stage) { + pluginBabelConfig.stages[stage].plugins.forEach(plugin => { + reduxPlugins.push( + babel.createConfigItem([resolve(plugin.name), plugin.options], { + name: plugin.name, + type: `plugin`, + }) + ) + }) + pluginBabelConfig.stages[stage].presets.forEach(preset => { + reduxPresets.push( + babel.createConfigItem([resolve(preset.name), preset.options], { + name: preset.name, + type: `preset`, + }) + ) + }) + } return [ reduxPresets, @@ -98,17 +119,27 @@ const prepareOptions = (babel, options = {}, resolve = require.resolve) => { ] } -const mergeConfigItemOptions = ({ items, itemToMerge, type, babel }) => { +export const mergeConfigItemOptions = ({ + items, + itemToMerge, + type, + babel, +}: { + items: ConfigItem[] + itemToMerge: ConfigItem + type: CreateConfigItemOptions["type"] + babel: typeof Babel +}): ConfigItem[] => { const index = _.findIndex( items, - i => i.file.resolved === itemToMerge.file.resolved + i => i.file?.resolved === itemToMerge.file?.resolved ) // If this exist, merge the options, otherwise, add it to the array if (index !== -1) { items[index] = babel.createConfigItem( [ - itemToMerge.file.resolved, + itemToMerge.file?.resolved, _.merge({}, items[index].options, itemToMerge.options), ], { @@ -121,9 +152,3 @@ const mergeConfigItemOptions = ({ items, itemToMerge, type, babel }) => { return items } - -exports.getCustomOptions = getCustomOptions - -// Export helper functions for testing -exports.prepareOptions = prepareOptions -exports.mergeConfigItemOptions = mergeConfigItemOptions diff --git a/packages/gatsby/src/utils/babel-loader.js b/packages/gatsby/src/utils/babel-loader.js index 3f5ad3c05e18c..47c969f982b23 100644 --- a/packages/gatsby/src/utils/babel-loader.js +++ b/packages/gatsby/src/utils/babel-loader.js @@ -1,10 +1,10 @@ const babelLoader = require(`babel-loader`) -const { +import { prepareOptions, getCustomOptions, mergeConfigItemOptions, -} = require(`./babel-loader-helpers`) +} from "./babel-loader-helpers" /** * Gatsby's custom loader for webpack & babel