195 lines
5.9 KiB
JavaScript
195 lines
5.9 KiB
JavaScript
"use strict";
|
|
|
|
const _ = require(`lodash`);
|
|
|
|
const slash = require(`slash`);
|
|
|
|
const fs = require(`fs`);
|
|
|
|
const path = require(`path`);
|
|
|
|
const crypto = require(`crypto`);
|
|
|
|
const glob = require(`glob`);
|
|
|
|
const {
|
|
warnOnIncompatiblePeerDependency
|
|
} = require(`./validate`);
|
|
|
|
const {
|
|
store
|
|
} = require(`../../redux`);
|
|
|
|
const existsSync = require(`fs-exists-cached`).sync;
|
|
|
|
const createNodeId = require(`../../utils/create-node-id`);
|
|
|
|
const createRequireFromPath = require(`../../utils/create-require-from-path`);
|
|
|
|
function createFileContentHash(root, globPattern) {
|
|
const hash = crypto.createHash(`md5`);
|
|
const files = glob.sync(`${root}/${globPattern}`, {
|
|
nodir: true
|
|
});
|
|
files.forEach(filepath => {
|
|
hash.update(fs.readFileSync(filepath));
|
|
});
|
|
return hash.digest(`hex`);
|
|
}
|
|
/**
|
|
* Make sure key is unique to plugin options. E.g there could
|
|
* be multiple source-filesystem plugins, with different names
|
|
* (docs, blogs).
|
|
* @param {*} name Name of the plugin
|
|
* @param {*} pluginObject
|
|
*/
|
|
|
|
|
|
const createPluginId = (name, pluginObject = null) => createNodeId(name + (pluginObject ? JSON.stringify(pluginObject.options) : ``), `Plugin`);
|
|
/**
|
|
* @typedef {Object} PluginInfo
|
|
* @property {string} resolve The absolute path to the plugin
|
|
* @property {string} name The plugin name
|
|
* @property {string} version The plugin version (can be content hash)
|
|
*/
|
|
|
|
/**
|
|
* resolvePlugin
|
|
* @param {string} pluginName
|
|
* This can be a name of a local plugin, the name of a plugin located in
|
|
* node_modules, or a Gatsby internal plugin. In the last case the pluginName
|
|
* will be an absolute path.
|
|
* @param {string} rootDir
|
|
* This is the project location, from which are found the plugins
|
|
* @return {PluginInfo}
|
|
*/
|
|
|
|
|
|
function resolvePlugin(pluginName, rootDir) {
|
|
// Only find plugins when we're not given an absolute path
|
|
if (!existsSync(pluginName)) {
|
|
// Find the plugin in the local plugins folder
|
|
const resolvedPath = slash(path.resolve(`./plugins/${pluginName}`));
|
|
|
|
if (existsSync(resolvedPath)) {
|
|
if (existsSync(`${resolvedPath}/package.json`)) {
|
|
const packageJSON = JSON.parse(fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`));
|
|
const name = packageJSON.name || pluginName;
|
|
warnOnIncompatiblePeerDependency(name, packageJSON);
|
|
return {
|
|
resolve: resolvedPath,
|
|
name,
|
|
id: createPluginId(name),
|
|
version: packageJSON.version || createFileContentHash(resolvedPath, `**`)
|
|
};
|
|
} else {
|
|
// Make package.json a requirement for local plugins too
|
|
throw new Error(`Plugin ${pluginName} requires a package.json file`);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Here we have an absolute path to an internal plugin, or a name of a module
|
|
* which should be located in node_modules.
|
|
*/
|
|
|
|
|
|
try {
|
|
const requireSource = rootDir !== null ? createRequireFromPath(`${rootDir}/:internal:`) : require;
|
|
const resolvedPath = slash(path.dirname(requireSource.resolve(pluginName)));
|
|
const packageJSON = JSON.parse(fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`));
|
|
warnOnIncompatiblePeerDependency(packageJSON.name, packageJSON);
|
|
return {
|
|
resolve: resolvedPath,
|
|
id: createPluginId(packageJSON.name),
|
|
name: packageJSON.name,
|
|
version: packageJSON.version
|
|
};
|
|
} catch (err) {
|
|
throw new Error(`Unable to find plugin "${pluginName}". Perhaps you need to install its package?`);
|
|
}
|
|
}
|
|
|
|
module.exports = (config = {}, rootDir = null) => {
|
|
// Instantiate plugins.
|
|
const plugins = []; // Create fake little site with a plugin for testing this
|
|
// w/ snapshots. Move plugin processing to its own module.
|
|
// Also test adding to redux store.
|
|
|
|
const processPlugin = plugin => {
|
|
if (_.isString(plugin)) {
|
|
const info = resolvePlugin(plugin, rootDir);
|
|
return Object.assign({}, info, {
|
|
pluginOptions: {
|
|
plugins: []
|
|
}
|
|
});
|
|
} else {
|
|
plugin.options = plugin.options || {}; // Plugins can have plugins.
|
|
|
|
const subplugins = [];
|
|
|
|
if (plugin.options.plugins) {
|
|
plugin.options.plugins.forEach(p => {
|
|
subplugins.push(processPlugin(p));
|
|
});
|
|
plugin.options.plugins = subplugins;
|
|
} // Add some default values for tests as we don't actually
|
|
// want to try to load anything during tests.
|
|
|
|
|
|
if (plugin.resolve === `___TEST___`) {
|
|
const name = `TEST`;
|
|
return {
|
|
id: createPluginId(name, plugin),
|
|
name,
|
|
pluginOptions: {
|
|
plugins: []
|
|
}
|
|
};
|
|
}
|
|
|
|
const info = resolvePlugin(plugin.resolve, rootDir);
|
|
return Object.assign({}, info, {
|
|
id: createPluginId(info.name, plugin),
|
|
pluginOptions: _.merge({
|
|
plugins: []
|
|
}, plugin.options)
|
|
});
|
|
}
|
|
}; // Add internal plugins
|
|
|
|
|
|
const internalPlugins = [`../../internal-plugins/dev-404-page`, `../../internal-plugins/load-babel-config`, `../../internal-plugins/internal-data-bridge`, `../../internal-plugins/prod-404`, `../../internal-plugins/webpack-theme-component-shadowing`];
|
|
internalPlugins.forEach(relPath => {
|
|
const absPath = path.join(__dirname, relPath);
|
|
plugins.push(processPlugin(absPath));
|
|
}); // Add plugins from the site config.
|
|
|
|
if (config.plugins) {
|
|
config.plugins.forEach(plugin => {
|
|
plugins.push(processPlugin(plugin));
|
|
});
|
|
} // 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;
|
|
plugins.push(processPlugin({
|
|
resolve: require.resolve(`gatsby-plugin-page-creator`),
|
|
options: {
|
|
path: slash(path.join(program.directory, `src/pages`)),
|
|
pathCheck: false
|
|
}
|
|
}));
|
|
return plugins;
|
|
};
|
|
//# sourceMappingURL=load.js.map
|