-
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
feat(gatsby): plugin option validation #27242
Conversation
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.
Liking the structured errors!
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.
Are we able to add a definition for GatsbyNode["pluginOptionsSchema"]
to gatsby/index.d.ts? I'm assuming we'll need to add our own type for Joi ones we extend it? Do you have any idea how that works in general?
Looking good! |
47db081
to
3b96006
Compare
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.
Some small nits and questions
dotenv: { | ||
args: [`name`], | ||
validate(value, helpers, args): void { | ||
if (!args.name) { | ||
return helpers.error( | ||
`any.dotenv requires the environment variable name` | ||
) | ||
} | ||
return value | ||
}, | ||
method(name): Schema { | ||
return this.$_addRule({ name: `dotenv`, args: { name } }) | ||
}, | ||
}, |
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.
I might have forgotten but I'm still not sure why we want this one.
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 let's plugin authors mark that a value entered during (a potential) gatsby plugin add
command should be stored in the .env
file instead of being written to the gatsby-config.js directly. E.g.:
// gatsby-plugin-source-contentful/gatsby-node.js
export const pluginOptionsSchema = ({ Joi }) => Joi.object({
accessToken: Joi.string().required().dotenv("CONTENTFUL_ACCESS_TOKEN")
})
Then, when we prompt the user to enter their access token we will 1) mask the input in the CLI and 2) write the value to the .env file and process.env.CONTENTFUL_ACCESS_TOKEN
to the gatsby-config.js 👍
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.
It's still something I'm not 100% convinced about. The feature sounds really cool, but I fear that env vars can be similar and bring conflicts.
Can we strip it out until we have the need for it/more discussions?
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.
Isn't this the main way we can ensure core -> cloud compatibility? @wardpeet can you explain more about what conflicts you anticipate?
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.
I might not 100% understand it so let's say that I have plugin A that has dotenv('HOST')
and a plugin B dotenv('HOST')
how would this play out? Also what if for some reason I rather have CONTENTFUL_DELIVERY_TOKEN instead of CONTENTFUL_ACCESS_TOKEN?
What do you mean with core <-> cloud compatibility?
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.
So this isn't for the user to understand, but rather the plugin author. We could solve the duplicate problem by concatenating the plugin name and the option name. So GATSBY_PLUGIN_CONTENTFUL_HOST
.
The core <-> compatibility is the idea that you'll always be in a valid state and you'd be ready to set up with cloud since it leverages process.env to hook into CMS keys and the like.
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.
That's why I want to hold off on adding this feature cause it needs more thinking.
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.
I have disabled (i.e. commented out) this extension for now until we decide on a fixed API for it to unblock this PR 👍
@mxstbr Will it also be possible to validate that we don't pass any options anymore? |
This'll happen automatically! When you publish a new version with a changed options schema the user will get an error after upgrading telling them that they are using options that don't exist 👍 |
I like the idea! .. but it brought some troubles to me. I'm using The comment says
|
Great catch @openscript, it should definitely be optional! Would you mind opening a new PR with that change? 🙏 |
exports.onPreInit = ({ reporter }, options) => { | ||
if (!options.trackingId) { | ||
reporter.warn( | ||
`The Google Analytics plugin requires a tracking ID. Did you mean to add it?` | ||
) | ||
} | ||
} |
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.
@mxstbr Shouldn't we have kept onPreInit
in case GATSBY_EXPERIMENTAL_PLUGIN_OPTION_VALIDATION
wasn't true
? 🤔
If people update gatsby-plugin-google-analytics
but don't update gatsby
, they won't get any warning anymore.
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.
True, good catch! PR welcome 👍
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.
On it boss! 😉
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.
Here you go: #27495 🙂
Hey team, working on a Gatsby plugins course and I wanted to feature this plugin options schema support but it appears that it isn't working for a local plugin. 🤔 I still have to dig into this PR/the code and see if I can confirm that's the issue. If so I'll open a new ticket and try and contribute a fix since I'd love to showcase this (non-local plugins are introduced later in the course and the local plugin in my demo is a good use case for options schema). |
That'd be sweet! |
Yes, looks like it does fail with a small test case so I will open an issue. it(`validates local plugin schemas`, async () => {
await loadPlugins({
plugins: [
{
resolve: require.resolve('./__fixtures__/local-plugin'),
options: {
optionalString: 1234
},
},
],
})
expect(reporter.error as jest.Mock).toHaveBeenCalledTimes(1)
expect(mockProcessExit).toHaveBeenCalledWith(1)
}) |
For whoever would like to review, I have a proposed fix: #29787 |
* Make pluginOptionsSchema optional @context: gatsbyjs#27242 * Exclude undefined pluginOptionsSchema * Exclude undefined pluginOptionsSchema from plugin validation
This implements plugin option validation if a plugin has a
gatsbyNode.pluginOptionsSchema
defined. (see #27166 for the RFC for thepluginOptionsSchema
API)I think we should disable this by default until we have documentation for it, added some more schemas to core plugins and (maybe) have tested it with a few alpha/beta testers! So, this PR adds a feature flag in the form of the
GATSBY_EXPERIMENTAL_PLUGIN_OPTION_VALIDATION
environment variable.I added the Google Analytics option schema for testing. Here is an example of what a configuration error looks like in the terminal with these incorrect options:
[ch15946]