Files
30-seconds-of-code/node_modules/gatsby/dist/bootstrap/load-themes/index.js
2019-08-20 15:52:05 +02:00

133 lines
4.0 KiB
JavaScript

"use strict";
const path = require(`path`);
const mergeGatsbyConfig = require(`../../utils/merge-gatsby-config`);
const Promise = require(`bluebird`);
const _ = require(`lodash`);
const debug = require(`debug`)(`gatsby:load-themes`);
const preferDefault = require(`../prefer-default`);
const getConfigFile = require(`../get-config-file`); // get the gatsby-config file for a theme
const resolveTheme = async themeSpec => {
const themeName = themeSpec.resolve || themeSpec;
let themeDir;
try {
themeDir = path.dirname(require.resolve(themeName));
} catch (e) {
// this can be local plugin, and require.resolve will throw
// in this case - let's return partial entry
return {
themeName,
themeSpec
};
}
const theme = await preferDefault(getConfigFile(themeDir, `gatsby-config`)); // if theme is a function, call it with the themeConfig
let themeConfig = theme;
if (_.isFunction(theme)) {
themeConfig = theme(themeSpec.options || {});
}
return {
themeName,
themeConfig,
themeSpec,
themeDir
};
}; // single iteration of a recursive function that resolve parent themes
// It's recursive because we support child themes declaring parents and
// have to resolve all the way `up the tree` of parent/children relationships
//
// 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
const processTheme = ({
themeName,
themeConfig,
themeSpec,
themeDir
}, {
useLegacyThemes
}) => {
const themesList = useLegacyThemes ? themeConfig && themeConfig.__experimentalThemes : 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);
return processTheme(themeObj, {
useLegacyThemes
});
}).then(arr => arr.concat([{
themeName,
themeConfig,
themeSpec,
themeDir
}]));
} else {
// if a theme doesn't define additional themes, return the original theme
return [{
themeName,
themeConfig,
themeSpec,
themeDir
}];
}
};
module.exports = async (config, {
useLegacyThemes = false
}) => {
const themesA = await Promise.mapSeries(useLegacyThemes ? config.__experimentalThemes || [] : config.plugins || [], async themeSpec => {
const themeObj = await resolveTheme(themeSpec);
return processTheme(themeObj, {
useLegacyThemes
});
}).then(arr => _.flattenDeep(arr)); // log out flattened themes list to aid in debugging
debug(themesA); // map over each theme, adding the theme itself to the plugins
// list in the config for the theme. This enables the usage of
// gatsby-node, etc in themes.
return Promise.mapSeries(themesA, ({
themeName,
themeConfig = {},
themeSpec
}) => {
return Object.assign({}, themeConfig, {
plugins: [...(themeConfig.plugins || []), // 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 || {}
}]
});
})
/**
* 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
* they were defined so that later configs, like the user's site and
* children, can override functionality in earlier themes.
*/
.reduce(mergeGatsbyConfig, {}).then(newConfig => {
return {
config: mergeGatsbyConfig(newConfig, config),
themes: themesA
};
});
};
//# sourceMappingURL=index.js.map