From 2065935bccfe8c9a6ee90757720fd7795625fed0 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Thu, 8 Jun 2017 11:59:59 +0200 Subject: [PATCH 01/13] Add ability to locally define plugins --- packages/gatsby/src/bootstrap/load-plugins.js | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index 0f25742b249cb..811887839f8c1 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -6,6 +6,32 @@ const path = require(`path`) const { store } = require(`../redux`) const nodeAPIs = require(`../utils/api-node-docs`) +function resolvePluginPath(pluginNameOrPath) { + try { + // Find the plugin in the node_modules folder + return slash(path.dirname(require.resolve(pluginNameOrPath))) + } catch (e) { + // Find the plugin relative to the current working directory + const resolvedPath = slash(path.resolve(pluginNameOrPath)) + + /** + * The path.resolve call defaults to the current working directory. + * Avoid picking up gatsby-* files and package.json from the project root + * when the plugin can't be found. + */ + if(resolvedPath === slash(process.cwd())) { + throw new Error(`Local plugin "${pluginNameOrPath}" was not found`) + } + + // Check if path looks like a plugin package + if (!fs.existsSync(`${resolvedPath}/package.json`)) { + throw new Error(`Local plugin "${pluginNameOrPath}" requires a package.json file`) + } + + return resolvedPath + } +} + module.exports = async (config = {}) => { // Instantiate plugins. const plugins = [] @@ -15,7 +41,8 @@ module.exports = async (config = {}) => { // Also test adding to redux store. const processPlugin = plugin => { if (_.isString(plugin)) { - const resolvedPath = slash(path.dirname(require.resolve(plugin))) + const resolvedPath = resolvePluginPath(plugin) + const packageJSON = JSON.parse( fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) ) @@ -40,14 +67,15 @@ module.exports = async (config = {}) => { // Add some default values for tests as we don't actually // want to try to load anything during tests. - let resolvedPath - let packageJSON = { name: `TEST` } - if (plugin.resolve !== `___TEST___`) { - resolvedPath = slash(path.dirname(require.resolve(plugin.resolve))) - packageJSON = JSON.parse( - fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) - ) + if (plugin.resolve === `___TEST___`) { + return { name: `TEST` } } + + const resolvedPath = resolvePluginPath(plugin.resolve) + const packageJSON = JSON.parse( + fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) + ) + return { resolve: resolvedPath, name: packageJSON.name, From 1597642b2eb43e2445033f59f27543cd92903c13 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Sun, 11 Jun 2017 18:22:41 +0200 Subject: [PATCH 02/13] Restrict local plugin search to ./plugins folder --- packages/gatsby/src/bootstrap/load-plugins.js | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index 811887839f8c1..0587427bd5d04 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -6,29 +6,42 @@ const path = require(`path`) const { store } = require(`../redux`) const nodeAPIs = require(`../utils/api-node-docs`) -function resolvePluginPath(pluginNameOrPath) { - try { - // Find the plugin in the node_modules folder - return slash(path.dirname(require.resolve(pluginNameOrPath))) - } catch (e) { - // Find the plugin relative to the current working directory - const resolvedPath = slash(path.resolve(pluginNameOrPath)) - - /** - * The path.resolve call defaults to the current working directory. - * Avoid picking up gatsby-* files and package.json from the project root - * when the plugin can't be found. - */ - if(resolvedPath === slash(process.cwd())) { - throw new Error(`Local plugin "${pluginNameOrPath}" was not found`) - } +function isAbsolutePath(path) { + return fs.existsSync(path) +} + +/** + * resolvePluginPath + * @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. + */ +function resolvePluginPath(pluginName) { + + if (!isAbsolutePath(pluginName)) { + + // Find the plugin in the local plugins folder + const resolvedPath = slash(path.resolve(`./plugins/${pluginName}`)) - // Check if path looks like a plugin package - if (!fs.existsSync(`${resolvedPath}/package.json`)) { - throw new Error(`Local plugin "${pluginNameOrPath}" requires a package.json file`) + if(fs.existsSync(resolvedPath)) { + + // Validate the plugin structure + if(!fs.existsSync(`${path}/package.json`)) { + throw new Error(`Local plugin "${pluginName}" requires a package.json file.`) + } + + return resolvedPath } + } - return resolvedPath + /** + * Here we have an absolute path to an internal plugin, or a name of a module + * which should be found in node_modules. + */ + try { + return slash(path.dirname(require.resolve(pluginName))) + } catch (err) { + throw new Error(`Unable to find plugin "${pluginName}"`) } } From 259cbe17ce0a224b9e8bcb587abf9fd2527bb4b1 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 12:16:59 +0200 Subject: [PATCH 03/13] Add content hash for local plugins --- packages/gatsby/src/bootstrap/load-plugins.js | 94 +++++++++++++------ .../query-runner/query-watcher.js | 3 + 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index 0587427bd5d04..d34e423329fe9 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -2,44 +2,86 @@ const _ = require(`lodash`) const slash = require(`slash`) const fs = require(`fs`) const path = require(`path`) - +const crypto = require(`crypto`) const { store } = require(`../redux`) const nodeAPIs = require(`../utils/api-node-docs`) +const Promise = require(`bluebird`) +const globCB = require(`glob`) +const glob = Promise.promisify(globCB) + +async function createFileContentHash(root, pattern) { + const hash = crypto.createHash(`md5`) + + const files = await glob(`${root}/${pattern}`, { nodir: true }) + + files.forEach(filepath => { + console.log(`+++ glob filepath`, filepath) + hash.update(fs.readFileSync(filepath)) + }) -function isAbsolutePath(path) { - return fs.existsSync(path) + return hash.digest(`hex`) } /** - * resolvePluginPath - * @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. + * @typedef {Object} PluginInfo + * @property {string} resolve The absolute path to the plugin + * @property {string} name The plugin name + * @property {string|number} version The plugin version (can be content hash) */ -function resolvePluginPath(pluginName) { - if (!isAbsolutePath(pluginName)) { +/** + * 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. + * @return {PluginInfo} + */ +async function resolvePlugin(pluginName) { + + // Only find plugins when we're not given an absolute path + if (!fs.existsSync(pluginName)) { // Find the plugin in the local plugins folder const resolvedPath = slash(path.resolve(`./plugins/${pluginName}`)) if(fs.existsSync(resolvedPath)) { - // Validate the plugin structure - if(!fs.existsSync(`${path}/package.json`)) { - throw new Error(`Local plugin "${pluginName}" requires a package.json file.`) - } + if(fs.existsSync(`${resolvedPath}/package.json`)) { + const packageJSON = JSON.parse( + fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) + ) + + return { + resolve: resolvedPath, + name: packageJSON.name || pluginName, + version: packageJSON.version || await createFileContentHash(resolvedPath, `**/*`), + } - return 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 found in node_modules. + * which should be located in node_modules. */ try { - return slash(path.dirname(require.resolve(pluginName))) + const resolvedPath = slash(path.dirname(require.resolve(pluginName))) + + const packageJSON = JSON.parse( + fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) + ) + + return { + resolve: resolvedPath, + name: packageJSON.name, + version: packageJSON.version, + } + } catch (err) { throw new Error(`Unable to find plugin "${pluginName}"`) } @@ -54,15 +96,10 @@ module.exports = async (config = {}) => { // Also test adding to redux store. const processPlugin = plugin => { if (_.isString(plugin)) { - const resolvedPath = resolvePluginPath(plugin) + const info = resolvePlugin(plugin) - const packageJSON = JSON.parse( - fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) - ) return { - resolve: resolvedPath, - name: packageJSON.name, - version: packageJSON.version, + ...info, pluginOptions: { plugins: [], }, @@ -84,15 +121,10 @@ module.exports = async (config = {}) => { return { name: `TEST` } } - const resolvedPath = resolvePluginPath(plugin.resolve) - const packageJSON = JSON.parse( - fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) - ) + const info = resolvePlugin(plugin.resolve) return { - resolve: resolvedPath, - name: packageJSON.name, - version: packageJSON.version, + ...info, pluginOptions: _.merge({ plugins: [] }, plugin.options), } } @@ -127,7 +159,7 @@ module.exports = async (config = {}) => { plugins.push({ resolve: slash(process.cwd()), name: `default-site-plugin`, - version: `n/a`, + version: await createFileContentHash(process.cwd(), `gatsby-*`), pluginOptions: { plugins: [], }, diff --git a/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js b/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js index 1520b1c9c6c26..11d1931cb47e6 100644 --- a/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js +++ b/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js @@ -15,6 +15,7 @@ const { store } = require(`../../redux/`) const { boundActionCreators } = require(`../../redux/actions`) const queryCompiler = require(`./query-compiler`).default const queryRunner = require(`./query-runner`) +const invariant = require(`invariant`) exports.extractQueries = () => { const pages = store.getState().pages @@ -57,6 +58,8 @@ exports.watch = rootDir => { queryCompiler().then(queries => { const pages = store.getState().pageComponents queries.forEach(({ text }, path) => { + invariant(pages[path], `Path ${path} not found in the store pages: ${JSON.stringify(pages)}`) + if (text !== pages[path].query) { boundActionCreators.replacePageComponentQuery({ query: text, From a3ee1e6eb472df249d1141fd3ac137d88b1d6b19 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 12:33:52 +0200 Subject: [PATCH 04/13] Catch some errors earlier --- packages/gatsby/src/bootstrap/load-plugins.js | 8 +++++++- packages/gatsby/src/schema/index.js | 17 ++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index d34e423329fe9..33700f0b78c00 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -52,10 +52,16 @@ async function resolvePlugin(pluginName) { fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) ) + console.log('resolve plugin', { + resolve: resolvedPath, + name: packageJSON.name || pluginName, + version: packageJSON.version || await createFileContentHash(resolvedPath, `**`), + }) + return { resolve: resolvedPath, name: packageJSON.name || pluginName, - version: packageJSON.version || await createFileContentHash(resolvedPath, `**/*`), + version: packageJSON.version || await createFileContentHash(resolvedPath, `**`), } } else { diff --git a/packages/gatsby/src/schema/index.js b/packages/gatsby/src/schema/index.js index 15615b986a5de..8b248aee8c3c9 100644 --- a/packages/gatsby/src/schema/index.js +++ b/packages/gatsby/src/schema/index.js @@ -5,21 +5,22 @@ const { GraphQLSchema, GraphQLObjectType } = require(`graphql`) const buildNodeTypes = require(`./build-node-types`) const buildNodeConnections = require(`./build-node-connections`) const { store } = require(`../redux`) +const invariant = require(`invariant`) module.exports = async () => { const typesGQL = await buildNodeTypes() const connections = buildNodeConnections(_.values(typesGQL)) + // Pull off just the graphql node from each type object. + const nodes = _.mapValues(typesGQL, `node`) + + invariant(!_.isEmpty(nodes), `There are no available GQL nodes`) + invariant(!_.isEmpty(connections), `There are no available GQL connections`) + const schema = new GraphQLSchema({ query: new GraphQLObjectType({ name: `RootQueryType`, - fields: () => { - return { - // Pull off just the graphql node from each type object. - ..._.mapValues(typesGQL, `node`), - ...connections, - } - }, + fields: { ...nodes, ...connections }, }), }) @@ -28,6 +29,4 @@ module.exports = async () => { type: `SET_SCHEMA`, payload: schema, }) - - return } From 13e6044f38a05788314ac08ba58091eca7cce18a Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 13:49:41 +0200 Subject: [PATCH 05/13] Add missing timer start --- packages/gatsby/src/schema/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/gatsby/src/schema/index.js b/packages/gatsby/src/schema/index.js index 8b248aee8c3c9..8c1e1f11d4efb 100644 --- a/packages/gatsby/src/schema/index.js +++ b/packages/gatsby/src/schema/index.js @@ -8,6 +8,8 @@ const { store } = require(`../redux`) const invariant = require(`invariant`) module.exports = async () => { + console.time(`building schema`) + const typesGQL = await buildNodeTypes() const connections = buildNodeConnections(_.values(typesGQL)) From 1798e390ecaed1deab456f35651b151c21ba8f5f Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 14:16:54 +0200 Subject: [PATCH 06/13] Make hash function sync because it simplifies things --- packages/gatsby/src/bootstrap/load-plugins.js | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index 33700f0b78c00..a4e99f1b1168c 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -5,17 +5,13 @@ const path = require(`path`) const crypto = require(`crypto`) const { store } = require(`../redux`) const nodeAPIs = require(`../utils/api-node-docs`) -const Promise = require(`bluebird`) -const globCB = require(`glob`) -const glob = Promise.promisify(globCB) +const glob = require(`glob`) -async function createFileContentHash(root, pattern) { +function createFileContentHash(root, globPattern) { const hash = crypto.createHash(`md5`) - - const files = await glob(`${root}/${pattern}`, { nodir: true }) + const files = glob.sync(`${root}/${globPattern}`, { nodir: true }) files.forEach(filepath => { - console.log(`+++ glob filepath`, filepath) hash.update(fs.readFileSync(filepath)) }) @@ -37,7 +33,7 @@ async function createFileContentHash(root, pattern) { * will be an absolute path. * @return {PluginInfo} */ -async function resolvePlugin(pluginName) { +function resolvePlugin(pluginName) { // Only find plugins when we're not given an absolute path if (!fs.existsSync(pluginName)) { @@ -52,16 +48,16 @@ async function resolvePlugin(pluginName) { fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) ) - console.log('resolve plugin', { + console.log(`resolve plugin`, { resolve: resolvedPath, name: packageJSON.name || pluginName, - version: packageJSON.version || await createFileContentHash(resolvedPath, `**`), + version: packageJSON.version || createFileContentHash(resolvedPath, `**`), }) return { resolve: resolvedPath, name: packageJSON.name || pluginName, - version: packageJSON.version || await createFileContentHash(resolvedPath, `**`), + version: packageJSON.version || createFileContentHash(resolvedPath, `**`), } } else { @@ -165,7 +161,7 @@ module.exports = async (config = {}) => { plugins.push({ resolve: slash(process.cwd()), name: `default-site-plugin`, - version: await createFileContentHash(process.cwd(), `gatsby-*`), + version: createFileContentHash(process.cwd(), `gatsby-*`), pluginOptions: { plugins: [], }, From fab18b1a466d91eae6e566fb8c8bfb5b613f512b Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 14:42:56 +0200 Subject: [PATCH 07/13] Plugin version should be string always --- packages/gatsby/src/bootstrap/load-plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index a4e99f1b1168c..ad3279176bf87 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -22,7 +22,7 @@ function createFileContentHash(root, globPattern) { * @typedef {Object} PluginInfo * @property {string} resolve The absolute path to the plugin * @property {string} name The plugin name - * @property {string|number} version The plugin version (can be content hash) + * @property {string} version The plugin version (can be content hash) */ /** From 077ac6bd3852bb97abb0bc2e898baed8a97252b0 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 14:43:41 +0200 Subject: [PATCH 08/13] Remove debug log --- packages/gatsby/src/bootstrap/load-plugins.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index ad3279176bf87..cba5375bdd27f 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -48,12 +48,6 @@ function resolvePlugin(pluginName) { fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) ) - console.log(`resolve plugin`, { - resolve: resolvedPath, - name: packageJSON.name || pluginName, - version: packageJSON.version || createFileContentHash(resolvedPath, `**`), - }) - return { resolve: resolvedPath, name: packageJSON.name || pluginName, From 78ec8c9e67503ecc1fe3a8b4b74b5b673753761e Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 14:45:32 +0200 Subject: [PATCH 09/13] Format code --- packages/gatsby/src/bootstrap/load-plugins.js | 16 ++++++---------- .../query-runner/query-watcher.js | 5 ++++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index cba5375bdd27f..3933ab32fb546 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -34,26 +34,23 @@ function createFileContentHash(root, globPattern) { * @return {PluginInfo} */ function resolvePlugin(pluginName) { - // Only find plugins when we're not given an absolute path if (!fs.existsSync(pluginName)) { - // Find the plugin in the local plugins folder const resolvedPath = slash(path.resolve(`./plugins/${pluginName}`)) - if(fs.existsSync(resolvedPath)) { - - if(fs.existsSync(`${resolvedPath}/package.json`)) { - const packageJSON = JSON.parse( + if (fs.existsSync(resolvedPath)) { + if (fs.existsSync(`${resolvedPath}/package.json`)) { + const packageJSON = JSON.parse( fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) ) return { resolve: resolvedPath, name: packageJSON.name || pluginName, - version: packageJSON.version || createFileContentHash(resolvedPath, `**`), + 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`) @@ -66,7 +63,7 @@ function resolvePlugin(pluginName) { * which should be located in node_modules. */ try { - const resolvedPath = slash(path.dirname(require.resolve(pluginName))) + const resolvedPath = slash(path.dirname(require.resolve(pluginName))) const packageJSON = JSON.parse( fs.readFileSync(`${resolvedPath}/package.json`, `utf-8`) @@ -77,7 +74,6 @@ function resolvePlugin(pluginName) { name: packageJSON.name, version: packageJSON.version, } - } catch (err) { throw new Error(`Unable to find plugin "${pluginName}"`) } diff --git a/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js b/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js index 11d1931cb47e6..8e954650c04fd 100644 --- a/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js +++ b/packages/gatsby/src/internal-plugins/query-runner/query-watcher.js @@ -58,7 +58,10 @@ exports.watch = rootDir => { queryCompiler().then(queries => { const pages = store.getState().pageComponents queries.forEach(({ text }, path) => { - invariant(pages[path], `Path ${path} not found in the store pages: ${JSON.stringify(pages)}`) + invariant( + pages[path], + `Path ${path} not found in the store pages: ${JSON.stringify(pages)}` + ) if (text !== pages[path].query) { boundActionCreators.replacePageComponentQuery({ From 88efe54320a5a6857fb921d90087473ebf975c6e Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 21:52:27 +0200 Subject: [PATCH 10/13] Update load-plugins snapshot --- .../src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap b/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap index 6dc84981f0f33..513a39d4e796d 100644 --- a/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap +++ b/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap @@ -93,7 +93,7 @@ Array [ "plugins": Array [], }, "resolve": "", - "version": "n/a", + "version": "d41d8cd98f00b204e9800998ecf8427e", }, ] `; From 89eafc78d6625e5852e68b2438bba599f7dfe0db Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Mon, 12 Jun 2017 22:05:13 +0200 Subject: [PATCH 11/13] Update snapshot and fix test --- .../bootstrap/__tests__/__snapshots__/load-plugins.js.snap | 3 +-- packages/gatsby/src/bootstrap/load-plugins.js | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap b/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap index 513a39d4e796d..02220cf214c21 100644 --- a/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap +++ b/packages/gatsby/src/bootstrap/__tests__/__snapshots__/load-plugins.js.snap @@ -40,7 +40,6 @@ Array [ "plugins": Array [], }, "resolve": "", - "version": undefined, }, Object { "name": "default-site-plugin", @@ -48,7 +47,7 @@ Array [ "plugins": Array [], }, "resolve": "", - "version": "n/a", + "version": "d41d8cd98f00b204e9800998ecf8427e", }, ] `; diff --git a/packages/gatsby/src/bootstrap/load-plugins.js b/packages/gatsby/src/bootstrap/load-plugins.js index 3933ab32fb546..80453659ae4ef 100644 --- a/packages/gatsby/src/bootstrap/load-plugins.js +++ b/packages/gatsby/src/bootstrap/load-plugins.js @@ -110,7 +110,12 @@ module.exports = async (config = {}) => { // Add some default values for tests as we don't actually // want to try to load anything during tests. if (plugin.resolve === `___TEST___`) { - return { name: `TEST` } + return { + name: `TEST`, + pluginOptions: { + plugins: [], + }, + } } const info = resolvePlugin(plugin.resolve) From 0f1cd4134d53f079df4b56739605fca1147bfb27 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Tue, 13 Jun 2017 10:06:07 +0200 Subject: [PATCH 12/13] Add some documentation about local plugins --- docs/docs/plugins.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/docs/plugins.md b/docs/docs/plugins.md index 8d409b3444f66..2c1694908970e 100644 --- a/docs/docs/plugins.md +++ b/docs/docs/plugins.md @@ -39,6 +39,38 @@ module.exports = { Plugins can take options. See each plugin page below for more detailed documentation on using each plugin. +## Locally defined plugins + +When you want to work on a new plugin, or maybe write one that is only relevant +to your specific use-case, a locally defined plugin is more convinient than +having to create an NPM package for it. + +You can place the code in the `plugins` folder in the root of your project like +this: + +``` +plugins +└── my-own-plugin + ├── gatsby-node.js + └── package.json +``` + +Each plugin requires a package.json file, but the minimum content is just an +empty object `{}`. The `name` and `version` fields are read from the package file. +The name is used to identify the plugin when it mutates the GraphQL data structure. +The version is used to clear the cache when it changes. + +For local plugins it is best to leave the version field empty. Gatsby will +generate an md5-hash from all gatsby-* file contents and use that as the version. +This way the cache is automatically flushed when you change the code of your +plugin. + +If the name is empty it is inferred from the plugin folder name. + +Like all gatsby-* files, the code is not being processed by Babel. If you +want to use javascript syntax which isn't supported by your version of Node.js, +you can place the files in a `src` subfolder and build them to the plugin folder root. + ## Official plugins * [gatsby-plugin-catch-links](/docs/packages/gatsby-plugin-catch-links/) From 9b822cb3fd652ba9fd6a27b13ccfad39fad46095 Mon Sep 17 00:00:00 2001 From: Thijs Koerselman Date: Tue, 13 Jun 2017 10:10:28 +0200 Subject: [PATCH 13/13] Fix some spelling --- docs/docs/plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/plugins.md b/docs/docs/plugins.md index 2c1694908970e..8d6a606024a02 100644 --- a/docs/docs/plugins.md +++ b/docs/docs/plugins.md @@ -42,7 +42,7 @@ on using each plugin. ## Locally defined plugins When you want to work on a new plugin, or maybe write one that is only relevant -to your specific use-case, a locally defined plugin is more convinient than +to your specific use-case, a locally defined plugin is more convenient than having to create an NPM package for it. You can place the code in the `plugins` folder in the root of your project like