-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
refactor(core): Make load plugins modular, prepare for TS #34813
Changes from 3 commits
6af048e
46c9493
a6f5d38
927a40d
535724a
beefd52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,102 +1,19 @@ | ||
import _ from "lodash" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only functions were extracted out of this file and put into their own files |
||
|
||
import { store } from "../../redux" | ||
import { IGatsbyState } from "../../redux/types" | ||
import * as nodeAPIs from "../../utils/api-node-docs" | ||
import * as browserAPIs from "../../utils/api-browser-docs" | ||
import ssrAPIs from "../../../cache-dir/api-ssr-docs" | ||
import { loadPlugins as loadPluginsInternal } from "./load" | ||
import { loadInternalPlugins } from "./load-internal-plugins" | ||
import { | ||
collatePluginAPIs, | ||
handleBadExports, | ||
handleMultipleReplaceRenderers, | ||
ExportType, | ||
ICurrentAPIs, | ||
validateConfigPluginsOptions, | ||
} from "./validate" | ||
import { | ||
IPluginInfo, | ||
IFlattenedPlugin, | ||
ISiteConfig, | ||
IRawSiteConfig, | ||
} from "./types" | ||
import { IPluginRefObject, PluginRef } from "gatsby-plugin-utils/dist/types" | ||
|
||
const getAPI = (api: { | ||
[exportType in ExportType]: { [api: string]: boolean } | ||
}): ICurrentAPIs => | ||
_.keys(api).reduce<Partial<ICurrentAPIs>>((merged, key) => { | ||
merged[key] = _.keys(api[key]) | ||
return merged | ||
}, {}) as ICurrentAPIs | ||
|
||
// Create a "flattened" array of plugins with all subplugins | ||
// brought to the top-level. This simplifies running gatsby-* files | ||
// for subplugins. | ||
const flattenPlugins = (plugins: Array<IPluginInfo>): Array<IPluginInfo> => { | ||
const flattened: Array<IPluginInfo> = [] | ||
const extractPlugins = (plugin: IPluginInfo): void => { | ||
if (plugin.subPluginPaths) { | ||
for (const subPluginPath of plugin.subPluginPaths) { | ||
// @pieh: | ||
// subPluginPath can look like someOption.randomFieldThatIsMarkedAsSubplugins | ||
// Reason for doing stringified path with . separator was that it was just easier to prevent duplicates | ||
// in subPluginPaths array (as each subplugin in the gatsby-config would add subplugin path). | ||
const segments = subPluginPath.split(`.`) | ||
let roots: Array<any> = [plugin.pluginOptions] | ||
for (const segment of segments) { | ||
if (segment === `[]`) { | ||
roots = roots.flat() | ||
} else { | ||
roots = roots.map(root => root[segment]) | ||
} | ||
} | ||
roots = roots.flat() | ||
|
||
roots.forEach(subPlugin => { | ||
flattened.push(subPlugin) | ||
extractPlugins(subPlugin) | ||
}) | ||
} | ||
} | ||
} | ||
|
||
plugins.forEach(plugin => { | ||
flattened.push(plugin) | ||
extractPlugins(plugin) | ||
}) | ||
|
||
return flattened | ||
} | ||
|
||
function normalizePlugin(plugin): IPluginRefObject { | ||
if (typeof plugin === `string`) { | ||
return { | ||
resolve: plugin, | ||
options: {}, | ||
} | ||
} | ||
|
||
if (plugin.options?.plugins) { | ||
plugin.options = { | ||
...plugin.options, | ||
plugins: normalizePlugins(plugin.options.plugins), | ||
} | ||
} | ||
|
||
return plugin | ||
} | ||
|
||
function normalizePlugins(plugins?: Array<PluginRef>): Array<IPluginRefObject> { | ||
return (plugins || []).map(normalizePlugin) | ||
} | ||
|
||
const normalizeConfig = (config: IRawSiteConfig = {}): ISiteConfig => { | ||
return { | ||
...config, | ||
plugins: (config.plugins || []).map(normalizePlugin), | ||
} | ||
} | ||
import { IFlattenedPlugin, IRawSiteConfig } from "./types" | ||
import { normalizeConfig } from "./utils/normalize" | ||
import { getAPI } from "./utils/get-api" | ||
import { flattenPlugins } from "./utils/flatten-plugins" | ||
|
||
export async function loadPlugins( | ||
rawConfig: IRawSiteConfig = {}, | ||
|
@@ -115,7 +32,7 @@ export async function loadPlugins( | |
}) | ||
|
||
// Collate internal plugins, site config plugins, site default plugins | ||
const pluginInfos = loadPluginsInternal(config, rootDir) | ||
const pluginInfos = await loadInternalPlugins(config, rootDir) | ||
|
||
// Create a flattened array of the plugins | ||
const pluginArray = flattenPlugins(pluginInfos) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import { slash } from "gatsby-core-utils" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file used to be |
||
import path from "path" | ||
import reporter from "gatsby-cli/lib/reporter" | ||
import { store } from "../../redux" | ||
import { | ||
IPluginInfo, | ||
IPluginRefObject, | ||
IPluginRefOptions, | ||
ISiteConfig, | ||
} from "./types" | ||
import { processPlugin } from "./process-plugin" | ||
import { createPluginId } from "./utils/create-id" | ||
import { createFileContentHash } from "./utils/create-hash" | ||
import { | ||
addGatsbyPluginCloudPluginWhenInstalled, | ||
incompatibleGatsbyCloudPlugin, | ||
GATSBY_CLOUD_PLUGIN_NAME, | ||
} from "./utils/handle-gatsby-cloud" | ||
|
||
const TYPESCRIPT_PLUGIN_NAME = `gatsby-plugin-typescript` | ||
|
||
export async function loadInternalPlugins( | ||
config: ISiteConfig = {}, | ||
rootDir: string | ||
): Promise<Array<IPluginInfo>> { | ||
// Instantiate plugins. | ||
const plugins: Array<IPluginInfo> = [] | ||
const configuredPluginNames = new Set() | ||
|
||
// Add internal plugins | ||
const internalPluginPaths = [ | ||
`../../internal-plugins/dev-404-page`, | ||
`../../internal-plugins/load-babel-config`, | ||
`../../internal-plugins/internal-data-bridge`, | ||
`../../internal-plugins/prod-404-500`, | ||
`../../internal-plugins/webpack-theme-component-shadowing`, | ||
`../../internal-plugins/bundle-optimisations`, | ||
`../../internal-plugins/functions`, | ||
].filter(Boolean) as Array<string> | ||
|
||
for (const internalPluginPath of internalPluginPaths) { | ||
const internalPluginAbsolutePath = path.join(__dirname, internalPluginPath) | ||
const processedPlugin = await processPlugin( | ||
internalPluginAbsolutePath, | ||
rootDir | ||
) | ||
plugins.push(processedPlugin) | ||
} | ||
|
||
// Add plugins from the site config. | ||
if (config.plugins) { | ||
for (const plugin of config.plugins) { | ||
const processedPlugin = await processPlugin(plugin, rootDir) | ||
plugins.push(processedPlugin) | ||
configuredPluginNames.add(processedPlugin.name) | ||
} | ||
} | ||
|
||
// the order of all of these page-creators matters. The "last plugin wins", | ||
// so the user's site comes last, and each page-creator instance has to | ||
// match the plugin definition order before that. This works fine for themes | ||
// because themes have already been added in the proper order to the plugins | ||
// array | ||
for (const plugin of [...plugins]) { | ||
const processedPlugin = await processPlugin( | ||
{ | ||
resolve: require.resolve(`gatsby-plugin-page-creator`), | ||
options: { | ||
path: slash(path.join(plugin.resolve, `src/pages`)), | ||
pathCheck: false, | ||
}, | ||
}, | ||
rootDir | ||
) | ||
|
||
plugins.push(processedPlugin) | ||
} | ||
|
||
if ( | ||
_CFLAGS_.GATSBY_MAJOR === `4` && | ||
configuredPluginNames.has(GATSBY_CLOUD_PLUGIN_NAME) && | ||
incompatibleGatsbyCloudPlugin(plugins) | ||
) { | ||
reporter.panic( | ||
`Plugin gatsby-plugin-gatsby-cloud is not compatible with your gatsby version. Please upgrade to gatsby-plugin-gatsby-cloud@next` | ||
) | ||
} | ||
|
||
if ( | ||
!configuredPluginNames.has(GATSBY_CLOUD_PLUGIN_NAME) && | ||
(process.env.GATSBY_CLOUD === `true` || process.env.GATSBY_CLOUD === `1`) | ||
) { | ||
await addGatsbyPluginCloudPluginWhenInstalled(plugins, rootDir) | ||
} | ||
|
||
// Support Typescript by default but allow users to override it | ||
if (!configuredPluginNames.has(TYPESCRIPT_PLUGIN_NAME)) { | ||
const processedTypeScriptPlugin = await processPlugin( | ||
{ | ||
resolve: require.resolve(TYPESCRIPT_PLUGIN_NAME), | ||
options: { | ||
// TODO(@mxstbr): Do not hard-code these defaults but infer them from the | ||
// pluginOptionsSchema of gatsby-plugin-typescript | ||
allExtensions: false, | ||
isTSX: false, | ||
jsxPragma: `React`, | ||
}, | ||
}, | ||
rootDir | ||
) | ||
plugins.push(processedTypeScriptPlugin) | ||
} | ||
|
||
// Add the site's default "plugin" i.e. gatsby-x files in root of site. | ||
plugins.push({ | ||
resolve: slash(process.cwd()), | ||
id: createPluginId(`default-site-plugin`), | ||
name: `default-site-plugin`, | ||
version: createFileContentHash(process.cwd(), `gatsby-*`), | ||
pluginOptions: { | ||
plugins: [], | ||
}, | ||
}) | ||
|
||
const program = store.getState().program | ||
|
||
// default options for gatsby-plugin-page-creator | ||
let pageCreatorOptions: IPluginRefOptions | undefined = { | ||
path: slash(path.join(program.directory, `src/pages`)), | ||
pathCheck: false, | ||
} | ||
|
||
if (config.plugins) { | ||
const pageCreatorPlugin = config.plugins.find( | ||
(plugin): plugin is IPluginRefObject => | ||
typeof plugin !== `string` && | ||
plugin.resolve === `gatsby-plugin-page-creator` && | ||
slash((plugin.options && plugin.options.path) || ``) === | ||
slash(path.join(program.directory, `src/pages`)) | ||
) | ||
if (pageCreatorPlugin) { | ||
// override the options if there are any user specified options | ||
pageCreatorOptions = pageCreatorPlugin.options | ||
} | ||
} | ||
|
||
const processedPageCreatorPlugin = await processPlugin( | ||
{ | ||
resolve: require.resolve(`gatsby-plugin-page-creator`), | ||
options: pageCreatorOptions, | ||
}, | ||
rootDir | ||
) | ||
|
||
plugins.push(processedPageCreatorPlugin) | ||
|
||
return plugins | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file was renamed from
load-config-and-plugins
toload-config/index.ts
and now exportsloadConfig