/
index.ts
130 lines (109 loc) · 3.62 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import _ from "lodash"
import { store } from "../../redux"
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 {
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.pluginOptions && plugin.pluginOptions.plugins) {
plugin.pluginOptions.plugins.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),
}
}
export async function loadPlugins(
rawConfig: IRawSiteConfig = {},
rootDir: string | null = null
): Promise<Array<IFlattenedPlugin>> {
// Turn all strings in plugins: [`...`] into the { resolve: ``, options: {} } form
const config = normalizeConfig(rawConfig)
// Show errors for invalid plugin configuration
if (process.env.GATSBY_EXPERIMENTAL_PLUGIN_OPTION_VALIDATION) {
await validateConfigPluginsOptions(config, rootDir)
}
const currentAPIs = getAPI({
browser: browserAPIs,
node: nodeAPIs,
ssr: ssrAPIs,
})
// Collate internal plugins, site config plugins, site default plugins
const pluginInfos = loadPluginsInternal(config, rootDir)
// Create a flattened array of the plugins
const pluginArray = flattenPlugins(pluginInfos)
// Work out which plugins use which APIs, including those which are not
// valid Gatsby APIs, aka 'badExports'
const x = collatePluginAPIs({ currentAPIs, flattenedPlugins: pluginArray })
// From this point on, these are fully-resolved plugins.
let flattenedPlugins = x.flattenedPlugins
const badExports = x.badExports
// Show errors for any non-Gatsby APIs exported from plugins
await handleBadExports({ currentAPIs, badExports })
// Show errors when ReplaceRenderer has been implemented multiple times
flattenedPlugins = handleMultipleReplaceRenderers({
flattenedPlugins,
})
// If we get this far, everything looks good. Update the store
store.dispatch({
type: `SET_SITE_FLATTENED_PLUGINS`,
payload: flattenedPlugins,
})
return flattenedPlugins
}