-
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
[gatsby-plugin-feed] Allow additional feed options #3413
[gatsby-plugin-feed] Allow additional feed options #3413
Conversation
Updates `gatsby-plugin-feed` to accept additional options on a per-plugin or per-feed basis. Available options are documented in [node-rss][1]. Any options specified in `feedOptions` are overriden by matching keys returned by a feed's `query`, if provided. [1]: https://github.com/dylang/node-rss#feedoptions
Deploy preview ready! Built with commit 257dae4 |
Thanks for jumping on this! I would rather use GraphQL data to populate options for the RSS module. Since we can query for all site options, what about a standardized GraphQL query instead of passing a separate For instance, what if {
site {
siteMetadata {
title
description
siteUrl
site_url: siteUrl
}
}
entries: {
// edge and node fields
}
} That represents the simplest configuration possible, and we could easily derive everything from that single option. The output would be Additionally, you could override that query exactly to gain additional options. Like so: {
resolve: 'gatsby-plugin-feed',
options: {
feeds: [
output: '/test.xml',
query: ``
]
}
} I think we can get a lot of what we want by simply standardizing the query, then making sure the context passed into the Does this make sense? If so, what do you think? Aliasing our |
@nicholaswyoung for sure, that makes sense! I was wondering if that was the direction you were heading. In the case of something like the {
site {
siteMetadata {
title
description
siteUrl
site_url: siteUrl
generator
}
}
someOtherQuery {
generator
}
} If that's the case I'll just amend this PR to include better instructions on how to pass those extra options, because I believe this should already work. |
@mikefowler The I've been thinking much about how to make configuration incredibly simple. I could see users wanting to override on a per-feed basis (for instance, in the case of a podcast or different media type), so maybe we allow them to override like so? feeds: [
{
query: `{
site {
siteMetadata {
// pull in fields you need to configure or remap for this rss feed
}
}
entries: allMarkdownRemark() {} // for example, the only thing that matters is the key, "entries"
}`,
}
] Then, when merged with the top-level query, any duplicated fields are overridden by local results. And honestly, I'm leaning towards dropping the |
I'll amend this PR with a better commit message before merging.
@nicholaswyoung: I took the ideas you outlined in https://github.com/uptimeventures/gatsby/commit/50368c3d76025619f277fbc37da7452a48044573 and jammed on them for a while tonight. The most recent commit on this branch has the plugin in a working state for generating multiple feeds using queries alone. The default config is No Config™, and adding a second (third, fourth, etc) feed looks something like this: module.exports = {
siteMetadata: {
title: 'My Website',
fireAntsTitle: 'Fire Ants!',
},
plugins: [
// ...
{
resolve: 'gatsby-plugin-feed',
options: {
feeds: [{
// This will use the default entries & metadata
output: 'rss.xml',
}, {
output: 'fireants.xml',
query: `
{
site {
siteMetadata {
title: fireAntsTitle
}
}
entries: allMarkdownRemark() {
# Etc, etc.
}
}
`,
}],
},
},
// ...
],
}; |
@mikefowler That's exactly the direction I was thinking of going. What do you think? Does it accomplish the goal of feeling natural when overriding global config with local options? Looking over that branch, it really does feel right. I just need to flesh out the logic for automatic configuration, since it'd be nice to have The feed plugin has become a popular addition to most Gatsby sites, but I didn't do the best job designing the options API in our first release. This PR is very close to what I envisioned. |
@@ -0,0 +1,16 @@ | |||
export default function serialize({ |
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'm inclined to think that even though the query format is standardized, we should still include a way for users to customize feed options via a callback.
...defaultOptions, | ||
...pluginOptions, | ||
} | ||
|
||
const links = feeds.map(({ output }, i) => { | ||
const links = options.feeds.map(({ output }, i) => { |
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.
Just curious: is this a style change only, or was the other implementation harming performance?
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.
Ah, just stylistic. I'm going to revert these changes because they're just adding noise to the diff.
} | ||
|
||
// @TODO: is this useful? We should think of an example that would use this. | ||
const context = defaultsDeep(options, rest) |
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.
The original intent of context
was to provide a shared object, passed to functions that created feed options or serialized nodes to entries. This allowed every parameter the option of being dynamic: either retrieved from the query data or specified options.
I think the idea is sound, though the prior implementation certainly wasn't. See the comment below on serialize
. I think we need to retain some of the ideas from context
, by allowing users to pass in their own setup
and serialize
functions in addition to our smart defaults.
@@ -23,7 +23,9 @@ | |||
}, | |||
"dependencies": { | |||
"babel-runtime": "^6.26.0", | |||
"lodash.merge": "^4.6.0", | |||
"deepmerge": "^2.0.1", | |||
"lodash.defaultsdeep": "^4.6.0", |
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 think we can get away with not including lodash. I know there's a gatsby plugin that integrates the babel plugin, but as a general rule, I'm trying to stay away from pulling in extras that I don't need. deepmerge
is probably the most important, since most other config is dealt with through object rest spread.
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.
@KyleAMathews Do you have an official policy regarding lodash in gatsby plugins? Object rest spread seems to do most of what is needed here, and deepmerge
fills in the gaps. But if it'd be better to rely on lodash if it's included in several plugins (and perhaps creating a smaller build), I could see the case for using 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.
@nicholaswyoung Most recent commit drops both of the lodash packages. I replaced defaultsDeep
with deepmerge
and reversed the argument order, which I think achieves the same result.
} | ||
|
||
export default function createFeed({ | ||
query: { |
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 questioned if there's a reason why query data shouldn't just be merged in with other parameters. Does it need to live under the key query
when most of the data is being derived from that object? I don't care either way, It's just another potential simplification I thought of.
Thanks for the feedback, @nicholaswyoung! I've been trying to work backwards from my ideal metadata configuration for managing multiple feeds, and I think my ideal is something like the following, but I'm having a hard time figuring out how that would square with the direction we're heading. {
siteMetadata: {
title: 'Website',
audioFeed: {
title: 'Audio',
// Any additional options get passed to node-rss
},
journalFeed: {
title: 'Journal',
},
}
} It may be the engineer in me that doesn't like the idea of storing related feed options, for separate feeds, as sibling keys in the same object, like this: {
siteMetadata: {
title: 'Website',
audioFeedTitle: 'Audio',
journalFeedTitle: 'Journal',
}
} This doesn't seem so bad at the outset, but with 5-10 options for each feed (in an advanced configuration, say), I would much prefer the first example. Thoughts? |
850d3e5
to
f987baf
Compare
f987baf
to
859a104
Compare
@mikefowler To address that scenario, I currently return a I'm open to changing anything that makes configuration easier to reason about. This is one of the hard spots everyone has gone through with this plugin. |
@nicholaswyoung pushed one more commit adding the |
@mikefowler That's exactly what I think is right. Even though it's a breaking change, there's really no reason to keep |
Would this allow for multiple rss feeds on one site? And would it allow you to customize it to work for a podcast feed? I'm trying to figure out how to do this right now: orbitfm/orbit.fm#6 |
@agarrharr It currently supports multiple feeds per site. Take a look at the configuration options I linked above. If you need help beyond that, I'll gladly answer specific questions. I run multiple feeds on my site, so I know this is easily within reach. :) |
@nicholaswyoung I'll have some time this weekend to work on the media integration, but if you have any work-in-progress, or want to take a stab at it yourself, feel free to push commits to this branch! Alternatively: I could temporarily revert to the previous implementations of |
@mikefowler I've been sick and/or out most of the week thus far, so I haven't had a chance to dig in. I'm going to pull this branch and take a look tomorrow when my head is clearer, but I have a hunch we can easily wrap it up. (Side note, sorry that the links to my repo above are now dead.) I saw another config change that was suggested by @agarrharr in #3489, but I think there has to be a cleaner API for generating dynamic feeds. I'm hesitant to make every configuration option an optional I'm using the plugin to generate podcast feeds, too, but the implementation is incredibly hacky. The number one question I get is concerning how to configure the plugin, so that's obviously the most pressing issue. If I can clean up the implementations of everybody's RSS generation workflow all at once, rather than landing a bunch of potentially bothersome changes... that's my goal. |
Thanks @nicholaswyoung. I'm very interested in figuring out a cleaner API for generating dynamic feeds. |
@mikefowler any chance you could finish this up soon? Lot of great fixes here! :-) |
@KyleAMathews, yea, it's still on my radar! My Gatsby contributions seem to be coming at the speed that I'm able to work on converting my website over from Jekyll :P I think this is quite close to being ready to ship. For sake of fixing the original confusion that this work stemmed from, we can add the new functionality (media/podcast feeds, for instance) in a separate changeset. |
I've been trying to find time to wrap this up, too. I've just been pulled in too many directions. After repeatedly considering what should be the heuristic for determining media entries from regular entries, I keep coming back to some version of the configuration we currently have. I don't know if a zero (or lightweight) configuration option is sensible after all. |
It's tough because you can make a feed from any data. |
It is tough. This is what I ended up changing in this plugin to make it work for me: orbitfm/orbit.fm@4bdfb2c#diff-5c11e5724db58b8e0e82c5472c465be4R41-64 But then my config for this plugin is huge! https://github.com/agarrharr/orbit.fm/blob/master/gatsby-config.js#L5-L239 |
@mikefowler It'd be great to get this merged if you have the chance to update it? In order to clean up the PR list I'll close hanging PRs like this over the next few days. But it's always better to merge a PR, so drop a comment here if you'd like to keep this open :) Or feel free to re-open this later. |
Closing as this seems inactive. Please open a new PR if you'd like to pick this up again. |
Overview
Refactors
gatsby-plugin-feed
so that thequery
option handles the bulk of configuration.Basic configuration
Scenario
I want an RSS feed that includes all of my Markdown files, and I don't need any custom configuration.
Configuration
gatsby-plugin-feed
must be listed ingatsby-config
, and allMarkdownRemark
nodes must have aslug
field assigned to them.Result
A feed is generated at
/rss.xml
. It includes all edges inallMarkdownRemark
, sorted by frontmatter date, in descending order.Custom feed options
Feeds may specify their own
query
option, the result of which will be deeply merged with the default query. As such, custom queries need not replicate the entire query, but can override specific keys as desired.Scenario
The default set of nodes included in the feed work fine for me, but I need to customize some feed options.
Configuration
The same configuration as described under [Basic Configuration][#basic-configuration), but with a custom query.
Multiple feeds
Scenario
The default feed doesn't work for me. I need more than one, and each will include different nodes.
Configuration
Addresses #1808
Reviewers
to: @nicholaswyoung
cc: @roundedbygravity