diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index d459153c638fc..a52071787e0ba 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,6 +12,7 @@ labels: "type: bug" - How to File an Issue: https://www.gatsbyjs.com/contributing/how-to-file-an-issue/ Before opening a new issue, please search existing issues: https://github.com/gatsbyjs/gatsby/issues + And existing Discussions: https://github.com/gatsbyjs/gatsby/discussions --> ## Description @@ -34,4 +35,4 @@ What happened. ### Environment -Run `gatsby info --clipboard` in your project directory and paste the output here. +Run `gatsby info --clipboard` in your project directory and paste the output here. Also name any `flags` you use inside `gatsby-config.js`. diff --git a/docs/docs/how-to/custom-configuration/eslint.md b/docs/docs/how-to/custom-configuration/eslint.md index b324c31630ccb..54d047afddee7 100644 --- a/docs/docs/how-to/custom-configuration/eslint.md +++ b/docs/docs/how-to/custom-configuration/eslint.md @@ -38,8 +38,8 @@ module.exports = { } ``` -Note: When there is no ESLint file Gatsby implicitly adds a barebones ESLint loader. This loader pipes ESLint feedback into the terminal window where you are running or building Gatsby and also to the console in your browser developer tools. This gives you consolidated, immediate feedback on newly-saved files. When you include a custom `.eslintrc` file, Gatsby gives you full control over the ESLint configuration. This means that it will override the built-in `eslint-loader` and you need to enable any and all rules yourself. One way to do this is to use the Community plugin [`gatsby-plugin-eslint`](/plugins/gatsby-plugin-eslint/). This also means that the default [ESLint config Gatsby ships with](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/eslint-config.ts) will be entirely overwritten. If you would still like to take advantage of those rules, you'll need to copy them to your local file. +**Note:** When there is no ESLint file Gatsby implicitly adds a barebones ESLint loader. This loader pipes ESLint feedback into the terminal window where you are running or building Gatsby and also to the console in your browser developer tools. This gives you consolidated, immediate feedback on newly-saved files. When you include a custom `.eslintrc` file, Gatsby gives you control over the ESLint configuration. This means that it will override the built-in `eslint-loader` only leaving the required rules activated (`no-anonymous-exports-page-templates` & `limited-exports-page-templates`). For the non-required config you'll need to activate each rule on your own. One way to do this is to use the Community plugin [`gatsby-plugin-eslint`](/plugins/gatsby-plugin-eslint/). This also means that the default [ESLint config Gatsby ships with](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/eslint-config.ts) (the `eslintConfig` export) will be entirely overwritten. If you would still like to take advantage of those rules, you'll need to copy them to your local file. ### Disabling ESLint -Creating an empty `.eslintrc` file at the root of your project will disable ESLint for your site. The empty file will disable the built-in `eslint-loader` because Gatsby assumes once you have an ESLint file you are in charge of linting. +Creating an empty `.eslintrc` file at the root of your project will mostly disable ESLint for your site. The empty file will disable the built-in `eslint-loader` because Gatsby assumes once you have an ESLint file you are in charge of linting. However, the required ESLint rules for [Fast Refresh](/docs/reference/local-development/fast-refresh) (`no-anonymous-exports-page-templates` & `limited-exports-page-templates`) will still be activated and shown in the terminal output. diff --git a/docs/docs/reference/release-notes/v3.4/index.md b/docs/docs/reference/release-notes/v3.4/index.md new file mode 100644 index 0000000000000..a05e53c33dcb2 --- /dev/null +++ b/docs/docs/reference/release-notes/v3.4/index.md @@ -0,0 +1,120 @@ +--- +date: "2021-04-27" +version: "3.4.0" +--- + +# [v3.4](https://github.com/gatsbyjs/gatsby/compare/gatsby@3.4.0-next.0...gatsby@3.4.0) (April 2021 #2) + +Welcome to `gatsby@3.4.0` release (April 2021 #2) + +Key highlights of this release: + +- [Experimental: Enable webpack persistent caching for production builds](#experimental-enable-webpack-persistent-caching-for-production-builds) - significantly speed up webpack compilation on subsequent builds +- [Experimental: Gatsby Functions](#experimental-gatsby-functions) - serverless functions in Gatsby & Gatsby Cloud +- [New Aggregation Resolvers](#new-aggregation-resolvers) - adds `min()`, `max()`, and `sum()` resolvers to `allX` queries +- [Better Fast Refresh handling for styling libraries](#better-fast-refresh-handling-for-styling-libraries) - Theme UI and Chakra UI now work correctly with Fast Refresh + +Also check out [notable bugfixes](#notable-bugfixes--improvements). + +**Bleeding Edge:** Want to try new features as soon as possible? Install `gatsby@next` and let us know +if you have any [issues](https://github.com/gatsbyjs/gatsby/issues). + +[Previous release notes](/docs/reference/release-notes/v3.3) + +[Full changelog](https://github.com/gatsbyjs/gatsby/compare/gatsby@3.4.0-next.0...gatsby@3.4.0) + +--- + +## Experimental: Enable webpack persistent caching for production builds + +[webpack 5 introduced built in persistent caching](https://webpack.js.org/blog/2020-10-10-webpack-5-release/#persistent-caching). It allows webpack to reuse result of previous compilations and significantly speed up compilation steps. + +To use it, add a flag to your `gatsby-config.js`: + +```js +// In your gatsby-config.js +module.exports = { + // your existing config + flags: { + PRESERVE_WEBPACK_CACHE: true, + }, +} +``` + +[Details and discussion](https://github.com/gatsbyjs/gatsby/discussions/28331). + +## Experimental: Functions + +We're making our initial alpha release of serverless functions in Gatsby! + +- [Details and discussion](https://github.com/gatsbyjs/gatsby/discussions/30735) +- [Original PR](https://github.com/gatsbyjs/gatsby/pull/30192). +- [Sign up for early access to Functions in Gatsby Cloud](https://www.gatsbyjs.com/functions/). + +## New Aggregation Resolvers + +The [PR #30789](https://github.com/gatsbyjs/gatsby/pull/30789) added new aggregation resolvers similar to the already existing `group` and `distinct` resolvers. You now can use `min()`, `max()`, and `sum()`. They support numeric fields, but also attempt to cast non-numeric fields and includes them if the value is not `NaN`. + +An example query: + +```graphql +{ + allShopifyProduct { + maxPrice: max(field: variants___price) + minPrice: min(field: variants___price) + totalPrice: sum(field: variants___price) + } +} +``` + +## Better Fast Refresh handling for styling libraries + +Since the introduction of Fast Refresh changes to theme files both in [Theme UI](https://theme-ui.com/) and [Chakra UI](https://chakra-ui.com/) didn't result in correct hot-reloading behavior as the user had to manually reload the page to see their changes. The [PR #30901](https://github.com/gatsbyjs/gatsby/pull/30901) added better Fast Refresh handling for components that don't satisfy the constraints set by Fast Refresh but it didn't completely fix the incorrect behavior in both plugins. Upstream PRs from us to [Theme UI](https://github.com/system-ui/theme-ui/pull/1659) and [Chakra UI](https://github.com/chakra-ui/chakra-ui/pull/3841) fixed the behavior! Install `theme-ui@^0.7.1` or `@chakra-ui/gatsby-plugin@^2.0.0` to get the updates. + +## Notable bugfixes & improvements + +- Fixed page context changes not triggering query rerunning [PR #28590](https://github.com/gatsbyjs/gatsby/pull/28590) +- Fixed not being able to disable `DEV_SSR` flag when `FAST_DEV` is enabled [PR #30992](https://github.com/gatsbyjs/gatsby/pull/30992) +- Speed up `createPages` by ~10% by memoizing `process.env` access [PR #30768](https://github.com/gatsbyjs/gatsby/pull/30768) +- You now can define the `--host` option of `gatsby-cli` with `env.HOST` [PR #26712](https://github.com/gatsbyjs/gatsby/pull/26712) +- Allow CI AWS lamba builds [PR #30653](https://github.com/gatsbyjs/gatsby/pull/30653) +- File System Route API: De-dupe collection pages [PR #31016](https://github.com/gatsbyjs/gatsby/pull/31016) + +## Contributors + +A big **Thank You** to [our community who contributed](https://github.com/gatsbyjs/gatsby/compare/gatsby@3.4.0-next.0...gatsby@3.4.0) to this release 💜 + +- [gustavo-a](https://github.com/gustavo-a): fix(gatsby-source-wordpress): change `console.warning` to `console.warn` [PR #30764](https://github.com/gatsbyjs/gatsby/pull/30764) +- [NatnaelSisay](https://github.com/NatnaelSisay): Fix: change attribute name [PR #30800](https://github.com/gatsbyjs/gatsby/pull/30800) +- [evildmp](https://github.com/evildmp): chore(docs): Update links to Diátaxis framework [PR #30808](https://github.com/gatsbyjs/gatsby/pull/30808) +- [hoobdeebla](https://github.com/hoobdeebla): fix(renovate): add breaking minor updates to major updates list [PR #30676](https://github.com/gatsbyjs/gatsby/pull/30676) +- [Js-Brecht](https://github.com/Js-Brecht) + + - fix(gatsby-core-utils): fetch-remote-file download failure when missing content-length header [PR #30810](https://github.com/gatsbyjs/gatsby/pull/30810) + - handle plugin parentDir resolution in resolvePlugin() [PR #30812](https://github.com/gatsbyjs/gatsby/pull/30812) + - fix(gatsby): "Cannot find module 'babel-preset-gatsby'" error [PR #30813](https://github.com/gatsbyjs/gatsby/pull/30813) + +- [herecydev](https://github.com/herecydev): fix(gatsby): Decode base path in runtime [PR #30682](https://github.com/gatsbyjs/gatsby/pull/30682) +- [axe312ger](https://github.com/axe312ger) + + - Refactor: using-contentful to use gatsby-plugin-image exclusively [PR #30717](https://github.com/gatsbyjs/gatsby/pull/30717) + - feat(contentful): warn users when using restricted content type names [PR #30715](https://github.com/gatsbyjs/gatsby/pull/30715) + - test: introduce e2e tests for Contentful [PR #30390](https://github.com/gatsbyjs/gatsby/pull/30390) + - test: Add Contentful content rendering to E2E tests [PR #30854](https://github.com/gatsbyjs/gatsby/pull/30854) + - test(contentful): improve content reference snapshot tests [PR #31008](https://github.com/gatsbyjs/gatsby/pull/31008) + +- [kaboumk](https://github.com/kaboumk): fix(gatsby-starter-wordpress-blog): Fix altText [PR #30832](https://github.com/gatsbyjs/gatsby/pull/30832) +- [johndavidcooley](https://github.com/johndavidcooley): chore(docs): Fix typo [PR #30858](https://github.com/gatsbyjs/gatsby/pull/30858) +- [AbdallahAbis](https://github.com/AbdallahAbis): chore(gatsby-plugin-image): Remove version note [PR #30758](https://github.com/gatsbyjs/gatsby/pull/30758) +- [pvorozhe](https://github.com/pvorozhe): chore: Add cloud hosting option for starter READMEs [PR #30792](https://github.com/gatsbyjs/gatsby/pull/30792) +- [pelleknaap](https://github.com/pelleknaap): Fix small typo [PR #30911](https://github.com/gatsbyjs/gatsby/pull/30911) +- [mgurevin](https://github.com/mgurevin): fix(gatsby-cli): added HOST environment variable [PR #26712](https://github.com/gatsbyjs/gatsby/pull/26712) +- [VMBindraban](https://github.com/VMBindraban): chore(gatsby-source-graphql): Update README url => uri [PR #30872](https://github.com/gatsbyjs/gatsby/pull/30872) +- [OdysLam](https://github.com/OdysLam): chore(docs): Add tailwind to more options at tutorial part 2 [PR #30910](https://github.com/gatsbyjs/gatsby/pull/30910) +- [moonmeister](https://github.com/moonmeister): breaking(gatsby-plugin-sitemap): vNext rewrite [PR #25670](https://github.com/gatsbyjs/gatsby/pull/25670) +- [AcademicHumber](https://github.com/AcademicHumber): Change the 'idKey' parameter's default value [PR #30502](https://github.com/gatsbyjs/gatsby/pull/30502) +- [kennethormandy](https://github.com/kennethormandy): chore(gatsby-plugin-mdx): Document CommonMark option [PR #30669](https://github.com/gatsbyjs/gatsby/pull/30669) +- [mathisobadia](https://github.com/mathisobadia): fix(gatsby): change order of feedbackDisabled checks to allow CI AWS lambda build [PR #30653](https://github.com/gatsbyjs/gatsby/pull/30653) +- [MichaelDeBoey](https://github.com/MichaelDeBoey): chore(gatsby-plugin-flow): Add pluginOptionsSchema validation [PR #27599](https://github.com/gatsbyjs/gatsby/pull/27599) +- [chrish-d](https://github.com/chrish-d): chore(docs): Updated warning icon to use emoji [PR #30979](https://github.com/gatsbyjs/gatsby/pull/30979) +- [jcalcaben](https://github.com/jcalcaben): fix(gatsby-plugin-mdx): Reference style links broken in static builds [PR #30967](https://github.com/gatsbyjs/gatsby/pull/30967) diff --git a/docs/docs/sourcing-from-agilitycms.md b/docs/docs/sourcing-from-agilitycms.md index c1144353d1eed..faf4d410da8b2 100644 --- a/docs/docs/sourcing-from-agilitycms.md +++ b/docs/docs/sourcing-from-agilitycms.md @@ -6,27 +6,31 @@ This guide takes you through the steps involved in setting up a Gatsby site that Check our [docs](https://help.agilitycms.com/hc/en-us/articles/360039879872) for up-to-date documentation. -## What is Agility CMS? What makes it different? +## What is Agility CMS? -[Agility CMS](https://agilitycms.com/) is a headless Content Management System (CMS) that lets you define your custom content types, relationships and pages. This is called Content Architecture, and you can reuse this content for your websites and apps. +[Agility CMS](https://agilitycms.com/) is a flexible headless Content Management System (CMS) with an infinite number of ways to configure and set up your pages and content. Agility lets you define custom content types, relationships and pages. This is called Content Architecture, and you can reuse this content for your websites and apps. Agility believes that a successful website balances the **User Experience (UX)**, **Editor Experience (EX)**, and **Developer Experience (DX)**. -While Gatsby tends to handle **UX** and **DX** quite well, editors are not always comfortable working directly in a codebase. They prefer to manage their sitemap and see what content is on which pages. Using Gatsby with a headless CMS allows for this. +While Gatsby tends to handle **UX** and **DX** quite well, editors are not always comfortable working directly in a codebase. They prefer to manage their sitemap and see what content is on which pages. Using Gatsby with a headless CMS like Agility allows for this. -Agility aims to empower and improve the **Editor Experience** by providing built-in **Page Management**. This means developers can build UI Components and leave editors to compose their pages. +Agility aims to empower and improve the **Editor Experience** by providing built-in [**Page Management**](https://help.agilitycms.com/hc/en-us/articles/360055805831). This means developers can build UI Components and leave editors to compose their pages. [Learn more about Agility CMS and Gatsby](https://help.agilitycms.com/hc/en-us/articles/360039879872) -## Getting started +## Getting Started -### Create a free Agility account +This guide walks you through the steps involved in setting up a Gatsby site that fetches content from Agility CMS. -Create an Agility CMS account with the Free Plan (this plan is free forever). [Sign up to Agility CMS](https://account.agilitycms.com/sign-up?product=agility-free). +### Step 1: Create a free Agility account -Once your account is created, you'll need to grab your GUID and API Keys. +In order to showcase best practices, evaluate, and help onboard new users when using Agility CMS, this guide uses the pre-configured Blog Template. This template has a few Pages along with some Page Modules and Content Models already set for you to help support a familiar blogging experience. -### Get the code +It's important to note though, that you can customize anything and everything in this template, it's just giving you a head start and serving as an example! + +Create an Agility CMS account with the [**Free Developer Plan**](https://account.agilitycms.com/sign-up?product=agility-free) (this plan is free forever). + +### Step 2: Get the code Make sure you have the Gatsby CLI installed: @@ -34,10 +38,10 @@ Make sure you have the Gatsby CLI installed: npm install -g gatsby-cli ``` -Clone the [Agility CMS Gatsby Starter](https://github.com/agility/agility-gatsby-starter) repo from GitHub that has all the code you need to get started: +Create a new Gatsby project using the [Agility CMS Gatsby Starter](https://github.com/agility/agilitycms-gatsby-starter) repo from GitHub that has all the code you need to get started: ```shell -git clone https://github.com/agility/agility-gatsby-starter.git +gatsby new agilitycms-gatsby-starter https://github.com/agility/agilitycms-gatsby-starter ``` Install the dependencies: @@ -46,52 +50,286 @@ Install the dependencies: npm install ``` -Once you've the infrastructure set up, run the site in development mode: +### Step 3: Authenticate your Gatsby site with Agility + +Make a copy of `.env.development.example` file called `.env.development`. ```shell -gatsby develop +cp .env.development.example .env.development ``` -The site is just a starter, but it has a bunch of interesting features that you can use to build from. The next step is to hook this code up to your new Agility CMS instance that you just created. +Add your `AGILITY_GUID` and `AGILITY_API_KEY` variable values to the `.env.development` file, you can find these in the Content Manager by going to [Settings](https://manager.agilitycms.com/settings/apikeys). + +```text:title=.env.development +# Your Instance Id +AGILITY_GUID= + +# Your Preview API Key (recommended) - you can get this from the Getting Started Page in Agility CMS. It starts with defaultpreview. +AGILITY_API_KEY= + +# If using your Preview API Key, set this to true +AGILITY_API_ISPREVIEW=true +``` -## Hook it up to your Agility CMS instance +### Step 4: Running the site locally -Edit the `gatsby-config.js` file and replace the `guid` and `apiKey` with yours. +Once your environment variables have been added for development, you can run the site locally: -You can find your API keys on the Getting Started page in the Agility CMS Content Manager. +```shell +gatsby develop +``` -![Agility CMS - Dashboard - API Keys](./images/agilitycms-api-keys.png) +If successful, your site's build should complete and you be able to view the site in your browser on `http://localhost:8000`. You can also run the GraphiQL IDE at `http://localhost:8000/___graphql`. The GraphiQL IDE will help you explore the app’s data, including data from Agility. -If you use the `preview` key, you won't have to publish to see the changes you've made show up. If you use the `fetch` key, make sure you've published any content you wish to see changed. +For production, follow the same steps using the `.env.production` file and your Live API Key. ## How it works -The Gatsby Source Plugin will synchronize your sitemap, pages, and content for you and place it into **GraphQL**. +### Sourcing and Querying Agility Content in Gatsby -All of those pages and content are then made available in GraphQL to the React Components you will write to render those pages. +You can source content from Agility CMS into your Gatsby site with [`gatsby-source-agilitycms`](https://github.com/agility/gatsby-source-agilitycms) which will synchronize all of your content, page modules, sitemaps and pages, and make them available via GraphQL. -Check out the component called "Jumbotron". This is an example of how to display a styled heading and sub-heading with content that comes from Agility CMS. Here is the Module that provides this content being edited in the Agility CMS Content Manager: +The source plugin uses [`@agility/content-sync`](https://github.com/agility/agility-sync-sdk) which ensures that only content that has changed is updated. It keeps things in-sync for you. This means your first build will download all of your content, while subsequent builds only update what has changed. This enables incremental builds and results in bleeding-edge, fast build times. -![Agility CMS - Example Module - Jumbotron](./images/agilitycms-jumbotron.png) +To query content from Agility CMS, you would query `allAgility`, for example, `allAgilityPost`, then select what fields you want to retrieve for each item. An example can be seen here in the [agilitycms-gatsby-starter](https://github.com/agility/agilitycms-gatsby-starter/blob/main/src/components/agility-pageModules/PostsListing.jsx): -And here is the code used to render it. Notice that the `title` and `subTitle` fields are available as properties of the `item.fields` object. +```graphql +query { + posts: allAgilityPost { + nodes { + customFields { + title + date(formatString: "MMMM DD, YYYY") + image { + url + label + } + content + } + } + } +} +``` -```jsx:title=src/modules/Jumbotron.js -import React, { Component } from "react" -import { graphql, StaticQuery } from "gatsby" +[Learn more about Sourcing and Querying Agility Content in Gatsby](https://help.agilitycms.com/hc/en-us/articles/360043003951) + +### How Pages Work + +The `gatsby-source-agilitycms` plugin makes it easy to source content, but it also generates your Pages for you based off of your sitemap in Agility CMS. This means that editors in the CMS control what pages are available, what their URLs are, and exactly what UI components (Agility CMS calls these Page Modules) make up each page. + +Each page in Agility is composed and generated dynamically at _build-time_ using a **masterPageTemplate** that you define in your `gatsby-config.js` plugin options. + +```js:title=gatsby-config.js +module.exports = { + siteMetadata: { + title: "Agility CMS Gatsby Starter", + }, + plugins: [ + ... + { + //the name of the plugin + resolve: "@agility/gatsby-source-agilitycms", + //the options for our plugin + options: { + ... + //the page template that will be used to render Agility CMS pages + masterPageTemplate: "./src/AgilityPage.jsx" + }, + }, + ... + ] +} +``` -import "./Jumbotron.css" +```jsx:title=src/AgilityPage.jsx +import React from "react" +import { graphql } from "gatsby" + +export const query = graphql` + query($pageID: Int!, $contentID: Int!, $languageCode: String!) { + agilitypage(languageCode: { eq: $languageCode }, itemID: { eq: $pageID }) { + pageJson + } + agilityitem( + languageCode: { eq: $languageCode } + itemID: { eq: $contentID } + ) { + itemJson + } + } +` + +const AgilityPage = ({ pageContext, data }) => { + return ( + <> + + +
+ +
+ +
+ +
+ + ) +} + +export default AgilityPage +``` + +[Learn more about How Agility Pages Work in Gatsby](https://help.agilitycms.com/hc/en-us/articles/360043035211) + +### How Page Modules Work + +Page Modules in Agility CMS are the functional components that make up a page. Editors use these to compose what type of content is on each page and in what order they appear. Developers define what page modules are available in the CMS and what fields they have. Each module defined in Agility CMS should correspond to a React Component in your Gatsby site. + +In the [agilitycms-gatsby-starter](https://github.com/agility/agilitycms-gatsby-starter) site, the name of the page module is used to find a corresponding React component that matches the same name. If a match is found, that component is dynamically imported and rendered. + +For example, if a module has a reference name of RichTextArea in the CMS, then while the page is being rendered by the gatsby-source-agilitycms plugin, it will look for `src/components/agility-pageModules/RichTextArea.jsx` in the `src/components/agility-pageModules` directory. + +```jsx:title=src/components/agility-pageModules/RichTextArea.jsx +import React from "react" +import { renderHTML } from "../../agility/utils" + +const RichTextArea = ({ module }) => { + // get module fields + const { customFields } = module + + return ( +
+
+
+
+
+ ) +} + +export default RichTextArea +``` -export default class Jumbotron extends Component { - render() { - return ( -
-

{this.props.item.fields.title}

-

{this.props.item.fields.subTitle}

-
- ) +[Learn more about How Agility Page Modules Work in Gatsby](https://help.agilitycms.com/hc/en-us/articles/360043037491) + +### How Page Templates Work + +Page Templates in Agility CMS are how developers can differentiate the styles of certain types of pages, and define where on the page that editors can add Modules (functional components of the page that editors control). Some sites may only have a single page template and this is re-used across the site, others may have other templates to allow for more flexible layouts. + +In the [agilitycms-gatsby-starter](https://github.com/agility/agilitycms-gatsby-starter) site, the Name of the Page Template is used to find a corresponding React component that matches the same name. If a match is found, that component is dynamically imported and rendered. + +For example, if a Page Template has a reference name of MainTemplate in the CMS, then while the page is being rendered by the `gatsby-source-agilitycms` plugin, it will look for `src/components/agility-pageTemplates/MainTemplate.jsx` in the `src/components/agility-pageTemplates` directory. + +```jsx:title=src/components/agility-pageTemplates/MainTemplate.jsx +import React from "react" +import ContentZone from "../../agility/components/ContentZone" +import { getModule } from "../../components/agility-pageModules" + +const MainTemplate = props => { + return ( +
+ +
+ ) +} +export default MainTemplate +``` + +[Learn more about How Agility Page Templates Work in Gatsby](https://help.agilitycms.com/hc/en-us/articles/360043038271) + +### Resolving Linked Content + +While you are sourcing and querying content in gatsby, you are likely to come across a scenario where you need to retrieve a content item and its related content. In Agility CMS, Linked Content fields are used to related content to one another in various ways. + +When querying a Post, for example, you may want to also retrieve the details for the Category. On your Post GraphQL node, you may notice a category property, however, it will only contain a contentID reference, not the entire node representing the Category. You'll need to resolve this Linked Content when you need it. + +In the [agilitycms-gatsby-starter](https://github.com/agility/agilitycms-gatsby-starter), the Linked Content is resolved by using [Gatsby Resolvers](/docs/reference/graphql-data-layer/schema-customization/#createresolvers-api). + +Resolvers are added to your `gatsby-node.js` in your site, and they allow you to add a new field to your content node which will handle resolving your Linked Content reference. This means you are telling GraphQL, when you query a specific property on a node, it will actually run a function to go and get your Linked Content and return it. + +An example of this can be found [here](https://github.com/agility/agilitycms-gatsby-starter/blob/main/gatsby-node.js) in the starter site: + +```js:title=gatsby-node.js +const agility = require("./src/agility/utils") + +exports.createResolvers = args => { + const { + createResolvers, + getNode, + createNodeId, + createNode, + createContentDigest, + configOptions, + } = args + + // The data needed for Linked Content is resolved here + const resolvers = { + // on the 'agilityPost' node type + agilityPost: { + // get the sitemap node that represents this item ( i.e. /blog/my-blog-post ) + sitemapNode: agility.getDynamicPageItemSitemapNode(), + + // get the category + linkedContent_agilityCategory: agility.getLinkedContentItem({ + type: "agilityCategory", + linkedContentFieldName: "category", + }), + }, + } + createResolvers(resolvers) +} +``` + +Now on the `agilityPost` node, you'll be able to query the category: + +```graphql +query { + posts: allAgilityPost { + nodes { + customFields { + title + date(formatString: "MMMM DD, YYYY") + image { + url + label + } + content + } + linkedContent_agilityCategory { + customFields { + title + } + } + } } } ``` -When you add new modules and content definitions to Agility CMS, the components used to render those modules will automatically receive the strongly typed data delivered to those modules as props. +### How Images Work + +Agility CMS also provides `gatsby-image-agilitycms` as a npm package. This is a custom image component that takes images stored within Agility CMS and handles all of the hard parts of displaying responsive images that follow best practices for performance on your website or application. + +```jsx +import { AgilityImage } from "@agility/gatsby-image-agilitycms" + +const Component = ({ image }) => ( + +) +``` + +[Learn more about How Images Work in Gatsby](https://help.agilitycms.com/hc/en-us/articles/360043048651) + +## Resources + +- [Agility CMS Official Site](https://agilitycms.com/) +- [Agility CMS & Gatsby Documentation](https://help.agilitycms.com/hc/en-us/articles/360039879872) +- [Agility CMS Community Slack](https://join.slack.com/t/agilitycms-community/shared_invite/zt-99qlv1hw-tpPOJ99V21Y2omtA_uTcJw) diff --git a/e2e-tests/contentful/gatsby-config.js b/e2e-tests/contentful/gatsby-config.js index 1fd1d47674fa8..8ffb795393aeb 100644 --- a/e2e-tests/contentful/gatsby-config.js +++ b/e2e-tests/contentful/gatsby-config.js @@ -17,5 +17,13 @@ module.exports = { `gatsby-transformer-sqip`, `gatsby-plugin-image`, `gatsby-plugin-sharp`, + // Enable to update schema.sql + // { + // resolve: `gatsby-plugin-schema-snapshot`, + // options: { + // path: `schema.gql`, + // update: true, + // }, + // }, ], } diff --git a/e2e-tests/contentful/schema.gql b/e2e-tests/contentful/schema.gql new file mode 100644 index 0000000000000..b5adaf7cf3a47 --- /dev/null +++ b/e2e-tests/contentful/schema.gql @@ -0,0 +1,503 @@ +### Type definitions saved at 2021-04-27T13:44:24.013Z ### + +type File implements Node @dontInfer { + sourceInstanceName: String! + absolutePath: String! + relativePath: String! + extension: String! + size: Int! + prettySize: String! + modifiedTime: Date! @dateformat + accessTime: Date! @dateformat + changeTime: Date! @dateformat + birthTime: Date! @dateformat + root: String! + dir: String! + base: String! + ext: String! + name: String! + relativeDirectory: String! + dev: Int! + mode: Int! + nlink: Int! + uid: Int! + gid: Int! + rdev: Int! + ino: Float! + atimeMs: Float! + mtimeMs: Float! + ctimeMs: Float! + atime: Date! @dateformat + mtime: Date! @dateformat + ctime: Date! @dateformat + birthtime: Date @deprecated(reason: "Use `birthTime` instead") + birthtimeMs: Float @deprecated(reason: "Use `birthTime` instead") +} + +type Directory implements Node @dontInfer { + sourceInstanceName: String! + absolutePath: String! + relativePath: String! + extension: String! + size: Int! + prettySize: String! + modifiedTime: Date! @dateformat + accessTime: Date! @dateformat + changeTime: Date! @dateformat + birthTime: Date! @dateformat + root: String! + dir: String! + base: String! + ext: String! + name: String! + relativeDirectory: String! + dev: Int! + mode: Int! + nlink: Int! + uid: Int! + gid: Int! + rdev: Int! + ino: Float! + atimeMs: Float! + mtimeMs: Float! + ctimeMs: Float! + atime: Date! @dateformat + mtime: Date! @dateformat + ctime: Date! @dateformat + birthtime: Date @deprecated(reason: "Use `birthTime` instead") + birthtimeMs: Float @deprecated(reason: "Use `birthTime` instead") +} + +type Site implements Node @dontInfer { + buildTime: Date @dateformat + siteMetadata: SiteSiteMetadata + polyfill: Boolean + pathPrefix: String +} + +type SiteSiteMetadata { + title: String + description: String +} + +type SiteFunction implements Node @dontInfer { + apiRoute: String! + originalFilePath: String! + relativeCompiledFilePath: String! + absoluteCompiledFilePath: String! + matchPath: String +} + +type SitePage implements Node @dontInfer { + path: String! + component: String! + internalComponentName: String! + componentChunkName: String! + matchPath: String +} + +type MarkdownHeading { + id: String + value: String + depth: Int +} + +enum MarkdownHeadingLevels { + h1 + h2 + h3 + h4 + h5 + h6 +} + +enum MarkdownExcerptFormats { + PLAIN + HTML + MARKDOWN +} + +type MarkdownWordCount { + paragraphs: Int + sentences: Int + words: Int +} + +type MarkdownRemark implements Node @childOf(mimeTypes: ["text/markdown", "text/x-markdown"], types: ["contentfulTextLongPlainTextNode", "contentfulTextLongMarkdownTextNode"]) @derivedTypes @dontInfer { + frontmatter: MarkdownRemarkFrontmatter + excerpt: String + rawMarkdownBody: String +} + +type MarkdownRemarkFrontmatter { + title: String +} + +interface ContentfulEntry implements Node { + contentful_id: String! + id: ID! + node_locale: String! +} + +interface ContentfulReference { + contentful_id: String! + id: ID! +} + +type ContentfulAsset implements ContentfulReference & Node @derivedTypes @dontInfer { + contentful_id: String! + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + file: ContentfulAssetFile + title: String + description: String + node_locale: String + sys: ContentfulAssetSys +} + +type ContentfulAssetFile @derivedTypes { + url: String + details: ContentfulAssetFileDetails + fileName: String + contentType: String +} + +type ContentfulAssetFileDetails @derivedTypes { + size: Int + image: ContentfulAssetFileDetailsImage +} + +type ContentfulAssetFileDetailsImage { + width: Int + height: Int +} + +type ContentfulAssetSys { + type: String + revision: Int +} + +type ContentfulNumber implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + integer: Int + content_reference: [ContentfulContentReference] @link(by: "id", from: "content reference___NODE") @proxy(from: "content reference___NODE") + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulNumberSys + decimal: Float +} + +type ContentfulContentReference implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + one: ContentfulContentReferenceContentfulTextUnion @link(by: "id", from: "one___NODE") + content_reference: [ContentfulContentReference] @link(by: "id", from: "content reference___NODE") @proxy(from: "content reference___NODE") + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulContentReferenceSys + many: [ContentfulContentReferenceContentfulNumberContentfulTextUnion] @link(by: "id", from: "many___NODE") +} + +union ContentfulContentReferenceContentfulTextUnion = ContentfulContentReference | ContentfulText + +type ContentfulContentReferenceSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulContentReferenceSysContentType +} + +type ContentfulContentReferenceSysContentType @derivedTypes { + sys: ContentfulContentReferenceSysContentTypeSys +} + +type ContentfulContentReferenceSysContentTypeSys { + type: String + linkType: String + id: String +} + +union ContentfulContentReferenceContentfulNumberContentfulTextUnion = ContentfulContentReference | ContentfulNumber | ContentfulText + +type ContentfulNumberSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulNumberSysContentType +} + +type ContentfulNumberSysContentType @derivedTypes { + sys: ContentfulNumberSysContentTypeSys +} + +type ContentfulNumberSysContentTypeSys { + type: String + linkType: String + id: String +} + +type ContentfulText implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + longMarkdown: contentfulTextLongMarkdownTextNode @link(by: "id", from: "longMarkdown___NODE") + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulTextSys + longPlain: contentfulTextLongPlainTextNode @link(by: "id", from: "longPlain___NODE") + short: String + content_reference: [ContentfulContentReference] @link(by: "id", from: "content reference___NODE") @proxy(from: "content reference___NODE") + shortList: [String] +} + +type contentfulTextLongMarkdownTextNode implements Node @derivedTypes @childOf(types: ["ContentfulText"]) @dontInfer { + longMarkdown: String + sys: contentfulTextLongMarkdownTextNodeSys +} + +type contentfulTextLongMarkdownTextNodeSys { + type: String +} + +type ContentfulTextSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulTextSysContentType +} + +type ContentfulTextSysContentType @derivedTypes { + sys: ContentfulTextSysContentTypeSys +} + +type ContentfulTextSysContentTypeSys { + type: String + linkType: String + id: String +} + +type contentfulTextLongPlainTextNode implements Node @derivedTypes @childOf(types: ["ContentfulText"]) @dontInfer { + longPlain: String + sys: contentfulTextLongPlainTextNodeSys +} + +type contentfulTextLongPlainTextNodeSys { + type: String +} + +type ContentfulMediaReference implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + many: [ContentfulAsset] @link(by: "id", from: "many___NODE") + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulMediaReferenceSys + one: ContentfulAsset @link(by: "id", from: "one___NODE") +} + +type ContentfulMediaReferenceSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulMediaReferenceSysContentType +} + +type ContentfulMediaReferenceSysContentType @derivedTypes { + sys: ContentfulMediaReferenceSysContentTypeSys +} + +type ContentfulMediaReferenceSysContentTypeSys { + type: String + linkType: String + id: String +} + +type ContentfulBoolean implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulBooleanSys + boolean: Boolean +} + +type ContentfulBooleanSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulBooleanSysContentType +} + +type ContentfulBooleanSysContentType @derivedTypes { + sys: ContentfulBooleanSysContentTypeSys +} + +type ContentfulBooleanSysContentTypeSys { + type: String + linkType: String + id: String +} + +type ContentfulDate implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + dateTime: Date @dateformat + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulDateSys + dateTimeTimezone: Date @dateformat + date: Date @dateformat +} + +type ContentfulDateSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulDateSysContentType +} + +type ContentfulDateSysContentType @derivedTypes { + sys: ContentfulDateSysContentTypeSys +} + +type ContentfulDateSysContentTypeSys { + type: String + linkType: String + id: String +} + +type ContentfulLocation implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + location: ContentfulLocationLocation + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulLocationSys +} + +type ContentfulLocationLocation { + lat: Float + lon: Float +} + +type ContentfulLocationSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulLocationSysContentType +} + +type ContentfulLocationSysContentType @derivedTypes { + sys: ContentfulLocationSysContentTypeSys +} + +type ContentfulLocationSysContentTypeSys { + type: String + linkType: String + id: String +} + +type ContentfulJson implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + json: contentfulJsonJsonJsonNode @link(by: "id", from: "json___NODE") + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulJsonSys +} + +type contentfulJsonJsonJsonNode implements Node @derivedTypes @childOf(types: ["ContentfulJson"]) @dontInfer { + Actors: [contentfulJsonJsonJsonNodeActors] + sys: contentfulJsonJsonJsonNodeSys + name: String + age: Int + city: String +} + +type contentfulJsonJsonJsonNodeActors { + name: String + age: Int + Born_At: String @proxy(from: "Born At") + Birthdate: String + photo: String + wife: String + weight: Float + hasChildren: Boolean + hasGreyHair: Boolean + children: [String] +} + +type contentfulJsonJsonJsonNodeSys { + type: String +} + +type ContentfulJsonSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulJsonSysContentType +} + +type ContentfulJsonSysContentType @derivedTypes { + sys: ContentfulJsonSysContentTypeSys +} + +type ContentfulJsonSysContentTypeSys { + type: String + linkType: String + id: String +} + +type ContentfulRichText implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { + contentful_id: String! + node_locale: String! + title: String + richText: ContentfulRichTextRichText + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + sys: ContentfulRichTextSys +} + +type ContentfulRichTextRichText { + raw: String + references: [ContentfulAssetContentfulContentReferenceContentfulLocationContentfulTextUnion] @link(by: "id", from: "references___NODE") +} + +union ContentfulAssetContentfulContentReferenceContentfulLocationContentfulTextUnion = ContentfulAsset | ContentfulContentReference | ContentfulLocation | ContentfulText + +type ContentfulRichTextSys @derivedTypes { + type: String + revision: Int + contentType: ContentfulRichTextSysContentType +} + +type ContentfulRichTextSysContentType @derivedTypes { + sys: ContentfulRichTextSysContentTypeSys +} + +type ContentfulRichTextSysContentTypeSys { + type: String + linkType: String + id: String +} + +type ContentfulContentType implements Node @derivedTypes @dontInfer { + name: String + displayField: String + description: String + sys: ContentfulContentTypeSys +} + +type ContentfulContentTypeSys { + type: String +} \ No newline at end of file