diff --git a/benchmarks/source-datocms/gatsby-config.js b/benchmarks/source-datocms/gatsby-config.js index dc5204cb87095..bb7c6fb9ca678 100644 --- a/benchmarks/source-datocms/gatsby-config.js +++ b/benchmarks/source-datocms/gatsby-config.js @@ -17,13 +17,13 @@ module.exports = { path: `${__dirname}/src/pages/`, }, }, - { + { resolve: `gatsby-source-datocms`, options: { apiToken: process.env.DATOCMS_API_TOKEN, previewMode: false, disableLiveReload: false, - apiUrl: 'https://site-api.datocms.com', + apiUrl: `https://site-api.datocms.com`, }, }, ], diff --git a/benchmarks/source-datocms/gatsby-node.js b/benchmarks/source-datocms/gatsby-node.js index e4ce6ac7d886e..75f590e92c7a0 100644 --- a/benchmarks/source-datocms/gatsby-node.js +++ b/benchmarks/source-datocms/gatsby-node.js @@ -3,8 +3,8 @@ const kebabCase = require(`lodash.kebabcase`) exports.onCreateNode = ({ actions, node }) => { const { createNodeField } = actions - if (node.internal.type === 'node__article') { - createNodeField({ node, name: "slug", value: kebabCase(node.title) }) + if (node.internal.type === `node__article`) { + createNodeField({ node, name: `slug`, value: kebabCase(node.title) }) } } @@ -16,7 +16,7 @@ exports.createPages = async ({ actions, graphql, reporter }) => { articles: allDatoCmsArticle { nodes { id - path + slug } } } @@ -28,11 +28,11 @@ exports.createPages = async ({ actions, graphql, reporter }) => { result.data.articles.nodes.map(article => { createPage({ - path: article.path, + path: article.slug, component: require.resolve(`./src/templates/article.js`), context: { id: article.id, - } + }, }) }) } diff --git a/benchmarks/source-datocms/src/pages/index.js b/benchmarks/source-datocms/src/pages/index.js index 8ebf326b65ca4..3af11ea1d1c93 100644 --- a/benchmarks/source-datocms/src/pages/index.js +++ b/benchmarks/source-datocms/src/pages/index.js @@ -9,7 +9,7 @@ const Index = ({ data }) => { @@ -29,7 +29,7 @@ export const query = graphql` articles: allDatoCmsArticle { nodes { title - path + slug } } } diff --git a/docs/blog/2020-03-26-service-relief-project/index.md b/docs/blog/2020-03-26-service-relief-project/index.md index b4c7d08ca9f79..fdabc87dc8794 100644 --- a/docs/blog/2020-03-26-service-relief-project/index.md +++ b/docs/blog/2020-03-26-service-relief-project/index.md @@ -16,9 +16,9 @@ We woke up and the world was utterly changed. It's easy to be overwhelmed. I sat State-mandated social distancing shutdowns are being rolled out across the country, closing down bars, entertainment venues, and restaurants - taking the livelihoods of countless service workers with them. "Shelter in place" orders also prevent independent workers like pet sitters and house cleaners from being able to do their jobs. And as independent small businesses classified as "nonessential," like bookstores and art galleries, are forced to close they also find themselves in the same increasingly dire situation. -Wonderfully, though, fundraisers are popping up all over the place to provide some emergency relief. Through them I saw a way to help out':' creating a fast, free and above all easy way for communities to gather local relief fundraisers in a single website, where donors can easily find and contribute. It turns out I wasn't the only one with this idea! +Wonderfully, though, fundraisers are popping up all over the place to provide some emergency relief. Through them I saw a way to help out: creating a fast, free and above all easy way for communities to gather local relief fundraisers in a single website, where donors can easily find and contribute. It turns out I wasn't the only one with this idea! -**In this post: ** +**In this post:** - [About the project](#about) - [How it all began](#beginnings) @@ -32,7 +32,7 @@ The Service Relief Project is a boilerplate for launching blazing-fast zero-cost Here's what it does: -- Generates a static website using [GatsbyJS](https://gatsbyjs.org) +- Generates a static website using [Gatsby](https://gatsbyjs.org) - Uses [Airtable](https://airtable.com) to manage your listings and categories - Includes an Airtable form to collect local submissions and add them to Airtable for approval - Can be personalized to a city or region without touching a line of code @@ -42,7 +42,7 @@ Using Gatsby to build and generate a static website based on data from a remote In order to provide the ability to launch a zero-cost directory of fundraisers for your local area, we've: -- Open-sourced the [entire project on Github](https://github.com/service-relief) +- Open-sourced the [entire project on GitHub](https://github.com/service-relief) - Written [detailed instructions on how to get started](https://www.servicerelief.us/start/) - Released a [Gatsby Starter](https://github.com/service-relief/gatsby-starter-service-relief) and a [Gatsby Theme](https://github.com/service-relief/service-relief/tree/master/themes/gatsby-theme-service-relief) - Released a [one-click deployment to Netlify](https://app.netlify.com/start/deploy?repository=https://github.com/service-relief/gatsby-starter-service-relief) @@ -53,7 +53,7 @@ _This project was inspired by [Chicago Service Relief](https://chicagoservicerel Here are a few of the sites that have already launched using this project: -- [Seattle Service Relief](http://seattleservicerelief.com/) +- [Seattle Service Relief](https://seattleservicerelief.com/) - [Denver Service Relief](https://denverservicerelief.com/) - [Austin Service Relief](https://austinservicerelief.com/) - [Sioux Falls Service Relief](https://siouxfallsservicerelief.com/) @@ -69,7 +69,7 @@ These are unprecedented times, and from my small home office in Omaha, Nebraska Drew and I have worked together in the past and I've both built and managed several websites for him over the years. All of them have been powered by [WordPress](https://wordpress.org), but I knew that spinning up another WordPress website was going to be overkill for something this simple. -That's where Gatsby came in. For the Seattle Service Relief site, I generated a new site using LekoArts' [Gatsby Minimal Blog](https://www.gatsbyjs.org/starters/LekoArts/gatsby-starter-minimal-blog/) by running `gatsby new` and customizing a quick site. I had used the same starter on my personal site which helped speed up the process. A few hours later I messaged him back with a link to the live site. +That's where Gatsby came in. For the Seattle Service Relief site, I generated a new site using LekoArts' [Gatsby Minimal Blog](/starters/LekoArts/gatsby-starter-minimal-blog/) by running `gatsby new` and customizing a quick site. I had used the same starter on my personal site which helped speed up the process. A few hours later I messaged him back with a link to the live site. ![Text message conversation with Drew where I announced that seattleservicerelief.com was live](./images/conversation-drew-finished-site.png) @@ -106,7 +106,7 @@ _A special thank-you to [Dustin Schau](https://twitter.com/SchauDustin), [Aisha Over the next hour and a half, we developed a prototype using the following tool stack: -- Github, for hosting the code of the site +- GitHub, for hosting the code of the site - Airtable, for managing data - Gatsby, to generate the site based on Airtable data - Netlify, for building and deploying the site @@ -138,9 +138,9 @@ I'll also be publishing my personal workflow for building and deploying your Ser Getting the word out to your network is the best way to raise awareness of this project. We'll be listing all published Service Relief websites on [https://www.servicerelief.us/](https://www.servicerelief.us/). -##### 3. Contribute to the project on Github +##### 3. Contribute to the project on GitHub -We've published this entire [project on Github](https://github.com/service-relief) to open it up for the world to contribute back. Here's what you'll see there: +We've published this entire [project on GitHub](https://github.com/service-relief) to open it up for the world to contribute back. Here's what you'll see there: - `service-relief` - this is the monorepo for the entire project, including the ServiceRelief.us website, Gatsby Theme, and Gatsby Starter. You'll want to fork and submit your pull requests against this repository. - `gatsby-starter-service-relief` - this is an automatically-generated Gatsby Starter based on the monorepo. When the monorepo is updated, this starter is automatically updated. diff --git a/docs/blog/2020-04-01-LA-2020-Mathews/index.md b/docs/blog/2020-04-01-LA-2020-Mathews/index.md new file mode 100644 index 0000000000000..0fb9e392be058 --- /dev/null +++ b/docs/blog/2020-04-01-LA-2020-Mathews/index.md @@ -0,0 +1,20 @@ +--- +title: "Gatsby Days LA 2020 Video 1: GatsbyJS CEO and Co-founder Kyle Mathews Shares His Vision for Gatsby’s Future" +date: 2020-04-01 +author: Greg Thomas +excerpt: "How did Gatsby get started and where is it headed? Learn more about the past, present, and future of Gatsby in founder Kyle Mathews' keynote presentation from Gatsby Days LA 2020" +tags: + - gatsby-days + - themes + - plugins + - documentation + - community +--- + +_Welcome to the Gatsby Days 2020 Video Blog: Los Angeles Edition. In this series of eleven videos, you can catch up with all the wit and wisdom shared at the presentations from our February community gathering in LA. If you weren’t able to make it in person, these videos are the next best thing to owning a time machine! (Though owning a time machine would be super cool, joining us at our next Gatsby Days—currently scheduled for October 19th in Amsterdam—would also be pretty awesome)._ + +As the co-founder and CEO of Gatsby, Kyle Mathews kicked off Gatsby Days LA 2020 with a keynote address that spanned Gatsby’s past, present, and future. Learn what sparked Kyle and co-founder Sam Bhagwat to develop a framework that could combine the best of static-site generation, content management system (CMS), and React technologies. Next, hear how Gatsby today is helping produce amazing developer experiences for building ridiculously fast websites. + +Kyle also shared his vision for the future of Gatsby, highlighting some of the “missing pieces” that are current focus areas for the company. For example, to help speed development, Gatsby is looking to significantly expand the collection of Gatsby themes, which provide building blocks for quickly adding functionality to websites. With help from a fast-growing community, Gatsby anticipates increasing contributions of themes, plugins, docs, and more. + +[![Gatsby Days Los Angeles: Kickoff/Keynote video](https://res.cloudinary.com/marcomontalbano/image/upload/v1585686057/video_to_markdown/images/youtube--9Ta7L4rN3x4-c05b58ac6eb4c4700831b2b3070cd403.jpg)](http://www.youtube.com/watch?v=9Ta7L4rN3x4 "Gatsby Days Los Angeles - Kickoff/Keynote video and future of Gatsby") diff --git a/docs/blog/2020-04-02-LA-2020-Schau/index.md b/docs/blog/2020-04-02-LA-2020-Schau/index.md new file mode 100644 index 0000000000000..ee7132188c16b --- /dev/null +++ b/docs/blog/2020-04-02-LA-2020-Schau/index.md @@ -0,0 +1,21 @@ +--- +title: "Gatsby Days LA 2020 Video 2: Live demo of Gatsby + Contentful developer workflow" +date: 2020-04-02 +author: Greg Thomas +excerpt: "Watch in real time as Dustin Schau, Gatsby's head of product, updates a fully accessible Gatsby-built site using the Contentful headless CMS and then deploys to a CDN." +tags: + - gatsby-days + - contentful + - accessibility + - cdn + - diversity-and-inclusion + - gatsby-cloud +--- + +_Welcome to the Gatsby Days 2020 Video Blog: Los Angeles Edition. In this series of eleven videos, you can catch up with all the presentations from our February community gathering in LA. If you weren’t able to make it in person, these videos are the next best thing to owning a time machine! (Though owning a time machine would be super cool, joining us at our next Gatsby Days—currently scheduled for October 19th in Amsterdam—would also be pretty awesome)._ + +Dustin Shau, Gatsby's Head of Product, is a dedicated open source developer. He was first drawn to the framework by Gatsby’s exceptional performance and outstanding developer experience. Now a Gatsby team member, Dustin is focused on making Gatsby the fastest, most inclusive platform for building websites and web applications. + +Watch Dustin demonstrate the impressive build-time performance of Gatsby and Gatsby Cloud by walking through typical developer workflows, including updating a website using Contentful's headless CMS and then rapidly deploying the results through a content delivery network (CDN). And discover how Gatsby enables developers to quickly incorporate accessibility capabilities—such as a SkipNav function—to deliver inclusive web experiences to the widest possible audience. + +[![Gatsby Days LA Video 2: What's next for Gatsby and Gatsby Cloud](https://res.cloudinary.com/marcomontalbano/image/upload/v1585776287/video_to_markdown/images/youtube--zbR47FqMJYY-c05b58ac6eb4c4700831b2b3070cd403.jpg)](https://www.youtube.com/watch?v=zbR47FqMJYY "Gatsby Days LA Video 2: What's next for Gatsby and Gatsby Cloud") diff --git a/docs/blog/2020-04-02-community-qa-with-kyle-mathews/index.md b/docs/blog/2020-04-02-community-qa-with-kyle-mathews/index.md new file mode 100644 index 0000000000000..5e44713807522 --- /dev/null +++ b/docs/blog/2020-04-02-community-qa-with-kyle-mathews/index.md @@ -0,0 +1,124 @@ +--- +title: "March 6th Community Q&A with Kyle Mathews" +date: 2020-04-02 +author: "Kyle Mathews" +tags: ["gatsby-inc"] +--- + +We’ve started hosting regular Gatsby community Q&A chats with yours truly! The last one was on March 6th and the next one is scheduled for early May. They’re great fun to chat with the folks about things that are on their mind and talk about ongoing/upcoming work. + +The [full video is on YouTube](https://www.youtube.com/watch?v=mGyUJvKjzXQ&feature=youtu.be) & I’ve written up many of the questions & my answers below. + +## In 2018 you blogged about "a new version of Gatsby" with incremental and parallelizing builds—what's the status & roadmap for incremental builds with Gatsby? + +I’m guessing this question is referring to [my blog post on the launch of our company in 2018](https://www.gatsbyjs.org/blog/2018-05-24-launching-new-gatsby-company/) and that supporting very fast deployments for everyone is our top goal as a company. + +This has always been my goal with Gatsby. The Gatsby v1 architecture was designed specifically to support this. Here’s the original tweet announcing when the basic support for incremental builds was added to the framework in a 1.0 alpha: + +https://twitter.com/kylemathews/status/856638851158220800 + +Gatsby has always used “incremental building” to drive developing on sites. When you edit a markdown file, Gatsby “incrementally” updates just the pages affected by that change to the markdown file. + +The Gatsby cache, if saved between builds, also substantially increases the speed of builds by avoiding much of the rework. + +As most of you know, [we recently launched our own continuous deployment product on Gatsby Cloud](https://www.gatsbyjs.org/blog/2020-01-27-announcing-gatsby-builds-and-reports/). Included in that was initial support for parallelizing parts of the build process — images to start with, and more to come. + +That drove some impressive improvements to build speeds: + +- [Third and Grove](https://www.thirdandgrove.com/) saw 60x build-time reductions from 60 minutes to 1 minute for their large 15,000 page, image-heavy Gatsby/Drupal site. +- [Gatsbyjs.org](https://gatsbyjs.org/) saw 9x reduced build times from 45 minutes to 5 minutes. +- Our [image processing benchmark site](https://github.com/KyleAMathews/gatsby-image-processing-test) saw 5x reduced build times from 200 seconds to 40 seconds. + +**We’re working on a dramatically improved way to cache between builds (making builds even more “incremental”) that’ll make all site builds a lot lot faster.** We’ll be making more noise about this soon as we ready it for launch. + +We want to make consistent < 10 second deploys a reality for everyone and any type of site & we’re very focused on making that happen. + +## What is the roadmap on SSR support for Gatsby? + +SSR (server side rendering) support is really critical for React websites. By default, React only runs in the client so it doesn't support bots from Google and social media sites, which hurts SEO and social sharing. + +There are two flavors of SSR — build-time & run-time — both solve the problem of SEO/social sharing. + +Gatsby has had build-time SSR support from the our first release in 2015. So Gatsby has always been a great choice for React apps that need SSR support. + +Some people ask us to support runtime SSR as well. We often discuss doing that but have always to date decided to instead redouble our efforts to improve build-time SSR as frankly, it’s a lot better for everything. + +Build-time SSR is incredibly less complex than runtime SSR. Operating build-time SSR sites is trouble free — you just build the site & push it to a CDN and don’t need to think about it anymore. Run-time SSR means you need running Node.js web servers to render the site...which means you have a lot of running code that can break, get overloaded, get memory leaks, and break in any number of other ways. + +People tell us one of the main things they love about Gatsby is they sleep a lot better at night. + +They don’t get alerted about website problems. + +The only problem with build-time SSR right now is when builds are either not fast enough or can’t scale to the size of your site. + +We’re razor focused right now on solving these two problems (see the last answer). We’re working so that you can build any size of site (millions of pages+) with Gatsby & deploy incremental changes in under 10 seconds. + +There are still two remaining valid reasons for run-time SSR that we plan to support. One is personalization where the page needs to be customized for the visitor based on a variety of factors. The other is A/B testing. Both of those require that you can render custom versions of pages on the fly. We will not only support this but also solve it in a way that doesn’t sacrifice the speed and simplicity Gatsby is known for. + +## What's a realistic availability timeline for incremental builds using Wordpress with WPGraphQL? + +A bit of back history for everyone: last year we hired [Jason Bahl](https://twitter.com/jasonbahl), the creator of [WPGraphQL](https://www.wpgraphql.com/), to continue his work. We want to fully support WordPress + Gatsby, meaning content authors can see real-time previews and content changes deploy in less than 10 seconds. This is the great experience that CMSs provide for content authors. Replicating it is a hard requirement for most people considering moving to a headless WordPress + Gatsby stack. + +We choose WPGraphQL as the way forward as Jason’s done an amazing job making incremental querying incredibly fast—as well as adding GraphQL subscription support, which will drive both preview & incremental builds. + +Last fall [Tyler Barnes](https://github.com/TylerBarnes) — a long-time Gatsby/WP developer — joined the team to work on a new version of gatsby-source-wordpress that leverages WPGraphQL to drive preview/10 second deploys. + +They’ve been making incredible progress. Check out [the umbrella issue for the epic](https://github.com/gatsbyjs/gatsby/issues/19292). A number of people are experimenting with the alphas and even shipping sites! If you’re interested in this space, please dive in. + +What’s amazing about this work is that **you’ll soon be able to seamlessly swap out the WordPress presentation layer for Gatsby **without** anyone working in the WordPress CMS noticing**. As a developer, you’ll be able to deliver way faster sites, enjoy far simpler hosting, put WordPress behind a firewall (maybe even skip some of those security updates! 😅🤪), and enjoy all the advantages of working in the world of modern React/JS tooling. + +## Working with images is a pain, and the distinction between page and static query seems a wrong API. The [issue #10482](https://github.com/gatsbyjs/gatsby/issues/10482) seems to fix both. What's the plan? + +We’ve worked on a number of ideas/prototypes for solving this but haven’t yet arrived at something we feel is a genuine improvement. There are more ideas floating around for better APIs, so stay tuned. We’d love to pair with anyone who has ideas for improving things as well. + +## Is there going to be a WP integration with Gatsby Cloud? + +Yup! Once the new gatsby-source-wordpress version is ready, Preview & Incremental builds will work out-of-the-box on Gatsby Cloud. + +## Are there going to be any big Gatsby core releases coming up? + +We ship releases multiple times a week. Most are incremental improvements and bug releases. We periodically write blog posts summarizing improvements. You can catch up with them at [https://www.gatsbyjs.org/blog/tags/gazette/](https://www.gatsbyjs.org/blog/tags/gazette/) + +We put up a couple of RFCs recently for “[Recipes](https://github.com/gatsbyjs/gatsby/pull/22610)” and a “[Gatsby Admin](https://github.com/gatsbyjs/gatsby/pull/22713)” experience you can go read. They’re going to push the Gatsby experience forward a lot. + +Lots more that we’ll be talking about soon. + +## Any plans for gatsby-source-drupal to support some kind of caching when retrieving thousands of nodes from Drupal? + +Yup! We hired recently [Shane Thomas](https://www.drupal.org/u/codekarate) to work full-time on improving Drupal + Gatsby to support Preview & Incremental builds just like WordPress and other CMSs. + +## Will Gatsby v3 have any breaking changes? + +A few, though we don’t anticipate it being a difficult upgrade. We’ve been collecting ideas in this issue (none of them are for sure yet) [https://github.com/gatsbyjs/gatsby/issues/15277](https://github.com/gatsbyjs/gatsby/issues/15277) + +## Shadowing pages is difficult. Query collection gets in the way of shadowing pages effectively when using different data sources. Known issue? Being addressed? + +Yeah — we’re not satisfied with the shadowing experience yet. One way we’re looking to improve the experience is with Gatsby Admin as you’ll be able to browse your themes and what files they have and immediately shadow one plus see the diff between your shadowed file and the original. + +We’re also investigating better patterns for building themes to ensure they’re flexible and straightforward to extend/override. + +## Is there a limit on the size of a website generated with Gatsby? At what point does the build time become unmanageable? + +That’s a constantly moving target as we improve the Gatsby build process. Our open source team is now 15 people strong and many of them are working on the build process from different angles from improving source plugins to core parts of the build process. [Peter van der Zee](https://twitter.com/kuvos) joined the team as a build performance specialist last fall from Facebook where he was a JS Infrastructure Engineer and [has a long string of PRs improving the build process over the past months](https://github.com/gatsbyjs/gatsby/commits?author=pvdz). + +We’re also working on adding benchmark sites that’ll show more clearly when a site is a good fit for Gatsby. + +## How do you make awesome documentation? I saw other projects but the documentation of Gatsby has a special place in my heart. + +Awww thanks! I don’t know there’s anything magic other than just caring enough to do it. Like doing anything else great — you have to care and put in a lot of effort. The whole community and internal folks leading the effort, like [Marcy Sutton](https://twitter.com/marcysutton) and previously [Shannon Soper](https://twitter.com/shannonb_ux), have done a ton of work to improve the docs over the last few years. + +## Is native TypeScript on the roadmap? + +Yes! This is something we’re pretty excited about shipping. If you’re interested in learning more or helping out, check out this issue [Sidhartha Chatterjee](https://github.com/sidharthachatterjee) put together — [https://github.com/gatsbyjs/gatsby/issues/18983](https://github.com/gatsbyjs/gatsby/issues/18983) + +[Blaine Kasten](https://twitter.com/blainekasten) has also been leading the effort to convert the entire codebase to Typescript which has been a massive effort by dozens of people — [https://github.com/gatsbyjs/gatsby/issues/21995](https://github.com/gatsbyjs/gatsby/issues/21995) + +## Are you guys trying to catch up to Next.js's smaller JS bundle size? + +A team at Chrome has been doing a lot of investigation into how frameworks like Next.js & Gatsby can optimize how we ship JavaScript. Next.js implemented that a few months ago and last week [Ward Peeters](https://twitter.com/wardpeet) shipped [a PR implementing the same new webpack bundling algorithm](https://github.com/gatsbyjs/gatsby/pull/22253) for Gatsby—so bundle sizes are now identical to Next.js. Very exciting improvement! + +## Are you continuing to work on even more good accessibility defaults for Gatsby in the future? How important is accessibility overall within Gatsby? + +We care a lot about accessibility. We think that’s part and parcel of building a great framework. We moved to @reach/router as part of Gatsby v2 to take advantage of Ryan Florence’s work on JS router accessibility, and Marcy Sutton has done a lot of testing on how to solve some lingering issues. We hired [Madalyn Rose](https://twitter.com/madalynrose) last fall as a full-time specialist for accessibility engineering in Gatsby. + +Check out our blog posts tagged with accessibility: [https://www.gatsbyjs.org/blog/tags/accessibility](https://www.gatsbyjs.org/blog/tags/accessibility) diff --git a/docs/blog/author.yaml b/docs/blog/author.yaml index 7ced83fa2fa0e..3c2e248ace572 100644 --- a/docs/blog/author.yaml +++ b/docs/blog/author.yaml @@ -400,3 +400,6 @@ bio: Semi-stack developer with a design background. Senior Product Manager at Gatsby Cloud. I love to make things with my hands, travel, and tinker with new tech. avatar: avatars/bob-orchard.jpg twitter: "@boborchard" +- id: Greg Thomas + bio: "Writer, musician, historian, and dedicated service provider for the dog." + avatar: avatars/greg-thomas.jpg diff --git a/docs/blog/avatars/greg-thomas.jpg b/docs/blog/avatars/greg-thomas.jpg new file mode 100644 index 0000000000000..0ec8e03b8e998 Binary files /dev/null and b/docs/blog/avatars/greg-thomas.jpg differ diff --git a/docs/contributing/docs-and-blog-components.md b/docs/contributing/docs-and-blog-components.md index 39e4a501e81e3..8396c4f4145a7 100644 --- a/docs/contributing/docs-and-blog-components.md +++ b/docs/contributing/docs-and-blog-components.md @@ -206,6 +206,89 @@ New docs and blog posts are added to the [docs](https://github.com/gatsbyjs/gats You can read more about writing in Markdown in the [Markdown syntax guide](/docs/mdx/markdown-syntax). +### Frontmatter + +[Frontmatter](/docs/adding-markdown-pages/#frontmatter-for-metadata-in-markdown-files) is a set of key-value pairs in your Markdown and MDX files that defines the metadata for a page. While authoring new docs and blog posts for the Gatsby site, it may be helpful to understand what frontmatter is available to you. + +#### General + +- `title` (string) + + The title of the doc or blog post. Gatsby renders the value in `og:title`, `` and `<h1>`. + +- `excerpt` (string) + + The excerpt for the post. Gatsby renders the value in `description`, `og:description`, and `twitter:description`. + +#### Blog Posts + +- `date` (string) + + The blog post's date in the format of `YYYY-MM-DD`. + +- `canonicalLink` (string) + + The URL to the original piece of content. This is useful for SEO attribution when cross-posting blog posts across domains. Google [offers an explanation](https://support.google.com/webmasters/answer/139066?hl=en) if you're interested in learning more. + +- `tags` (array) + + The blog post's related tags. Gatsby renders the [YAML array/list](https://en.wikipedia.org/wiki/YAML#Basic_components) as links to tag archives and creates the archive if it doesn't exist. + +- `image` (string) + + The relative path to the image. + + - Facebook and `twitterCard: summary` support an aspect ratio of 1:1. + - LinkedIn supports an aspect ratio of 1.91:1 and `twitterCard: summary_large_image` supports an aspect ratio of 2:1 + - Gatsby resizes the image to 1500x1500 and renders the URL in the `og:image` and `twitter:image` metadata. + +- `imageAuthor` (string) + + The name of the image's author. Gatsby renders the value in an `<a>` tag only if `imageAuthorLink` is defined. + +- `imageAuthorLink` (string) + + The link to the image's author. Gatsby renders the value in an `<a>` tag only if `imageAuthor` is defined. + +- `showImageInArticle` (boolean, default false) + + Determines if the `image` is displayed as a hero in the blog post. Gatsby renders it as a fluid image with a width of 786px. + +- `twitterCard` (string) + + A choice between: `summary` or `summary_large_image` that Gatsby renders in the `twitter:card` metadata. + + - `summary` - displays the post as a snapshot that includes a thumbnail, title, and description to convey its content. + - `summary_large_image` - displays the post as a large, full-width image that conveys the visual aspect. + +- `author` (string) + + The author's name, which is also the `id` in the `/docs/blog/author.yaml` file. Gatsby renders a link to the author's archive page. + +#### Documentation + +- `description` (string, default `excerpt`) + + A description of the doc. Gatsby renders the value in the `description` and `og:description` metadata. + +- `issue` (string) + + The issue URL relating to a stub on GitHub. Gatsby renders a link to the stub. + +- `disableTableOfContents` - (boolean) + + Determines if the table of contents is output. + +- `tableOfContentsDepth` - (integer) + + The number of levels to render the table of contents. + +#### Relevant Links + +- [About Twitter Cards](https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/abouts-cards) +- [Facebook Sharing - Best Practices](https://developers.facebook.com/docs/sharing/best-practices#images) +- [Making Your Website Shareable on LinkedIn](https://www.linkedin.com/help/linkedin/answer/46687/making-your-website-shareable-on-linkedin?lang=en) + ### Code blocks Code can be formatted using regular Markdown syntax, but the docs site has additional enhancements that can be used thanks to various Gatsby plugins that aren't all native Markdown. diff --git a/docs/docs/page-build-optimizations-for-incremental-data-changes.md b/docs/docs/page-build-optimizations-for-incremental-data-changes.md index 1d93dc8c2b852..f077b485e4568 100644 --- a/docs/docs/page-build-optimizations-for-incremental-data-changes.md +++ b/docs/docs/page-build-optimizations-for-incremental-data-changes.md @@ -56,7 +56,7 @@ If there are no changed or deleted paths, then the relevant files will not be cr - This feature is not available with `gatsby develop`. -* At the end of each build, gatsby creates a `redux.state` file in `/.cache` that contains previous build data. You will need to persist the `.cache/redux.state` between builds, allowing for comparison. If there is no `redux.state` file located in the `/.cache` folder then a full build will be triggered. +* You will need to persist the `.cache` and `public` directories between builds. This allows for comparisons and reuse of previously built files. If `.cache` directory was not persisted then a full build will be triggered. If `public` directory was not persisted then you might experience failing builds or builds that are missing certain assets. * Any code or static query changes (templates, components, source handling, new plugins etc) will prompt the creation of a new webpack compilation hash and trigger a full build. diff --git a/docs/docs/preprocessing-external-images.md b/docs/docs/preprocessing-external-images.md index adcbe307cad42..863f4140feb14 100644 --- a/docs/docs/preprocessing-external-images.md +++ b/docs/docs/preprocessing-external-images.md @@ -85,7 +85,7 @@ exports.onCreateNode = async ({ Going step by step through the code: -1. Define some types for `MarkdownRemark` using the Schema Customization API. For `featuredImg`, use the `from` argument to point the `link` extension to the correct field name (with a `___NODE` suffix), [more details about foreign-key fields here](https://www.gatsbyjs.org/docs/schema-customization/#foreign-key-fields). Defining a field for alternative text as `featuredImgAlt` can also improve accessibility, in addition to providing context for the image if it fails to load. +1. Define some types for `MarkdownRemark` using the Schema Customization API. For `featuredImg`, use the `from` argument to point the `link` extension to the correct field name (with a `___NODE` suffix), [more details about foreign-key fields here](/docs/schema-customization/#foreign-key-fields). Defining a field for alternative text as `featuredImgAlt` can also improve accessibility, in addition to providing context for the image if it fails to load. 2. Create an `onCreateNode` function so you can watch for when `MarkdownRemark` nodes are made. 3. Use `createRemoteFileNode` by passing in the various required fields and get a reference to the file afterwards. 4. If the Node is created, attach it as a child of the original Node. `___NODE` tells the GraphQL layer that the name before it is going to be a field on the parent Node that links to another Node. To do this, pass the `id` as the reference. Do note, this new node is now attached to the root of the `markdownRemark` node instead of the `frontmatter` field. diff --git a/docs/docs/processing-payments-with-stripe.md b/docs/docs/processing-payments-with-stripe.md index 6fbb6414bd996..fc08251e34c87 100644 --- a/docs/docs/processing-payments-with-stripe.md +++ b/docs/docs/processing-payments-with-stripe.md @@ -31,13 +31,13 @@ Several tutorials, plugins and starters exist to help you get up and running wit ### Plugins -- [gatsby-source-stripe](https://www.gatsbyjs.org/packages/gatsby-source-stripe/): This plugin allows you to bring your product and SKU data into your Gatsby site at build time to be [used with Stripe Checkout](https://www.gatsbyjs.org/tutorial/ecommerce-tutorial/#example-2-import-skus-via-source-plugin). +- [gatsby-source-stripe](/packages/gatsby-source-stripe/): This plugin allows you to bring your product and SKU data into your Gatsby site at build time to be [used with Stripe Checkout](/tutorial/ecommerce-tutorial/#example-2-import-skus-via-source-plugin). ### Starters & Examples - [Example site from the Gatsby Stripe tutorial](https://github.com/gatsbyjs/gatsby/tree/master/examples/ecommerce-tutorial-with-stripe) -- [gatsby-starter-ecommerce](https://www.gatsbyjs.org/starters/parmsang/gatsby-starter-ecommerce/) -- [gatsby-starter-stripe](https://www.gatsbyjs.org/starters/brxck/gatsby-starter-stripe/) +- [gatsby-starter-ecommerce](/starters/parmsang/gatsby-starter-ecommerce/) +- [gatsby-starter-stripe](/starters/brxck/gatsby-starter-stripe/) ## Other resources diff --git a/docs/sites.yml b/docs/sites.yml index d7f68652c96c2..e2a026814dd88 100644 --- a/docs/sites.yml +++ b/docs/sites.yml @@ -10075,6 +10075,16 @@ - Library built_by: Gilbish Kosma built_by_url: https://www.gil20.me/ +- title: Monolit + url: https://monolit.hr + main_url: https://monolit.hr + description: > + Standard business website with sliders and contact form. + categories: + - Business + built_by: Devnet + built_by_url: https://devnet.hr + featured: false - title: Andrew Zeller main_url: https://zeller.io source_url: https://github.com/ajzeller/zellerio_gatsby @@ -10130,3 +10140,97 @@ - Web Development built_by: Jason Zheng built_by_url: https://github.com/bilafish +- title: Fluiditype + url: https://www.fluiditype.com/ + main_url: https://www.fluiditype.com/ + description: > + Fluditype is small CSS library focusing on pure typographic fluidity. Recommend to be used for blogs, portfolios, documentation & and simplistic text websites. + categories: + - Open Source + - Design + built_by: Boris Kirov + built_by_url: https://www.boriskirov.com + featured: false +- title: Bonsaiilabs + main_url: https://bonsaiilabs.com/ + url: https://bonsaiilabs.com/ + description: > + We are a team of two, creating software for startups and enabling learners with our visualize, break, and solve approach. + featured: false + categories: + - Education + - Consulting + built_by: Bonsaiilabs Team + built_by_url: https://bonsaiilabs.com/team +- title: Tyson + main_url: https://www.tyson.com + url: https://www.tyson.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: Hillshire Farm + main_url: https://www.hillshirefarm.com + url: https://www.hillshirefarm.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: Hillshire Snacking + main_url: https://www.hillshiresnacking.com + url: https://www.hillshiresnacking.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: Jimmy Dean + main_url: https://www.jimmydean.com + url: https://www.jimmydean.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: Aidells + main_url: https://www.aidells.com + url: https://www.aidells.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: State Fair + main_url: https://www.corndogs.com + url: https://www.corndogs.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: Nudges + main_url: https://www.nudgesdogtreats.com + url: https://www.nudgesdogtreats.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: Tyson Ingredient Solutions + main_url: https://www.tysoningredientsolutions.com + url: https://www.tysoningredientsolutions.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. +- title: Wright Brand + main_url: https://www.wrightbrand.com + url: https://www.wrightbrand.com + featured: false + categories: + - Food + - Marketing + built_by: Tyson Foods, Inc. diff --git a/docs/starters.yml b/docs/starters.yml index 288965e42dda5..53478db928b01 100644 --- a/docs/starters.yml +++ b/docs/starters.yml @@ -5820,3 +5820,17 @@ - Lots of built-in templates, widgets, or bring in your own custom components. - Uses @builder.io/gatsby plugin to dynamically create pages published on the editor. - SEO +- url: https://gatsby-starter-reason-blog.netlify.com/ + repo: https://github.com/mukul-rathi/gatsby-starter-reason-blog + description: The Gatsby Starter Blog using ReasonML! + tags: + - Blog + - Styling:CSS-in-JS + - Language:Other + features: + - Basic setup for a full-featured type-safe blog + - ReasonML support out-of-the-box + - ReasonReact v3 JSX syntax + - CSS-in-Reason support + - StaticQuery GraphQL support in ReasonML + - Similar to gatsby-starter-blog diff --git a/integration-tests/gatsby-cli/__tests__/build.js b/integration-tests/gatsby-cli/__tests__/build.js index f33b4c551fad9..770b017d8fe7d 100644 --- a/integration-tests/gatsby-cli/__tests__/build.js +++ b/integration-tests/gatsby-cli/__tests__/build.js @@ -1,4 +1,4 @@ -import { GatsbyCLI, removeFolder } from "../test-helpers" +import { GatsbyCLI } from "../test-helpers" const MAX_TIMEOUT = 2147483647 jest.setTimeout(MAX_TIMEOUT) @@ -6,10 +6,8 @@ jest.setTimeout(MAX_TIMEOUT) describe(`gatsby build`, () => { const cwd = `gatsby-sites/gatsby-build` - beforeAll(() => removeFolder(`${cwd}/.cache`)) - beforeAll(() => removeFolder(`${cwd}/public`)) - afterAll(() => removeFolder(`${cwd}/.cache`)) - afterAll(() => removeFolder(`${cwd}/public`)) + beforeAll(() => GatsbyCLI.from(cwd).invoke(`clean`)) + afterAll(() => GatsbyCLI.from(cwd).invoke(`clean`)) it(`creates a built gatsby site`, () => { const [code, logs] = GatsbyCLI.from(cwd).invoke(`build`) diff --git a/integration-tests/gatsby-cli/__tests__/develop.js b/integration-tests/gatsby-cli/__tests__/develop.js new file mode 100644 index 0000000000000..864a7f6568440 --- /dev/null +++ b/integration-tests/gatsby-cli/__tests__/develop.js @@ -0,0 +1,67 @@ +import spawn from "cross-spawn" +import { GatsbyCLI } from "../test-helpers" + +const timeout = seconds => + new Promise(resolve => { + setTimeout(resolve, seconds * 1000) + }) + +const MAX_TIMEOUT = 2147483647 +jest.setTimeout(MAX_TIMEOUT) + +describe(`gatsby develop`, () => { + const cwd = `gatsby-sites/gatsby-develop` + + beforeAll(() => GatsbyCLI.from(cwd).invoke(`clean`)) + afterAll(() => GatsbyCLI.from(cwd).invoke(`clean`)) + + it(`starts a gatsby site on port 8000`, async () => { + // 1. Start the `gatsby develop` command + const [childProcess, getLogs] = GatsbyCLI.from(cwd).invokeAsync(`develop`) + + // 2. Wait for the build process to finish + await timeout(10) + + // 3. kill the `gatsby develop` command so we can get logs + spawn.sync("kill", [childProcess.pid]) + + // 4. Make sure logs for the user contain expected results + const logs = getLogs() + logs.should.contain(`success open and validate gatsby-configs`) + logs.should.contain(`success load plugins`) + logs.should.contain(`success onPreInit`) + logs.should.contain(`success initialize cache`) + logs.should.contain(`success copy gatsby files`) + logs.should.contain(`success onPreBootstrap`) + logs.should.contain(`success createSchemaCustomization`) + logs.should.contain(`success source and transform nodes`) + logs.should.contain(`success building schema`) + logs.should.contain(`success createPages`) + logs.should.contain(`success createPagesStatefully`) + logs.should.contain(`success onPreExtractQueries`) + logs.should.contain(`success update schema`) + logs.should.contain(`success extract queries from components`) + logs.should.contain(`success write out requires`) + logs.should.contain(`success write out redirect data`) + logs.should.contain(`success onPostBootstrap`) + logs.should.contain(`info bootstrap finished`) + // These don't fire in CI. Need to figure out how to make it work. Might not be possible + // logs.should.contain( + // `You can now view gatsby-starter-default in the browser.` + // ) + // logs.should.contain(`http://localhost:8000/`) + // logs.should.contain( + // `View GraphiQL, an in-browser IDE, to explore your site's data and schema` + // ) + // logs.should.contain(`http://localhost:8000/___graphql`) + // logs.should.contain(`Note that the development build is not optimized.`) + // logs.should.contain(`To create a production build, use gatsby build`) + }) + + it.skip(`starts a gatsby site on port 9000 with -p 9000`, () => {}) + it.skip(`starts a gatsby site at a diffent host with -h`, () => {}) + it.skip(`starts a gatsby site with ssl using -S`, () => {}) + it.skip(`starts a gatsby site with cert file using -c`, () => {}) + it.skip(`starts a gatsby site with key file using -k`, () => {}) + it.skip(`starts a gatsby site with -open-tracing-config-file`, () => {}) +}) diff --git a/integration-tests/gatsby-cli/__tests__/feedback.js b/integration-tests/gatsby-cli/__tests__/feedback.js new file mode 100644 index 0000000000000..108fd5a983310 --- /dev/null +++ b/integration-tests/gatsby-cli/__tests__/feedback.js @@ -0,0 +1,23 @@ +import { GatsbyCLI } from "../test-helpers" + +const MAX_TIMEOUT = 2147483647 +jest.setTimeout(MAX_TIMEOUT) + +describe(`gatsby feedback`, () => { + it(`Prints a note to give feedback`, () => { + const [status, logs] = GatsbyCLI.from(`gatsby-sites/gatsby-build`).invoke( + `feedback` + ) + + logs.should.contain( + `Hello! Will you help Gatsby improve by taking a four question survey?` + ) + logs.should.contain( + `It takes less than five minutes and your ideas and feedback will be very helpful` + ) + logs.should.contain( + `Give us your feedback here: https://gatsby.dev/feedback` + ) + expect(status).toBe(0) + }) +}) diff --git a/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/.gitignore b/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/.gitignore new file mode 100644 index 0000000000000..f81327511eeb4 --- /dev/null +++ b/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/.gitignore @@ -0,0 +1,69 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# dotenv environment variable files +.env* + +# gatsby files +.cache/ +public + +# Mac files +.DS_Store + +# Yarn +yarn-error.log +.pnp/ +.pnp.js +# Yarn Integrity file +.yarn-integrity diff --git a/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/package.json b/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/package.json new file mode 100644 index 0000000000000..1ba3273f25386 --- /dev/null +++ b/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/package.json @@ -0,0 +1,37 @@ +{ + "name": "gatsby-starter-default", + "private": true, + "description": "A simple starter to get up and developing quickly with Gatsby", + "version": "0.1.0", + "author": "Kyle Mathews <mathews.kyle@gmail.com>", + "dependencies": { + "gatsby": "^2.19.45", + "prop-types": "^15.7.2", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "react-helmet": "^5.2.1" + }, + "devDependencies": { + "prettier": "^1.19.1" + }, + "keywords": [ + "gatsby" + ], + "license": "MIT", + "scripts": { + "build": "gatsby build", + "develop": "gatsby develop", + "format": "prettier --write \"**/*.{js,jsx,json,md}\"", + "start": "npm run develop", + "serve": "gatsby serve", + "clean": "gatsby clean", + "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/gatsbyjs/gatsby-starter-default" + }, + "bugs": { + "url": "https://github.com/gatsbyjs/gatsby/issues" + } +} diff --git a/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/src/pages/index.js b/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/src/pages/index.js new file mode 100644 index 0000000000000..cf671a42b39d9 --- /dev/null +++ b/integration-tests/gatsby-cli/gatsby-sites/gatsby-develop/src/pages/index.js @@ -0,0 +1,2 @@ +import React from "react" +export default () => <div>Hi</div> diff --git a/integration-tests/gatsby-cli/test-helpers/invoke-cli.js b/integration-tests/gatsby-cli/test-helpers/invoke-cli.js index 09110d72ba604..236caf9e71283 100644 --- a/integration-tests/gatsby-cli/test-helpers/invoke-cli.js +++ b/integration-tests/gatsby-cli/test-helpers/invoke-cli.js @@ -22,9 +22,26 @@ export const GatsbyCLI = { return [ results.status, createLogsMatcher(results.output.toString().split("\n")), - results.output.toString().split("\n"), ] }, + + invokeAsync: (...args) => { + const res = spawn( + join(__dirname, `../../../packages/gatsby-cli/lib/index.js`), + args, + { + cwd: join(__dirname, `../`, `./${relativeCwd}`), + } + ) + + const logs = [] + + res.stdout.on("data", data => { + logs.push(data.toString()) + }) + + return [res, () => createLogsMatcher(logs)] + }, } }, } diff --git a/packages/gatsby-cli/CHANGELOG.md b/packages/gatsby-cli/CHANGELOG.md index 82a519cb8878c..79e19b0c5218e 100644 --- a/packages/gatsby-cli/CHANGELOG.md +++ b/packages/gatsby-cli/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.11.4](https://github.com/gatsbyjs/gatsby/compare/gatsby-cli@2.11.3...gatsby-cli@2.11.4) (2020-04-01) + +**Note:** Version bump only for package gatsby-cli + ## [2.11.3](https://github.com/gatsbyjs/gatsby/compare/gatsby-cli@2.11.2...gatsby-cli@2.11.3) (2020-03-27) **Note:** Version bump only for package gatsby-cli diff --git a/packages/gatsby-cli/package.json b/packages/gatsby-cli/package.json index 4d4d57e5314a9..dcea660bb54c7 100644 --- a/packages/gatsby-cli/package.json +++ b/packages/gatsby-cli/package.json @@ -1,7 +1,7 @@ { "name": "gatsby-cli", "description": "Gatsby command-line interface for creating new sites and running Gatsby commands", - "version": "2.11.3", + "version": "2.11.4", "author": "Kyle Mathews <mathews.kyle@gmail.com>", "bin": { "gatsby": "lib/index.js" @@ -26,7 +26,7 @@ "fs-exists-cached": "^1.0.0", "fs-extra": "^8.1.0", "gatsby-core-utils": "^1.1.1", - "gatsby-telemetry": "^1.2.2", + "gatsby-telemetry": "^1.2.3", "hosted-git-info": "^3.0.4", "is-valid-path": "^0.1.1", "lodash": "^4.17.15", diff --git a/packages/gatsby-plugin-google-gtag/CHANGELOG.md b/packages/gatsby-plugin-google-gtag/CHANGELOG.md index 07e341bfbd189..e9fe9d76cb9ca 100644 --- a/packages/gatsby-plugin-google-gtag/CHANGELOG.md +++ b/packages/gatsby-plugin-google-gtag/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.0.0](https://github.com/gatsbyjs/gatsby/compare/gatsby-plugin-google-gtag@1.2.1...gatsby-plugin-google-gtag@2.0.0) (2020-04-01) + +### Bug Fixes + +- **gatsby-plugin-google-gtag:** OutboundLink Forward Ref ([#22705](https://github.com/gatsbyjs/gatsby/issues/22705)) ([7a4db4b](https://github.com/gatsbyjs/gatsby/commit/7a4db4b)) + ## [1.2.1](https://github.com/gatsbyjs/gatsby/compare/gatsby-plugin-google-gtag@1.2.0...gatsby-plugin-google-gtag@1.2.1) (2020-03-23) **Note:** Version bump only for package gatsby-plugin-google-gtag diff --git a/packages/gatsby-plugin-google-gtag/package.json b/packages/gatsby-plugin-google-gtag/package.json index d2948108648af..81e834d2b89d2 100644 --- a/packages/gatsby-plugin-google-gtag/package.json +++ b/packages/gatsby-plugin-google-gtag/package.json @@ -1,7 +1,7 @@ { "name": "gatsby-plugin-google-gtag", "description": "Gatsby plugin to add google gtag onto a site", - "version": "1.2.1", + "version": "2.0.0", "author": "Tyler Buchea <tyler@buchea.com>", "bugs": { "url": "https://github.com/gatsbyjs/gatsby/issues" diff --git a/packages/gatsby-plugin-google-gtag/src/index.js b/packages/gatsby-plugin-google-gtag/src/index.js index 8be786d406d73..455ba289465c6 100644 --- a/packages/gatsby-plugin-google-gtag/src/index.js +++ b/packages/gatsby-plugin-google-gtag/src/index.js @@ -1,50 +1,51 @@ import React from "react" import PropTypes from "prop-types" -function OutboundLink(props) { - return ( - <a - {...props} - onClick={e => { - if (typeof props.onClick === `function`) { - props.onClick(e) - } - let redirect = true - if ( - e.button !== 0 || - e.altKey || - e.ctrlKey || - e.metaKey || - e.shiftKey || - e.defaultPrevented - ) { - redirect = false - } - if (props.target && props.target.toLowerCase() !== `_self`) { - redirect = false - } - if (window.gtag) { - window.gtag(`event`, `click`, { - event_category: `outbound`, - event_label: props.href, - transport_type: redirect ? `beacon` : ``, - event_callback: function() { - if (redirect) { - document.location = props.href - } - }, - }) - } else { - if (redirect) { - document.location = props.href - } +const OutboundLink = React.forwardRef(({ children, ...props }, ref) => ( + <a + ref={ref} + {...props} + onClick={e => { + if (typeof props.onClick === `function`) { + props.onClick(e) + } + let redirect = true + if ( + e.button !== 0 || + e.altKey || + e.ctrlKey || + e.metaKey || + e.shiftKey || + e.defaultPrevented + ) { + redirect = false + } + if (props.target && props.target.toLowerCase() !== `_self`) { + redirect = false + } + if (window.gtag) { + window.gtag(`event`, `click`, { + event_category: `outbound`, + event_label: props.href, + transport_type: redirect ? `beacon` : ``, + event_callback: function() { + if (redirect) { + document.location = props.href + } + }, + }) + } else { + if (redirect) { + document.location = props.href } + } - return false - }} - /> - ) -} + return false + }} + > + {children} + </a> +)) OutboundLink.propTypes = { href: PropTypes.string, diff --git a/packages/gatsby-source-contentful/src/extend-node-type.js b/packages/gatsby-source-contentful/src/extend-node-type.js index ef7ad9ce43d69..ef1560221e431 100644 --- a/packages/gatsby-source-contentful/src/extend-node-type.js +++ b/packages/gatsby-source-contentful/src/extend-node-type.js @@ -55,7 +55,7 @@ const getBase64Image = imageProps => { // Note: sha1 is unsafe for crypto but okay for this particular case const shasum = crypto.createHash(`sha1`) - shasum.update(`requestUrl`) + shasum.update(requestUrl) const urlSha = shasum.digest(`hex`) // TODO: Find the best place for this step. This is definitely not it. diff --git a/packages/gatsby-telemetry/CHANGELOG.md b/packages/gatsby-telemetry/CHANGELOG.md index 66d9aa824e890..25cc177090c84 100644 --- a/packages/gatsby-telemetry/CHANGELOG.md +++ b/packages/gatsby-telemetry/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.2.3](https://github.com/gatsbyjs/gatsby/compare/gatsby-telemetry@1.2.2...gatsby-telemetry@1.2.3) (2020-04-01) + +### Bug Fixes + +- **telemetry:** fix isTrackingEnabled always truthy ([#22613](https://github.com/gatsbyjs/gatsby/issues/22613)) ([5aaf296](https://github.com/gatsbyjs/gatsby/commit/5aaf296)), closes [#22531](https://github.com/gatsbyjs/gatsby/issues/22531) + ## [1.2.2](https://github.com/gatsbyjs/gatsby/compare/gatsby-telemetry@1.2.1...gatsby-telemetry@1.2.2) (2020-03-25) ### Features diff --git a/packages/gatsby-telemetry/package.json b/packages/gatsby-telemetry/package.json index b7398285b5730..5c75fdd4aa617 100644 --- a/packages/gatsby-telemetry/package.json +++ b/packages/gatsby-telemetry/package.json @@ -1,7 +1,7 @@ { "name": "gatsby-telemetry", "description": "Gatsby Telemetry", - "version": "1.2.2", + "version": "1.2.3", "author": "Jarmo Isotalo <jarmo@isotalo.fi>", "bugs": { "url": "https://github.com/gatsbyjs/gatsby/issues" diff --git a/packages/gatsby-theme-blog-core/CHANGELOG.md b/packages/gatsby-theme-blog-core/CHANGELOG.md index 22655e79134bb..1d6ba847fe100 100644 --- a/packages/gatsby-theme-blog-core/CHANGELOG.md +++ b/packages/gatsby-theme-blog-core/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.3.10](https://github.com/gatsbyjs/gatsby/compare/gatsby-theme-blog-core@1.3.9...gatsby-theme-blog-core@1.3.10) (2020-04-01) + +**Note:** Version bump only for package gatsby-theme-blog-core + ## [1.3.9](https://github.com/gatsbyjs/gatsby/compare/gatsby-theme-blog-core@1.3.8...gatsby-theme-blog-core@1.3.9) (2020-03-30) **Note:** Version bump only for package gatsby-theme-blog-core diff --git a/packages/gatsby-theme-blog-core/package.json b/packages/gatsby-theme-blog-core/package.json index 8be812d44d94f..ea4ffd7daf8d9 100644 --- a/packages/gatsby-theme-blog-core/package.json +++ b/packages/gatsby-theme-blog-core/package.json @@ -1,6 +1,6 @@ { "name": "gatsby-theme-blog-core", - "version": "1.3.9", + "version": "1.3.10", "main": "index.js", "author": "christopherbiscardi <chris@christopherbiscardi.com> (@chrisbiscardi)", "license": "MIT", @@ -30,7 +30,7 @@ }, "devDependencies": { "@mdx-js/react": "^1.5.7", - "gatsby": "^2.20.9", + "gatsby": "^2.20.10", "prettier": "^1.19.1", "react": "^16.12.0", "react-dom": "^16.12.0" diff --git a/packages/gatsby-theme-blog/CHANGELOG.md b/packages/gatsby-theme-blog/CHANGELOG.md index 3929762a2cea1..2d273424d75d8 100644 --- a/packages/gatsby-theme-blog/CHANGELOG.md +++ b/packages/gatsby-theme-blog/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.4.10](https://github.com/gatsbyjs/gatsby/compare/gatsby-theme-blog@1.4.9...gatsby-theme-blog@1.4.10) (2020-04-01) + +**Note:** Version bump only for package gatsby-theme-blog + ## [1.4.9](https://github.com/gatsbyjs/gatsby/compare/gatsby-theme-blog@1.4.8...gatsby-theme-blog@1.4.9) (2020-03-30) **Note:** Version bump only for package gatsby-theme-blog diff --git a/packages/gatsby-theme-blog/package.json b/packages/gatsby-theme-blog/package.json index 14261ebc0e6db..3aa91b2e6a5ec 100644 --- a/packages/gatsby-theme-blog/package.json +++ b/packages/gatsby-theme-blog/package.json @@ -1,6 +1,6 @@ { "name": "gatsby-theme-blog", - "version": "1.4.9", + "version": "1.4.10", "description": "A Gatsby theme for miscellaneous blogging with a dark/light mode", "main": "index.js", "keywords": [ @@ -29,7 +29,7 @@ "gatsby-plugin-react-helmet": "^3.2.1", "gatsby-plugin-theme-ui": "^0.2.53", "gatsby-plugin-twitter": "^2.2.1", - "gatsby-theme-blog-core": "^1.3.9", + "gatsby-theme-blog-core": "^1.3.10", "mdx-utils": "0.2.0", "react-helmet": "^5.2.1", "react-switch": "^5.0.1", @@ -39,7 +39,7 @@ "typography-theme-wordpress-2016": "^0.16.19" }, "devDependencies": { - "gatsby": "^2.20.9", + "gatsby": "^2.20.10", "prettier": "^1.19.1", "react": "^16.12.0", "react-dom": "^16.12.0" diff --git a/packages/gatsby-theme-notes/CHANGELOG.md b/packages/gatsby-theme-notes/CHANGELOG.md index 3b802f6b731f3..24e893a45a506 100644 --- a/packages/gatsby-theme-notes/CHANGELOG.md +++ b/packages/gatsby-theme-notes/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.2.10](https://github.com/gatsbyjs/gatsby/compare/gatsby-theme-notes@1.2.9...gatsby-theme-notes@1.2.10) (2020-04-01) + +**Note:** Version bump only for package gatsby-theme-notes + ## [1.2.9](https://github.com/gatsbyjs/gatsby/compare/gatsby-theme-notes@1.2.8...gatsby-theme-notes@1.2.9) (2020-03-30) **Note:** Version bump only for package gatsby-theme-notes diff --git a/packages/gatsby-theme-notes/package.json b/packages/gatsby-theme-notes/package.json index ab6791a38d7c5..6ec27c769eadc 100644 --- a/packages/gatsby-theme-notes/package.json +++ b/packages/gatsby-theme-notes/package.json @@ -1,7 +1,7 @@ { "name": "gatsby-theme-notes", "description": "Gatsby Theme for adding a notes section to your website", - "version": "1.2.9", + "version": "1.2.10", "author": "John Otander", "license": "MIT", "main": "index.js", @@ -20,7 +20,7 @@ }, "homepage": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-theme-notes#readme", "devDependencies": { - "gatsby": "^2.20.9", + "gatsby": "^2.20.10", "react": "^16.12.0", "react-dom": "^16.12.0" }, diff --git a/packages/gatsby/CHANGELOG.md b/packages/gatsby/CHANGELOG.md index d9db9de35cfe2..d9ca1b2bdaf0b 100644 --- a/packages/gatsby/CHANGELOG.md +++ b/packages/gatsby/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.20.10](https://github.com/gatsbyjs/gatsby/compare/gatsby@2.20.9...gatsby@2.20.10) (2020-04-01) + +### Bug Fixes + +- **core:** Add gatsby/graphql type definitions ([#22652](https://github.com/gatsbyjs/gatsby/issues/22652)) ([ac205cf](https://github.com/gatsbyjs/gatsby/commit/ac205cf)) + ## [2.20.9](https://github.com/gatsbyjs/gatsby/compare/gatsby@2.20.8...gatsby@2.20.9) (2020-03-30) ### Bug Fixes diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index 276e46d40a68e..5444d43f90164 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -1,7 +1,7 @@ { "name": "gatsby", "description": "Blazing fast modern site generator for React", - "version": "2.20.9", + "version": "2.20.10", "author": "Kyle Mathews <mathews.kyle@gmail.com>", "bin": { "gatsby": "./dist/bin/gatsby.js" @@ -71,13 +71,13 @@ "flat": "^4.1.0", "fs-exists-cached": "1.0.0", "fs-extra": "^8.1.0", - "gatsby-cli": "^2.11.3", + "gatsby-cli": "^2.11.4", "gatsby-core-utils": "^1.1.1", "gatsby-graphiql-explorer": "^0.3.1", "gatsby-link": "^2.3.1", "gatsby-plugin-page-creator": "^2.2.1", "gatsby-react-router-scroll": "^2.2.1", - "gatsby-telemetry": "^1.2.2", + "gatsby-telemetry": "^1.2.3", "glob": "^7.1.6", "got": "8.3.2", "graphql": "^14.6.0", @@ -160,8 +160,8 @@ "rimraf": "^3.0.2", "xhr-mock": "^2.5.1", "zipkin": "^0.19.2", - "zipkin-transport-http": "^0.19.2", - "zipkin-javascript-opentracing": "^2.1.0" + "zipkin-javascript-opentracing": "^2.1.0", + "zipkin-transport-http": "^0.19.2" }, "engines": { "node": ">=10.13.0" diff --git a/packages/gatsby/src/redux/nodes.ts b/packages/gatsby/src/redux/nodes.ts index 3385e108a6a8d..1c68274b3f17f 100644 --- a/packages/gatsby/src/redux/nodes.ts +++ b/packages/gatsby/src/redux/nodes.ts @@ -2,6 +2,8 @@ import { store } from "./" import { IGatsbyNode } from "./types" import { createPageDependency } from "./actions/add-page-dependency" +export type FilterCacheKey = string + /** * Get all nodes from redux store. */ @@ -155,27 +157,22 @@ export const addResolvedNodes = ( * looping over all the nodes, when the number of pages (/nodes) scale up. */ export const ensureIndexByTypedChain = ( + cacheKey: FilterCacheKey, chain: string[], nodeTypeNames: string[], typedKeyValueIndexes: Map< - string, + FilterCacheKey, Map<string | number | boolean, Set<IGatsbyNode>> > ): void => { - const chained = chain.join(`+`) - - const nodeTypeNamePrefix = nodeTypeNames.join(`,`) + `/` - // The format of the typedKey is `type,type/path+to+eqobj` - const typedKey = nodeTypeNamePrefix + chained - - if (typedKeyValueIndexes.has(typedKey)) { + if (typedKeyValueIndexes.has(cacheKey)) { return } const { nodes, resolvedNodesCache } = store.getState() const byKeyValue = new Map<string | number | boolean, Set<IGatsbyNode>>() - typedKeyValueIndexes.set(typedKey, byKeyValue) + typedKeyValueIndexes.set(cacheKey, byKeyValue) nodes.forEach(node => { if (!nodeTypeNames.includes(node.internal.type)) { @@ -232,18 +229,13 @@ export const ensureIndexByTypedChain = ( * per `id` so there's a minor optimization for that (no need for Sets). */ export const getNodesByTypedChain = ( - chain: string[], + cacheKey: FilterCacheKey, value: boolean | number | string, - nodeTypeNames: string[], typedKeyValueIndexes: Map< - string, + FilterCacheKey, Map<string | number | boolean, Set<IGatsbyNode>> > ): Set<IGatsbyNode> | undefined => { - const key = chain.join(`+`) - - const typedKey = nodeTypeNames.join(`,`) + `/` + key - - const byTypedKey = typedKeyValueIndexes?.get(typedKey) + const byTypedKey = typedKeyValueIndexes?.get(cacheKey) return byTypedKey?.get(value) } diff --git a/packages/gatsby/src/redux/run-sift.js b/packages/gatsby/src/redux/run-sift.js index e1905a2c21010..aba8ae2936406 100644 --- a/packages/gatsby/src/redux/run-sift.js +++ b/packages/gatsby/src/redux/run-sift.js @@ -1,4 +1,5 @@ // @flow + const { default: sift } = require(`sift`) const { prepareRegex } = require(`../utils/prepare-regex`) const { makeRe } = require(`micromatch`) @@ -19,6 +20,35 @@ const { getNode: siftGetNode, } = require(`./nodes`) +/** + * Creates a key for the filterCache + * + * @param {Array<string>} typeNames + * @param {DbQuery} filter + * @returns {FilterCacheKey} (a string: `types.join()/path.join()/operator` ) + */ +const createTypedFilterCacheKey = (typeNames, filter) => { + // Note: while `elemMatch` is a special case, in the key it's just `elemMatch` + // (This function is future proof for elemMatch support, won't receive it yet) + let f = filter + let comparator = `` + let paths /*: Array<string>*/ = [] + while (f) { + paths.push(...f.path) + if (f.type === `elemMatch`) { + let q /*: IDbQueryElemMatch*/ = f + f = q.nestedQuery + } else { + let q /*: IDbQueryQuery*/ = f + comparator = q.query.comparator + break + } + } + + // Note: the separators (`,` and `/`) are arbitrary but must be different + return typeNames.join(`,`) + `/` + comparator + `/` + paths.join(`,`) +} + ///////////////////////////////////////////////////////////////////// // Parse filter ///////////////////////////////////////////////////////////////////// @@ -105,7 +135,7 @@ function handleMany(siftArgs, nodes) { * * @param {Array<DbQuery>} filters Resolved. (Should be checked by caller to exist) * @param {Array<string>} nodeTypeNames - * @param {Map<string, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes + * @param {Map<FilterCacheKey, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes * @returns {Array<IGatsbyNode> | undefined} */ const runFlatFiltersWithoutSift = ( @@ -149,7 +179,7 @@ const runFlatFiltersWithoutSift = ( /** * @param {Array<DbQuery>} filters * @param {Array<string>} nodeTypeNames - * @param {Map<string, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes + * @param {Map<FilterCacheKey, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes * @returns {Array<Set<IGatsbyNode>> | undefined} Undefined means at least one * cache was not found. Must fallback to sift. */ @@ -163,15 +193,21 @@ const getBucketsForFilters = (filters, nodeTypeNames, typedKeyValueIndexes) => { query: { value: targetValue }, } = filter - ensureIndexByTypedChain(chain, nodeTypeNames, typedKeyValueIndexes) + let cacheKey = createTypedFilterCacheKey(nodeTypeNames, filter) - const nodesByKeyValue = getNodesByTypedChain( + ensureIndexByTypedChain( + cacheKey, chain, - targetValue, nodeTypeNames, typedKeyValueIndexes ) + const nodesByKeyValue = getNodesByTypedChain( + cacheKey, + targetValue, + typedKeyValueIndexes + ) + // If we couldn't find the needle then maybe sift can, for example if the // schema contained a proxy; `slug: String @proxy(from: "slugInternal")` // There are also cases (and tests) where id exists with a different type @@ -202,7 +238,7 @@ const getBucketsForFilters = (filters, nodeTypeNames, typedKeyValueIndexes) => { * @property {boolean} args.firstOnly true if you want to return only the first * result found. This will return a collection of size 1. Not a single element * @property {{filter?: Object, sort?: Object} | undefined} args.queryArgs - * @property {undefined | Map<string, Map<string | number | boolean, Set<IGatsbyNode>>>} args.typedKeyValueIndexes + * @property {undefined | Map<FilterCacheKey, Map<string | number | boolean, Set<IGatsbyNode>>>} args.typedKeyValueIndexes * May be undefined. A cache of indexes where you can look up Nodes grouped * by a key: `types.join(',')+'/'+filterPath.join('+')`, which yields a Map * which holds a Set of Nodes for the value that the filter is trying to eq @@ -243,7 +279,7 @@ exports.runSift = runFilterAndSort * @param {Array<DbQuery> | undefined} filterFields * @param {boolean} firstOnly * @param {Array<string>} nodeTypeNames - * @param {undefined | Map<string, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes + * @param {undefined | Map<FilterCacheKey, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes * @param resolvedFields * @returns {Array<IGatsbyNode> | undefined} Collection of results. Collection * will be limited to 1 if `firstOnly` is true @@ -318,7 +354,7 @@ const filterToStats = ( * * @param {Array<DbQuery>} filters Resolved. (Should be checked by caller to exist) * @param {Array<string>} nodeTypeNames - * @param {Map<string, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes + * @param {Map<FilterCacheKey, Map<string | number | boolean, Set<IGatsbyNode>>>} typedKeyValueIndexes * @returns {Array|undefined} Collection of results */ const filterWithoutSift = (filters, nodeTypeNames, typedKeyValueIndexes) => { diff --git a/packages/gatsby/src/schema/__tests__/fixtures/queries.js b/packages/gatsby/src/schema/__tests__/fixtures/queries.js index 8e93dbdbd696a..d0697fc474309 100644 --- a/packages/gatsby/src/schema/__tests__/fixtures/queries.js +++ b/packages/gatsby/src/schema/__tests__/fixtures/queries.js @@ -39,6 +39,7 @@ const nodes = [ }, frontmatter: { title: `Markdown File 1`, + tags: [], date: new Date(Date.UTC(2019, 0, 1)), authors: [`author2@example.com`, `author1@example.com`], reviewer___NODE: `author2`, @@ -55,6 +56,7 @@ const nodes = [ }, frontmatter: { title: `Markdown File 2`, + tags: [`constructor`], published: false, authors: [`author1@example.com`], reviewer___NODE: null, diff --git a/packages/gatsby/src/schema/__tests__/queries.js b/packages/gatsby/src/schema/__tests__/queries.js index 8058d9a29b406..e39cfe0fe4b71 100644 --- a/packages/gatsby/src/schema/__tests__/queries.js +++ b/packages/gatsby/src/schema/__tests__/queries.js @@ -654,14 +654,14 @@ describe(`Query schema`, () => { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "edges": Array [], - "nodes": Array [], - "totalCount": 0, - }, -} -`) + Object { + "allMarkdown": Object { + "edges": Array [], + "nodes": Array [], + "totalCount": 0, + }, + } + `) }) it(`adds nodes field as a convenience shortcut`, async () => { @@ -874,47 +874,47 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "group": Array [ - Object { - "edges": Array [ Object { - "node": Object { - "frontmatter": Object { - "date": "2019-01-01", - "title": "Markdown File 1", - }, - }, - }, - Object { - "node": Object { - "frontmatter": Object { - "date": null, - "title": "Markdown File 2", - }, - }, - }, - ], - "fieldValue": "Author 1", - }, - Object { - "edges": Array [ - Object { - "node": Object { - "frontmatter": Object { - "date": "2019-01-01", - "title": "Markdown File 1", - }, + "allMarkdown": Object { + "group": Array [ + Object { + "edges": Array [ + Object { + "node": Object { + "frontmatter": Object { + "date": "2019-01-01", + "title": "Markdown File 1", + }, + }, + }, + Object { + "node": Object { + "frontmatter": Object { + "date": null, + "title": "Markdown File 2", + }, + }, + }, + ], + "fieldValue": "Author 1", + }, + Object { + "edges": Array [ + Object { + "node": Object { + "frontmatter": Object { + "date": "2019-01-01", + "title": "Markdown File 1", + }, + }, + }, + ], + "fieldValue": "Author 2", + }, + ], }, - }, - ], - "fieldValue": "Author 2", - }, - ], - }, -} -`) + } + `) }) it(`handles groups added in inline fragment`, async () => { @@ -940,47 +940,47 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "group": Array [ - Object { - "edges": Array [ - Object { - "node": Object { - "frontmatter": Object { - "date": "2019-01-01", - "title": "Markdown File 1", - }, - }, - }, Object { - "node": Object { - "frontmatter": Object { - "date": null, - "title": "Markdown File 2", - }, - }, - }, - ], - "fieldValue": "Author 1", - }, - Object { - "edges": Array [ - Object { - "node": Object { - "frontmatter": Object { - "date": "2019-01-01", - "title": "Markdown File 1", - }, + "allMarkdown": Object { + "group": Array [ + Object { + "edges": Array [ + Object { + "node": Object { + "frontmatter": Object { + "date": "2019-01-01", + "title": "Markdown File 1", + }, + }, + }, + Object { + "node": Object { + "frontmatter": Object { + "date": null, + "title": "Markdown File 2", + }, + }, + }, + ], + "fieldValue": "Author 1", + }, + Object { + "edges": Array [ + Object { + "node": Object { + "frontmatter": Object { + "date": "2019-01-01", + "title": "Markdown File 1", + }, + }, + }, + ], + "fieldValue": "Author 2", + }, + ], }, - }, - ], - "fieldValue": "Author 2", - }, - ], - }, -} -`) + } + `) }) it(`handles groups added in nested fragment`, async () => { @@ -1012,47 +1012,47 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "group": Array [ - Object { - "edges": Array [ Object { - "node": Object { - "frontmatter": Object { - "date": "2019-01-01", - "title": "Markdown File 1", - }, - }, - }, - Object { - "node": Object { - "frontmatter": Object { - "date": null, - "title": "Markdown File 2", - }, - }, - }, - ], - "fieldValue": "Author 1", - }, - Object { - "edges": Array [ - Object { - "node": Object { - "frontmatter": Object { - "date": "2019-01-01", - "title": "Markdown File 1", - }, + "allMarkdown": Object { + "group": Array [ + Object { + "edges": Array [ + Object { + "node": Object { + "frontmatter": Object { + "date": "2019-01-01", + "title": "Markdown File 1", + }, + }, + }, + Object { + "node": Object { + "frontmatter": Object { + "date": null, + "title": "Markdown File 2", + }, + }, + }, + ], + "fieldValue": "Author 1", + }, + Object { + "edges": Array [ + Object { + "node": Object { + "frontmatter": Object { + "date": "2019-01-01", + "title": "Markdown File 1", + }, + }, + }, + ], + "fieldValue": "Author 2", + }, + ], }, - }, - ], - "fieldValue": "Author 2", - }, - ], - }, -} -`) + } + `) }) it(`groups null result`, async () => { @@ -1075,12 +1075,39 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "group": Array [], - }, -} -`) + Object { + "allMarkdown": Object { + "group": Array [], + }, + } + `) + }) + + it(`groups using reserved keywords`, async () => { + const query = ` + { + allMarkdown { + group(field: frontmatter___tags) { + field + fieldValue + } + } + } + ` + const results = await runQuery(query) + expect(results.errors).toBeUndefined() + expect(results.data).toMatchInlineSnapshot(` + Object { + "allMarkdown": Object { + "group": Array [ + Object { + "field": "frontmatter.tags", + "fieldValue": "constructor", + }, + ], + }, + } + `) }) }) @@ -1132,14 +1159,14 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "distinct": Array [ - "2019-01-01T00:00:00.000Z", - ], - }, -} -`) + Object { + "allMarkdown": Object { + "distinct": Array [ + "2019-01-01T00:00:00.000Z", + ], + }, + } + `) }) it(`handles null result`, async () => { @@ -1157,12 +1184,12 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "distinct": Array [], - }, -} -`) + Object { + "allMarkdown": Object { + "distinct": Array [], + }, + } + `) }) }) }) @@ -1249,25 +1276,25 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "nodes": Array [ - Object { - "frontmatter": Object { - "reviewer": Object { - "name": "Author 2", + Object { + "allMarkdown": Object { + "nodes": Array [ + Object { + "frontmatter": Object { + "reviewer": Object { + "name": "Author 2", + }, + }, + }, + Object { + "frontmatter": Object { + "reviewer": null, + }, + }, + ], }, - }, - }, - Object { - "frontmatter": Object { - "reviewer": null, - }, - }, - ], - }, -} -`) + } + `) }) it(`with defined field mappings`, async () => { @@ -1287,25 +1314,25 @@ Object { const results = await runQuery(query) expect(results.errors).toBeUndefined() expect(results.data).toMatchInlineSnapshot(` -Object { - "allMarkdown": Object { - "nodes": Array [ - Object { - "frontmatter": Object { - "reviewerByEmail": Object { - "name": "Author 2", + Object { + "allMarkdown": Object { + "nodes": Array [ + Object { + "frontmatter": Object { + "reviewerByEmail": Object { + "name": "Author 2", + }, + }, + }, + Object { + "frontmatter": Object { + "reviewerByEmail": null, + }, + }, + ], }, - }, - }, - Object { - "frontmatter": Object { - "reviewerByEmail": null, - }, - }, - ], - }, -} -`) + } + `) }) }) diff --git a/packages/gatsby/src/schema/resolvers.js b/packages/gatsby/src/schema/resolvers.js index 81faf07bc7c0c..b0cdf234a7ac2 100644 --- a/packages/gatsby/src/schema/resolvers.js +++ b/packages/gatsby/src/schema/resolvers.js @@ -74,7 +74,11 @@ const group = (source, args, context, info) => { acc[key] = (acc[key] || []).concat(node) }) return acc - }, {}) + // Note: using Object.create on purpose: + // object key may be arbitrary string including reserved words (i.e. `constructor`) + // see: https://github.com/gatsbyjs/gatsby/issues/22508 + }, Object.create(null)) + return Object.keys(groupedResults) .sort() .reduce((acc, fieldValue) => {