Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(gatsby): migrate bootstrap load-themes to typescript #32790

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/gatsby/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "3.13.0-next.0",
"author": "Kyle Mathews <[email protected]>",
"bin": {
"gatsby": "./cli.js"
"gatsby": "cli.js"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
Expand Down Expand Up @@ -168,6 +168,7 @@
"@babel/register": "^7.14.0",
"@babel/runtime": "^7.14.8",
"@types/eslint": "^7.2.6",
"@types/lodash": "^4.14.172",
"@types/micromatch": "^4.0.1",
"@types/normalize-path": "^3.0.0",
"@types/reach__router": "^1.3.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const loadThemes = require(`..`)
const path = require(`path`)
import { loadThemes } from ".."
import path from "path"

describe(`loadThemes`, () => {
test(`resolves themes and plugins from location of gatsby-config`, async () => {
Expand Down Expand Up @@ -33,7 +33,6 @@ describe(`loadThemes`, () => {
config: { plugins },
themes,
} = await loadThemes(config, {
useLegacyThemes: false,
configFilePath,
rootDir: path.dirname(configFilePath),
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
const { createRequireFromPath } = require(`gatsby-core-utils`)
const path = require(`path`)
import { mergeGatsbyConfig } from "../../utils/merge-gatsby-config"
const Promise = require(`bluebird`)
const _ = require(`lodash`)
import { createRequireFromPath } from "gatsby-core-utils"
import path from "path"
import {
IGatsbyConfigInput,
mergeGatsbyConfig,
} from "../../utils/merge-gatsby-config"
import _Promise from "bluebird"
import _ from "lodash"
const debug = require(`debug`)(`gatsby:load-themes`)
import { preferDefault } from "../prefer-default"
import { getConfigFile } from "../get-config-file"
const { resolvePlugin } = require(`../load-plugins/load`)
const reporter = require(`gatsby-cli/lib/reporter`)
import { resolvePlugin } from "../load-plugins/load"
import reporter from "gatsby-cli/lib/reporter"
import { ITheme, IThemeSpec } from "./types"
import { IGatsbyConfig } from "../../redux/types"

// get the gatsby-config file for a theme
const resolveTheme = async (
themeSpec,
configFileThatDeclaredTheme,
themeSpec: IThemeSpec | string,
configFileThatDeclaredTheme: string,
isMainConfig = false,
rootDir
) => {
const themeName = themeSpec.resolve || themeSpec
let themeDir
rootDir: string
): Promise<ITheme> => {
const themeName =
typeof themeSpec === `string` ? themeSpec : themeSpec.resolve || ``
let themeDir: string | undefined = undefined
try {
const scopedRequire = createRequireFromPath(`${rootDir}/:internal:`)
// theme is an node-resolvable module
themeDir = path.dirname(scopedRequire.resolve(themeName))
} catch (e) {
let pathToLocalTheme
let pathToLocalTheme: string | undefined = undefined

// only try to look for local theme in main site
// local themes nested in other themes is potential source of problems:
Expand Down Expand Up @@ -62,14 +68,25 @@ const resolveTheme = async (
const theme = preferDefault(configModule)

// if theme is a function, call it with the themeConfig
let themeConfig = theme
let themeConfig: Record<string, string>
if (_.isFunction(theme)) {
themeConfig = theme(themeSpec.options || {})
themeConfig = theme(
typeof themeSpec !== `string` && themeSpec.options
? themeSpec.options
: {}
)
} else {
themeConfig = theme
}
return {
themeName,
themeConfig,
themeSpec,
themeSpec:
typeof themeSpec !== `string`
? themeSpec
: {
resolve: themeSpec,
},
themeDir,
parentDir: rootDir,
configFilePath,
Expand All @@ -83,44 +100,65 @@ const resolveTheme = async (
// Theoretically, there could be an infinite loop here but in practice there is
// no use case for a loop so I expect that to only happen if someone is very
// off track and creating their own set of themes

type ValueOrArray<T> = T | Array<ValueOrArray<T>>

const processTheme = (
{ themeName, themeConfig, themeSpec, themeDir, configFilePath },
{ themeName, themeConfig, themeSpec, themeDir, configFilePath }: ITheme,
{ rootDir }
) => {
): Array<ITheme> | _Promise<ValueOrArray<ITheme>> => {
const themesList = themeConfig && themeConfig.plugins
// Gatsby themes don't have to specify a gatsby-config.js (they might only use gatsby-node, etc)
// in this case they're technically plugins, but we should support it anyway
// because we can't guarantee which files theme creators create first
if (themeConfig && themesList) {
// for every parent theme a theme defines, resolve the parent's
// gatsby config and return it in order [parentA, parentB, child]
return Promise.mapSeries(themesList, async spec => {
const themeObj = await resolveTheme(spec, configFilePath, false, themeDir)
return processTheme(themeObj, { rootDir: themeDir })
}).then(arr =>
arr.concat([
{ themeName, themeConfig, themeSpec, themeDir, parentDir: rootDir },
])
)
return _Promise
.mapSeries(themesList, async spec => {
const themeObj = await resolveTheme(
spec,
configFilePath || ``,
false,
themeDir
)
return processTheme(themeObj, { rootDir: themeDir })
})
.then(arr =>
arr.concat([
{ themeName, themeConfig, themeSpec, themeDir, parentDir: rootDir },
])
)
} else {
// if a theme doesn't define additional themes, return the original theme
return [{ themeName, themeConfig, themeSpec, themeDir, parentDir: rootDir }]
}
}

module.exports = async (config, { configFilePath, rootDir }) => {
const themesA = await Promise.mapSeries(
config.plugins || [],
async themeSpec => {
export const loadThemes = async (
config: IGatsbyConfig,
{
configFilePath,
rootDir,
}: {
configFilePath: string
rootDir: string
}
): Promise<{
config: IGatsbyConfigInput
themes: Array<ITheme>
}> => {
const themesA = await _Promise
.mapSeries(config.plugins || [], async themeSpec => {
const themeObj = await resolveTheme(
themeSpec,
typeof themeSpec === `string` ? themeSpec : themeSpec.resolve,
configFilePath,
true,
rootDir
)
return processTheme(themeObj, { rootDir })
}
).then(arr => _.flattenDeep(arr))
})
.then(arr => _.flattenDeep(arr))

// log out flattened themes list to aid in debugging
debug(themesA)
Expand All @@ -129,25 +167,31 @@ module.exports = async (config, { configFilePath, rootDir }) => {
// list in the config for the theme. This enables the usage of
// gatsby-node, etc in themes.
return (
Promise.mapSeries(
themesA,
({ themeName, themeConfig = {}, themeSpec, themeDir, parentDir }) => {
return {
...themeConfig,
plugins: [
...(themeConfig.plugins || []).map(plugin => {
return {
resolve: typeof plugin === `string` ? plugin : plugin.resolve,
options: plugin.options || {},
parentDir: themeDir,
}
}),
// theme plugin is last so it's gatsby-node, etc can override it's declared plugins, like a normal site.
{ resolve: themeName, options: themeSpec.options || {}, parentDir },
],
_Promise
.mapSeries(
themesA,
({ themeName, themeConfig = {}, themeSpec, themeDir, parentDir }) => {
return {
...themeConfig,
plugins: [
...(themeConfig.plugins || []).map(plugin => {
return {
resolve: typeof plugin === `string` ? plugin : plugin.resolve,
options: plugin.options || {},
parentDir: themeDir,
}
}),
// theme plugin is last so it's gatsby-node, etc can override it's declared plugins, like a normal site.
{
resolve: themeName,
options:
typeof themeSpec === `string` ? {} : themeSpec.options || {},
parentDir,
},
],
}
}
}
)
)
/**
* themes resolve to a gatsby-config, so here we merge all of the configs
* into a single config, making sure to maintain the order in which
Expand Down
15 changes: 15 additions & 0 deletions packages/gatsby/src/bootstrap/load-themes/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { IGatsbyConfig } from "../../redux/types"

export interface ITheme {
themeName: string
themeConfig: IGatsbyConfig
themeSpec: string | IThemeSpec
themeDir: string
parentDir?: string
configFilePath?: string
}

export interface IThemeSpec {
resolve?: string
options?: { [key: string]: unknown }
}
2 changes: 1 addition & 1 deletion packages/gatsby/src/utils/merge-gatsby-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ interface INormalizedPluginEntry {
options: Record<string, unknown>
}

interface IGatsbyConfigInput {
export interface IGatsbyConfigInput {
siteMetadata?: Record<string, unknown>
plugins?: Array<PluginEntry>
pathPrefix?: string
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4715,6 +4715,11 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6"
integrity sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q==

"@types/lodash@^4.14.172":
version "4.14.172"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.172.tgz#aad774c28e7bfd7a67de25408e03ee5a8c3d028a"
integrity sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==

"@types/mdast@^3.0.0", "@types/mdast@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb"
Expand Down