diff --git a/docs/docs/tutorial/part-4/index.mdx b/docs/docs/tutorial/part-4/index.mdx index 28dfe6e5950e2..2c2b0053e49ba 100644 --- a/docs/docs/tutorial/part-4/index.mdx +++ b/docs/docs/tutorial/part-4/index.mdx @@ -2,7 +2,7 @@ title: "Part 4: Query for Data with GraphQL" --- -import { Announcement, Notification } from 'gatsby-interface' +import { Announcement, Notification, LinkButton } from 'gatsby-interface' import Collapsible from '@components/collapsible' import { MdInfo } from 'react-icons/md' @@ -909,24 +909,10 @@ Use the "Was this doc helpful to you?" form at the bottom of this page to let us In Part 5, you'll add some content to your blog posts using a special format called MDX. You'll also learn about transformer plugins, which you can use to convert data in your data layer from one type to another. -} variant="SECONDARY" - content={ -
-

- Note: We{"'"}re still working on updating this Tutorial to use Gatsby v3. - You've reached the end of the new content we've released so far. Subsequent parts - will be added as we finish them. -

-

- If you{"'"}re looking for a full experience in the meantime, you can check out the (slightly outdated){" "} - - Gatsby v2 Tutorial - - . -

-
- } -/> +> + Continue to Part 5 + diff --git a/docs/docs/tutorial/part-5/blog-page-with-frontmatter.png b/docs/docs/tutorial/part-5/blog-page-with-frontmatter.png new file mode 100644 index 0000000000000..7653ad9e4e4d9 Binary files /dev/null and b/docs/docs/tutorial/part-5/blog-page-with-frontmatter.png differ diff --git a/docs/docs/tutorial/part-5/blog-page-with-full-posts.png b/docs/docs/tutorial/part-5/blog-page-with-full-posts.png new file mode 100644 index 0000000000000..6b75dbd155b11 Binary files /dev/null and b/docs/docs/tutorial/part-5/blog-page-with-full-posts.png differ diff --git a/docs/docs/tutorial/part-5/data-layer-with-nodes.png b/docs/docs/tutorial/part-5/data-layer-with-nodes.png new file mode 100644 index 0000000000000..e3629387f3477 Binary files /dev/null and b/docs/docs/tutorial/part-5/data-layer-with-nodes.png differ diff --git a/docs/docs/tutorial/part-5/index.mdx b/docs/docs/tutorial/part-5/index.mdx new file mode 100644 index 0000000000000..d61f7dbdd2277 --- /dev/null +++ b/docs/docs/tutorial/part-5/index.mdx @@ -0,0 +1,660 @@ +--- +title: "Part 5: Transform data to use MDX" +--- + +import { Announcement, Notification } from 'gatsby-interface' +import Collapsible from '@components/collapsible' +import { MdInfo } from 'react-icons/md' + + +

+ Note: We{"'"}re still working on updating this Tutorial to use Gatsby v3. + The first few parts of the new Tutorial have been released here, and subsequent parts + will be added as we finish them. +

+

+ If you{"'"}re looking for a full experience in the meantime, you can check out the (slightly outdated){" "} + + Gatsby v2 Tutorial + + . +

+ + } +/> + +## Introduction + +In [Part 4](/docs/tutorial/part-4/), you used the `gatsby-source-filesystem` source plugin to build a Blog page that lists the names of your blog post files. But you weren't able to actually render the contents of your post files, because `gatsby-source-filesystem` doesn't provide a field for it. To do that, you'll need another type of plugin called a **transformer plugin**. + +Sometimes, the format of the data you get from source plugins isn’t exactly what you want to use to build your website. For example, the filesystem source plugin lets you query data *about* files, but it doesn't let you use the data *inside* the files themselves. To make this possible, Gatsby supports transformer plugins, which take the raw content from source plugins and transform it into something more usable. + +In this part of the Tutorial, you'll learn about one particular transformer plugin, `gatsby-plugin-mdx`, which lets you use [MDX](https://mdxjs.com/), a file format that allows Markdown and JSX alongside your text content. (Fun fact: this Tutorial is actually written in MDX!) You'll use MDX to add some content to your blog post files, and then you'll use `gatsby-plugin-mdx` to render the contents of your posts on your Blog page. + + + +**Note:** Usually, transformer plugin names start with `gatsby-transformer-`. (`gatsby-plugin-mdx` is one exception to this convention.) + +To see a list of other transformer plugins, try searching for `gatsby-transformer-` in the [Gatsby Plugin Library](/plugins/). + + + +By the end of this part of the Tutorial, you will be able to: + +- Write an MDX file with Markdown formatting and frontmatter. +- Use the `gatsby-plugin-mdx` plugin to render the contents of your MDX files on your Blog page. +- Use the `sort` field to control the order of results in your GraphQL queries. + +## A closer look at Gatsby's GraphQL data layer + +To understand how `gatsby-plugin-mdx` and other transformer plugins work, you need to know a bit more about how Gatsby’s GraphQL data layer works. + +Inside the data layer, information is stored in objects called **nodes**. A node is the smallest form unit of data in the data layer. Different source plugins create different types of nodes, each of which have their own properties. For example, `gatsby-source-filesystem` creates File nodes. + +A **transformer plugin** converts nodes from one type to another. For example, the `gatsby-plugin-mdx` plugin transforms File nodes that have the `.mdx` extension into MDX nodes, which have a different set of fields that you can query using GraphQL. Transformer plugins let you manipulate the raw data in the nodes created by source plugins, so that you can get it into the structure or format you need. + +![The gatsby-source-filesystem plugin pulls data from your local filesystem into Gatsby's GraphQL data layer as File nodes. Then the gatsby-plugin-mdx transformer plugin uses those File nodes to create new MDX nodes. Finally, you can use GraphQL queries to pull data from the MDX nodes into your components.](./data-layer-with-nodes.png) + + + +**Note:** Even though it's called a transformer plugin, it's not actually *changing* the original nodes created by the source plugins. Each transformer plugin creates new nodes based on the data from the sourced nodes, but it doesn't actually change the source nodes themselves. So even though `gatsby-plugin-mdx` creates new MDX nodes in the data layer, you can still access the original File nodes created by `gatsby-source-filesystem`. + + + +In this part of the Tutorial, you'll learn how to use a transformer plugin to create MDX nodes from your File nodes. + +## Add some MDX content to your blog posts + +In Part 4, you created empty files for your blog posts. Now, it's time to fill them in! + +Using Markdown formatting in MDX} +> + +MDX files let you format text using Markdown, a markup language that uses a special syntax to add special formatting to your text elements. For example, you can make text appear **strong** by wrapping it in `**double asterisks**`, or you can create a link by using a syntax like `[text to link](url)`. + +Once you get used to what all the different symbols mean, Markdown can be easier to read than HTML, which makes it a popular format for written content like blog posts. + + + +**New to Markdown?** The MDX documentation includes a [table of components](https://mdxjs.com/table-of-components) that shows the different formatting options available. It includes things like headings, blockquotes, lists, and code blocks. + + + +#### Frontmatter + +With `gatsby-plugin-mdx`, you can also add **frontmatter** to your MDX files. Frontmatter is additional metadata about your file. It won't be rendered on your page, but it's a way for you to add some extra details about your content. For example, you might store your post title or the date it was published. + +To add frontmatter to your post, put it between an opening and closing set of three hyphens (`---`) at the top of your MDX file. Within the opening and closing hyphens, you can create key-value pairs for any kind of data you want to store about your file. + +Here's an example: + +```mdx +--- +name: "Fun Facts about Red Pandas" +datePublished: "2021-07-12" +author: "#1 Red Panda Fan" +--- +``` + +You'll learn more about how to access the frontmatter for your posts later on. + + + +Add some Markdown content to each of the `.mdx` files you created in your `/blog` directory in Part 4. + +Include frontmatter with fields for the title of each post and the date it was published. (Give each post a different date, to make it easier to add sorting later on.) After the frontmatter, write some post content using some Markdown syntax. + +Here are some example posts that you can use for inspiration: + +```mdx:title=blog/my-first-post.mdx +--- +title: "My First Post" +date: "2021-07-23" +--- + +This is my first blog post! Isn't it *great*? + +Some of my **favorite** things are: + +* Petting dogs +* Singing +* Eating potato-based foods +``` + +```mdx:title=blog/another-post.mdx +--- +title: "Another Post" +date: "2021-07-24" +--- + +Here's another post! It's even better than the first one! +``` + +```mdx:title=blog/yet-another-post.mdx +--- +title: "Yet Another Post" +date: "2021-07-25" +--- + +Wow look at all this content. How do they do it? +``` + +## Render each post's contents on the Blog page + +Now that you have some MDX content inside your blog posts, it's time set up the `gatsby-plugin-mdx` transformer plugin. + + + + +**Quick Refresher:** Remember the process for adding a plugin to your site (from [Part 3](/docs/tutorial/part-3/))? See if you can remember the three steps from memory before checking your answer. (Science has shown that the act of trying to [actively recall information](https://www.cultofpedagogy.com/retrieval-practice/) helps you retain it better!) + + + +The `gatsby-plugin-mdx` plugin provides some new tools for you to use in your site: + +* The `allMdx` and `mdx` fields (for your GraphQL queries) +* An `MDXRenderer` component (for processing and displaying MDX content) + +To render your posts on the Blog page, you'll complete a few different steps: + +1. Install and configure the `gatsby-plugin-mdx` transformer plugin and its dependencies. +2. Update the Blog page query to use the `allMdx` field from `gatsby-plugin-mdx` instead of `allFile`. +3. Use the `MDXRenderer` component from `gatsby-plugin-mdx` to render your post's MDX contents in the JSX for your Blog page. + + +### Task: Install and configure the MDX transformer plugin (and dependencies) + +The `gatsby-plugin-mdx` package requires a few additional dependencies to run: `@mdx-js/mdx` (which implements MDX) and `@mdx-js/react` (which maps the MDX implementation to React components). + +1. In your terminal, run the command below to install `gatsby-plugin-mdx` and its dependencies. (This adds all three packages to the `dependencies` object in your `package.json` file and to your `node_modules` directory.) + ```shell + npm install gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react + ``` + +2. Add `gatsby-plugin-mdx` to the `plugins` array in your `gatsby-config.js` file, so that Gatsby knows to use the plugin when building your site. + ```js:title=gatsby-config.js + module.exports = { + siteMetadata: { + title: "My Super Cool Blog", + }, + plugins: [ + "gatsby-plugin-gatsby-cloud", + "gatsby-plugin-image", + "gatsby-plugin-sharp", + { + resolve: `gatsby-source-filesystem`, + options: { + name: `blog`, + path: `${__dirname}/blog/`, + }, + }, + "gatsby-plugin-mdx", // highlight-line + ], + }; + ``` + + + +**Tip:** There are a variety of [remark](https://remark.js.org/) plugins that you can use to add extra features to your Markdown. You can configure them using the [`gatsbyRemarkPlugins`](/plugins/gatsby-plugin-mdx/#gatsby-remark-plugins) option when you configure `gatsby-plugin-mdx` in your `gatsby-config.js` file. + +Here are some popular remark plugins: + +* [`gatsby-remark-images`](/plugins/gatsby-remark-images/): Use this if you want to generate responsive images when using the Markdown image syntax (which looks like this: `![alt](image url)`). + * To use this plugin, you'll also need `gatsby-plugin-sharp`, which you installed already in Part 3. +* [`gatsby-remark-prismjs`](/plugins/gatsby-remark-prismjs/): Add syntax highlighting to your code blocks. +* [`gatsby-remark-autolink-headers`](/plugins/gatsby-remark-autolink-headers/): Automatically create links for all the headers in your Markdown content. + +Try searching for `gatsby-remark-` in the [Gatsby Plugin Library](/plugins/) for a full list. + + + +### Task: Update the Blog page query to use the `allMdx` field instead of `allFile` + +The `gatsby-plugin-mdx` plugin makes two new fields available for you to use in your GraphQL queries: `allMdx` and `mdx`. In this part of the Tutorial, you'll use `allMdx` to add the contents of each blog post to your Blog page. (You'll use the `mdx` field later on, in Part 6.) + +You can use the `allMdx` field to request data for multiple MDX nodes at once (similar to the way `allFile` worked with File nodes). Open GraphiQL and explore what fields are available on MDX nodes. Try running a few queries to see what kind of information you get back. + + + +**Quick Refresher:** Remember how to access GraphiQL? See if you can remember the steps before checking for the answer in Part 4. (Check the section called ["Use GraphiQL to explore the data layer and write GraphQL queries"](/docs/tutorial/part-4/#use-graphiql-to-explore-the-data-layer-and-write-graphql-queries)). + + + +Use GraphiQL to create a new query that gets data about your blog posts using the `allMdx` field instead of the `allFile` field. + +1. Under `allMdx`, open the `nodes` dropdown. Inside the `frontmatter` dropdown, you should see fields for all the keys you created in the frontmatter of your MDX files. Select the `title` and `date` fields. You can use the `formatString` argument on the `date` field to change the way your dates are displayed (see Syntax Hint below). + ```graphql + query MyQuery { + allMdx { + nodes { + frontmatter { + date(formatString: "MMMM D, YYYY") + title + } + } + } + } + ``` + + + +**Syntax Hint:** When it comes to using dates in your frontmatter, the `formatString` argument is a helpful tool for changing the way the date is displayed. + +Imagine you have a key in your frontmatter with a value that uses a date format like `"YYYY-MM-DD"`. (It doesn't matter what you name the key, as long as the value has the required format.) GraphiQL will automatically detect that your value is a date, and when you select the corresponding frontmatter field in the Explorer pane, GraphiQL will automatically show a few arguments that you can pass to that field. One of those arguments is called `formatString`, which you can pass a [Moment.js formatting token](https://momentjs.com/docs/#/displaying/format/) to change the way the date displays. + +For example, if your MDX frontmatter looks like this: + +```mdx +--- +date: "2021-07-23" +--- +``` + +...and your GraphQL query looks like this: + +```graphql +query MyQuery { + allMdx { + nodes { + frontmatter { + date(formatString: "MMMM D, YYYY") + } + } + } +} +``` + +...then the dates in your response will look like this: `"July 23, 2021"`. + + + +2. While you're at it, add the `id` field, which is a unique string that Gatsby automatically adds to every node in the data layer. (You'll use this as a React `key` later on, when you iterate over your list of posts.) + ```graphql + query MyQuery { + allMdx { + nodes { + frontmatter { + date(formatString: "MMMM D, YYYY") + title + } + id + } + } + } + ``` + +3. Execute your query by clicking the triangle button. Your response object should look something like this: + ```json + { + "data": { + "allMdx": { + "nodes": [ + { + "frontmatter": { + "date": "July 25, 2021", + "title": "Yet Another Post" + }, + "id": "c4b5ae6d-f3ad-5ea4-ab54-b08a72badea1" + }, + { + "frontmatter": { + "date": "July 23, 2021", + "title": "My First Post" + }, + "id": "11b3a825-30c5-551d-a713-dd748e7d554a" + }, + { + "frontmatter": { + "date": "July 24, 2021", + "title": "Another Post" + }, + "id": "560896e4-0148-59b8-9a2b-bf79bee68fba" + } + ] + } + }, + "extensions": {} + } + ``` + +4. You might notice that your posts aren't listed in order. Most blog sites list their posts in reverse-chronological order, so that the newest posts are listed first. You can sort the data nodes in your response by using the `sort` argument on the `allMdx` field. + * In the Explorer pane, toggle the `sort` dropdown underneath the `allMdx` field. + * Under `sort`, check the `fields` argument, and use the dropdown to select which field you want to sort your data nodes by. In this case, that would be `frontmatter___date` (with three underscores). + * Check the `order` argument, and use the dropdown to select `DESC`. This will sort the nodes in descending order, so that the newest posts come first. + ```graphql + query MyQuery { + allMdx(sort: {fields: frontmatter___date, order: DESC}) { + nodes { + frontmatter { + date(formatString: "MMMM D, YYYY") + title + } + id + } + } + } + ``` + +5. Run your query again to verify that the posts come back in the correct order. Your response should look something like this: + ```json + { + "data": { + "allMdx": { + "nodes": [ + { + "frontmatter": { + "date": "July 25, 2021", + "title": "Yet Another Post" + }, + "id": "c4b5ae6d-f3ad-5ea4-ab54-b08a72badea1" + }, + { + "frontmatter": { + "date": "July 24, 2021", + "title": "Another Post" + }, + "id": "560896e4-0148-59b8-9a2b-bf79bee68fba" + }, + { + "frontmatter": { + "date": "July 23, 2021", + "title": "My First Post" + }, + "id": "11b3a825-30c5-551d-a713-dd748e7d554a" + } + ] + } + }, + "extensions": {} + } + ``` + +6. The last thing you need to add to your query is the contents of each post! To do that, add the `body` field to your query. + ```graphql + query MyQuery { + allMdx(sort: {fields: frontmatter___date, order: DESC}) { + nodes { + frontmatter { + date(formatString: "MMMM D, YYYY") + title + } + id + body + } + } + } + ``` + +7. When you run your query, the `body` field for each node should look something like the data shown below. That's a lot of information! The `body` field actually contains the *compiled MDX content* for your file. It might not be readable for humans, but it's the format that the `MDXRenderer` component understands. (You'll get to `MDXRenderer` in a moment.) + ```json + "body": "var _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n \"title\": \"Yet Another Post\",\n \"date\": \"2021-07-25\"\n};\nvar layoutProps = {\n _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n var components = _ref.components,\n props = _objectWithoutProperties(_ref, _excluded);\n\n return mdx(MDXLayout, _extends({}, layoutProps, props, {\n components: components,\n mdxType: \"MDXLayout\"\n }), mdx(\"p\", null, \"Wow look at all this content. How do they do it?\"));\n}\n;\nMDXContent.isMDXComponent = true;" + ``` + +Now that you have your GraphQL query all set up, it's time to tackle the last piece of the puzzle: rendering your posts in the Blog page. + + + +**Pro Tip:** When transformer plugins create a new node, they add a `parent` field that references back to the original source node it was created from. For example, when `gatsby-plugin-mdx` creates new MDX nodes, it adds a `parent` field which you can use to access data from the original File node. + +Using the `parent` node can come in handy if you want to use data from the transformed nodes along with data from the original source nodes. For example, the query below gives you back the time a file was changed, which you could use to display when a post was last updated. + +```graphql +query MyQuery { + allMdx { + nodes { + parent { + ... on File { + modifiedTime(formatString: "MMMM D, YYYY") + } + } + } + } +} +``` + + + + +### Task: Use the `MDXRenderer` component to render your post's contents in your Blog page + +Now that your GraphQL query is all set up, it's time to replace the page query in your Blog page component. + +1. Start by swapping out the `allFile` page query in your Blog page for the one you just created using `allMdx`. (Don't forget to delete the query name!) + ```js:title=src/pages/blog.js + // imports + + const BlogPage = ({ data }) => { + return ( + // ... + ) + } + + // highlight-start + export const query = graphql` + query { + allMdx(sort: {fields: frontmatter___date, order: DESC}) { + nodes { + frontmatter { + date(formatString: "MMMM D, YYYY") + title + } + id + body + } + } + } + ` + // highlight-end + + export default BlogPage + ``` + +2. Next, update the JSX for your Blog page to use the data fields of your response. Start by rendering just the title and date for each post. + * Now that you're rendering more than just a filename, it makes more sense to use the [`
`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article) semantic HTML element instead of a `
    ` and nested `
  • ` elements. + * You can also use the `id` field as your unique `key` prop for each post. (React uses the `key` prop to keep track of what elements need to be re-rendered. If you don't include it, you'll get a warning in your browser console. For more on the `key` prop, check out the [React Docs: List and Keys](https://reactjs.org/docs/lists-and-keys.html#keys).) + ```js:title=src/pages/blog.js + // imports + + const BlogPage = ({ data }) => { + return ( + + {/* highlight-start */} + { + data.allMdx.nodes.map((node) => ( +
    +

    {node.frontmatter.title}

    +

    Posted: {node.frontmatter.date}

    +
    + )) + } + {/* highlight-end */} +
    + ) + } + + export const query = graphql` + query { + allMdx(sort: {fields: frontmatter___date, order: DESC}) { + nodes { + frontmatter { + title + date(formatString: "MMMM DD, YYYY") + } + id + body + } + } + } + ` + + export default BlogPage + ``` + +3. Go to `localhost:8000/blog` in your web browser. You should be able to see the titles and dates for each of your posts: + +![A screenshot of the Blog page in a web browser. Underneath the page heading, there are three posts listed: "Yet Another Post" (posted July 25, 2021), "Another Post" (posted July 24, 2021), and "My First Post" (posted July 23, 2021).](./blog-page-with-frontmatter.png) + +4. The final step in this part of the Tutorial is to render the actual contents of your MDX blog posts. To do that, you'll need to use a component from `gatsby-plugin-mdx` called `MDXRenderer`. Start by importing the component into your Blog page: + +```js:title=src/pages/blog.js +import * as React from 'react' +import { graphql } from 'gatsby' +import { MDXRenderer } from 'gatsby-plugin-mdx' // highlight-line +import Layout from '../components/layout' + +// ... +``` + +The MDXRenderer component} +> + +`MDXRenderer` is a component included in the `gatsby-plugin-mdx` plugin that you can use to render the contents of a `.mdx` file. + +The `MDXRenderer` uses the `children` prop, similar to the `Layout` component you created in [Part 2](/docs/tutorial/part-2/). It expects to receive compiled MDX between the its opening and closing tags. You can pass in the `body` field from an MDX node. + + + +**Quick Refresher:** Need a reminder of how the `children` prop works? Refer back to the ["Create a reusable layout component" section in Part 2](/docs/tutorial/part-2/#create-a-reusable-layout-component). + + + +Here's a quick example of how to import and use the `MDXRenderer` component: + +```js +import { MDXRenderer } from 'gatsby-plugin-mdx' + +// Use this in the JSX for your component + + { node.body } + +``` + + + +5. In the JSX for your Blog page, use the `MDXRenderer` component to wrap the contents of the `body` field for each node: + +```js:title=src/pages/blog.js +import * as React from 'react' +import { graphql } from 'gatsby' +import { MDXRenderer } from 'gatsby-plugin-mdx' +import Layout from '../components/layout' + +const BlogPage = ({ data }) => { + return ( + + { + data.allMdx.nodes.map((node) => ( +
    +

    {node.frontmatter.title}

    +

    Posted: {node.frontmatter.date}

    + {/* highlight-start */} + + {node.body} + + {/* highlight-end */} +
    + )) + } +
    + ) +} + +export const query = graphql` + query { + allMdx(sort: {fields: frontmatter___date, order: DESC}) { + nodes { + frontmatter { + title + date(formatString: "MMMM DD, YYYY") + } + id + body + } + } + } +` + +export default BlogPage +``` + +6. When you refresh your Blog page in the web browser, you should see your post contents rendered! + ![A screenshot of the Blog page in a web browser. Now, underneath the date for each post, the contents of the blog post are also being rendered.](./blog-page-with-full-posts.png) + +Nice work! Your site now has a blog page with actual content. + +## Summary + +Take a moment to think back on what you've learned so far. Challenge yourself to answer the following questions from memory: + +* What is a transformer plugin? How do transformer plugins affect the data in the data layer? +* What is MDX? Why is it useful? + + + +**Ship It!** 🚀 + +Before you move on, deploy your changes to your live site on Gatsby Cloud so that you can share your progress! + +First, run the following commands in a terminal to push your changes to your GitHub repository. (Make sure you're in the top-level directory for your Gatsby site!) + +```shell +git add . +git commit -m "Finished Gatsby Tutorial Part 5" +git push +``` + +Once your changes have been pushed to GitHub, Gatsby Cloud should notice the update and rebuild and deploy the latest version of your site. (It may take a few minutes for your changes to be reflected on the live site. Watch your build's progress from your [Gatsby Cloud dashboard](/dashboard/).) + + + +### Key takeaways + +* Data in Gatsby's GraphQL data layer is stored in **nodes**. +* Each source plugin creates a different type of node with different fields. +* Transformer plugins create new types of nodes, using data from existing source nodes as a starting point. Transformer plugins don't actually change the original source nodes. +* `gatsby-plugin-mdx` is a transformer plugin that lets you use MDX in your site. With MDX, you can create text content with Markdown formatting and embedded React components. + + + +**Share Your Feedback!** + +Our goal is for this Tutorial to be helpful and easy to follow. We'd love to hear your feedback about what you liked or didn't like about this part of the Tutorial. + +Use the "Was this doc helpful to you?" form at the bottom of this page to let us know what worked well and what we can improve. + + + +### What's coming next? + +Right now, all your blog posts and their contents are being rendered in one long page. It would be better if each post lived on its own page, and then the Blog page could link out to all the different posts. + +In Part 6, you'll learn how to use Gatsby's filesystem route API to dynamically create new pages for each of your blog posts. + + +

    + Note: We{"'"}re still working on updating this Tutorial to use Gatsby v3. + You've reached the end of the new content we've released so far. Subsequent parts + will be added as we finish them. Part 6 has a tentative release date of July 28, 2021. +

    +

    + If you{"'"}re looking for a full experience in the meantime, you can check out the (slightly outdated){" "} + + Gatsby v2 Tutorial + + . +

    + + } +/> diff --git a/docs/docs/tutorial/part-five/allfile-query.png b/docs/docs/tutorial/part-five/allfile-query.png deleted file mode 100644 index d0a457b47b1fc..0000000000000 Binary files a/docs/docs/tutorial/part-five/allfile-query.png and /dev/null differ diff --git a/docs/docs/tutorial/part-five/data-in-console.png b/docs/docs/tutorial/part-five/data-in-console.png deleted file mode 100644 index 7ece96f81420d..0000000000000 Binary files a/docs/docs/tutorial/part-five/data-in-console.png and /dev/null differ diff --git a/docs/docs/tutorial/part-five/filesystem-autocomplete.png b/docs/docs/tutorial/part-five/filesystem-autocomplete.png deleted file mode 100644 index f91668c1ba023..0000000000000 Binary files a/docs/docs/tutorial/part-five/filesystem-autocomplete.png and /dev/null differ diff --git a/docs/docs/tutorial/part-five/filesystem-explorer-options.png b/docs/docs/tutorial/part-five/filesystem-explorer-options.png deleted file mode 100644 index a4811a1d1474d..0000000000000 Binary files a/docs/docs/tutorial/part-five/filesystem-explorer-options.png and /dev/null differ diff --git a/docs/docs/tutorial/part-five/filesystem-query.png b/docs/docs/tutorial/part-five/filesystem-query.png deleted file mode 100644 index b6604116721da..0000000000000 Binary files a/docs/docs/tutorial/part-five/filesystem-query.png and /dev/null differ diff --git a/docs/docs/tutorial/part-five/graphiql-filesystem.png b/docs/docs/tutorial/part-five/graphiql-filesystem.png deleted file mode 100644 index b775e213b8f8c..0000000000000 Binary files a/docs/docs/tutorial/part-five/graphiql-filesystem.png and /dev/null differ diff --git a/docs/docs/tutorial/part-five/index.md b/docs/docs/tutorial/part-five/index.md deleted file mode 100644 index 5cafcfa3883ba..0000000000000 --- a/docs/docs/tutorial/part-five/index.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -title: Source Plugins -typora-copy-images-to: ./ -disableTableOfContents: true ---- - -> This tutorial is part of a series about Gatsby’s data layer. Make sure you’ve gone through [part 4](/docs/tutorial/part-four/) before continuing here. - -## What's in this tutorial? - -In this tutorial, you'll be learning about how to pull data into your Gatsby site using GraphQL and source plugins. Before you learn about these plugins, however, you'll want to know how to use something called GraphiQL, a tool that helps you structure your queries correctly. - -## Introducing GraphiQL - -GraphiQL is the GraphQL integrated development environment (IDE). It's a powerful (and all-around awesome) tool you'll use often while building Gatsby websites. - -You can access it when your site's development server is running—normally at `http://localhost:8000/___graphql`. - - - -Poke around the built-in `Site` "type" and see what fields are available on it -- including the `siteMetadata` object you queried earlier. Try opening GraphiQL and play with your data! Press Ctrl + Space (or use Shift + Space as an alternate keyboard shortcut) to bring up the autocomplete window and Ctrl + Enter to run the GraphQL query. You'll be using GraphiQL a lot more through the remainder of the tutorial. - -## Using the GraphiQL Explorer - -The GraphiQL Explorer enables you to interactively construct full queries by clicking through available fields and inputs without the repetitive process of typing these queries out by hand. - - - -## Source plugins - -Data in Gatsby sites can come from anywhere: APIs, databases, CMSs, local files, etc. - -Source plugins fetch data from their source. E.g. the filesystem source plugin knows how to fetch data from the file system. The WordPress plugin knows how to fetch data from the WordPress API. - -Add [`gatsby-source-filesystem`](/plugins/gatsby-source-filesystem/) and explore how it works. - -First, install the plugin at the root of the project: - -```shell -npm install gatsby-source-filesystem -``` - -Then add it to your `gatsby-config.js`: - -```javascript:title=gatsby-config.js -module.exports = { - siteMetadata: { - title: `Pandas Eating Lots`, - }, - plugins: [ - // highlight-start - { - resolve: `gatsby-source-filesystem`, - options: { - name: `src`, - path: `${__dirname}/src/`, - }, - }, - // highlight-end - `gatsby-plugin-emotion`, - { - resolve: `gatsby-plugin-typography`, - options: { - pathToConfigModule: `src/utils/typography`, - }, - }, - ], -} -``` - -Save that and restart the gatsby development server. Then open up GraphiQL again. - -In the explorer pane, you'll see `allFile` and `file` available as selections: - -![The GraphiQL IDE showing the new dropdown options provided by the gatsby-source-filesystem plugin](graphiql-filesystem.png) - -Click the `allFile` dropdown. Position your cursor after `allFile` in the query area, and then type Ctrl + Enter. This will pre-fill a query for the `id` of each file. Press "Play" to run the query: - -![The GraphiQL IDE showing the results of a filesystem query](filesystem-query.png) - -In the Explorer pane, the `id` field has automatically been selected. Make selections for more fields by checking the field's corresponding checkbox. Press "Play" to run the query again, with the new fields: - -![The GraphiQL IDE showing the new fields in the Explorer column](filesystem-explorer-options.png) - -Alternatively, you can add fields by using the autocomplete shortcut (Ctrl + Space). This will show queryable fields on the `File` nodes. - -![The GraphiQL IDE showing the gatsby-source-filesystem plugin's new autocomplete options](filesystem-autocomplete.png) - -Try adding a number of fields to your query, press Ctrl + Enter each time to re-run the query. You'll see the updated query results: - -![The GraphiQL IDE showing the results of the query](allfile-query.png) - -The result is an array of `File` "nodes" (node is a fancy name for an object in a "graph"). Each `File` node object has the fields you queried for. - -## Build a page with a GraphQL query - -Building new pages with Gatsby often starts in GraphiQL. You first sketch out the data query by playing in GraphiQL then copy this to a React page component to start building the UI. - -Let's try this. - -Create a new file at `src/pages/my-files.js` with the `allFile` GraphQL query you just -created: - -```jsx:title=src/pages/my-files.js -import React from "react" -import { graphql } from "gatsby" -import Layout from "../components/layout" - -export default function MyFiles({ data }) { - console.log(data) // highlight-line - return ( - -
    Hello world
    -
    - ) -} - -export const query = graphql` - query { - allFile { - edges { - node { - relativePath - prettySize - extension - birthTime(fromNow: true) - } - } - } - } -` -``` - -The `console.log(data)` line is highlighted above. It's often helpful when creating a new component to console out the data you're getting from the GraphQL query so you can explore the data in your browser console while building the UI. - -If you visit the new page at `/my-files/` and open up your browser console you will see something like: - -![Browser console showing the structure of the data object](data-in-console.png) - -The shape of the data matches the shape of the GraphQL query. - -Add some code to your component to print out the File data. - -```jsx:title=src/pages/my-files.js -import React from "react" -import { graphql } from "gatsby" -import Layout from "../components/layout" - -export default function MyFiles({ data }) { - console.log(data) - return ( - - {/* highlight-start */} -
    -

    My Site's Files

    - - - - - - - - - - - {data.allFile.edges.map(({ node }, index) => ( - - - - - - - ))} - -
    relativePathprettySizeextensionbirthTime
    {node.relativePath}{node.prettySize}{node.extension}{node.birthTime}
    -
    - {/* highlight-end */} -
    - ) -} - -export const query = graphql` - query { - allFile { - edges { - node { - relativePath - prettySize - extension - birthTime(fromNow: true) - } - } - } - } -` -``` - -And now visit `http://localhost:8000/my-files`… 😲 - -![A browser window showing a list of the files in the site](my-files-page.png) - -## What's coming next? - -Now you've learned how source plugins bring data _into_ Gatsby’s data system. In the next tutorial, you'll learn how transformer plugins _transform_ the raw content brought by source plugins. The combination of source plugins and transformer plugins can handle all data sourcing and data transformation you might need when building a Gatsby site. Learn about transformer plugins in [part six of the tutorial](/docs/tutorial/part-six/). diff --git a/docs/docs/tutorial/part-five/my-files-page.png b/docs/docs/tutorial/part-five/my-files-page.png deleted file mode 100644 index 17467af4ca70f..0000000000000 Binary files a/docs/docs/tutorial/part-five/my-files-page.png and /dev/null differ diff --git a/docs/docs/tutorial/part-four/index.md b/docs/docs/tutorial/part-four/index.md deleted file mode 100644 index 59279f0471472..0000000000000 --- a/docs/docs/tutorial/part-four/index.md +++ /dev/null @@ -1,359 +0,0 @@ ---- -title: Data in Gatsby -typora-copy-images-to: ./ -disableTableOfContents: true ---- - -Welcome to Part Four of the tutorial! Halfway through! Hope things are starting to feel pretty comfortable 😀 - -## Recap of the first half of the tutorial - -So far, you've been learning how to use React.js—how powerful it is to be able to create your _own_ components to act as custom building blocks for websites. - -You’ve also explored styling components using CSS Modules. - -## What's in this tutorial? - -In the next four parts of the tutorial (including this one), you'll be diving into the Gatsby data layer, which is a powerful feature of Gatsby that lets you build sites from Markdown, WordPress, headless CMSs, and other data sources of all flavors. - -**NOTE:** Gatsby’s data layer is powered by GraphQL. For an in-depth tutorial on GraphQL, we recommend [How to GraphQL](https://www.howtographql.com/). - -## Data in Gatsby - -A website has four parts: HTML, CSS, JS, and data. The first half of the tutorial focused on the first three. Now let’s learn how to use data in Gatsby sites. - -**What is data?** - -A very computer science-y answer would be: data is things like `"strings"`, integers (`42`), objects (`{ pizza: true }`), etc. - -For the purpose of working in Gatsby, however, a more useful answer is "everything that lives outside a React component". - -So far, you've been writing text and adding images _directly_ in components. Which is an _excellent_ way to build many websites. But, often you want to store data _outside_ components and then bring the data _into_ the component as needed. - -If you're building a site with WordPress (so other contributors have a nice interface for adding & maintaining content) and Gatsby, the _data_ for the site (pages and posts) are in WordPress and you _pull_ that data, as needed, into your components. - -Data can also live in file types like Markdown, CSV, etc. as well as databases -and APIs of all sorts. - -**Gatsby's data layer lets you pull data from these (and any other source) directly into your components** -- in the shape and form you want. - -## Using Unstructured Data vs GraphQL - -### Do I have to use GraphQL and source plugins to pull data into Gatsby sites? - -Absolutely not! You can use the node `createPages` API to pull unstructured data into Gatsby pages directly, rather than through the GraphQL data layer. This is a great choice for small sites, while GraphQL and source plugins can help save time with more complex sites. - -See the [Using Gatsby without GraphQL](/docs/how-to/querying-data/using-gatsby-without-graphql/) guide to learn how to pull data into your Gatsby site using the node `createPages` API and to see an example site! - -### When do I use unstructured data vs GraphQL? - -If you're building a small site, one efficient way to build it is to pull in unstructured data as outlined in this guide, using `createPages` API, and then if the site becomes more complex later on, you move on to building more complex sites, or you'd like to transform your data, follow these steps: - -1. Check out the [Plugin Library](/plugins/) to see if the source plugins and/or transformer plugins you'd like to use already exist -2. If they don't exist, read the [Plugin Authoring](/docs/creating-plugins/) guide and consider building your own! - -### How Gatsby's data layer uses GraphQL to pull data into components - -There are many options for loading data into React components. One of the most popular and powerful of these is a technology called [GraphQL](https://graphql.org/). - -GraphQL was invented at Facebook to help product engineers _pull_ needed data into components. - -GraphQL is a **q**uery **l**anguage (the _QL_ part of its name). If you're familiar with SQL, it works in a very similar way. Using a special syntax, you describe the data you want in your component and then that data is given to you. - -Gatsby uses GraphQL to enable components to declare the data they need. - -## Create a new example site - -Create another new site for this part of the tutorial. You're going to build a Markdown blog called "Pandas Eating Lots". It's dedicated to showing off the best pictures and videos of pandas eating lots of food. Along the way, you'll be dipping your toes into GraphQL and Gatsby's Markdown support. - -Open a new terminal window and run the following commands to create a new Gatsby site in a directory called `tutorial-part-four`. Then navigate to the new directory: - -```shell -gatsby new tutorial-part-four https://github.com/gatsbyjs/gatsby-starter-hello-world -cd tutorial-part-four -``` - -Then install some other needed dependencies at the root of the project. You'll use the Typography theme "Kirkham", and you'll try out a CSS-in-JS library, ["Emotion"](https://emotion.sh/): - -```shell -npm install gatsby-plugin-typography typography react-typography typography-theme-kirkham gatsby-plugin-emotion @emotion/react -``` - -Set up a site similar to what you ended with in [Part Three](/docs/tutorial/part-three). This site will have a layout component and two page components: - -```jsx:title=src/components/layout.js -import React from "react" -import { css } from "@emotion/react" -import { Link } from "gatsby" - -import { rhythm } from "../utils/typography" - -export default function Layout({ children }) { - return ( -
    - -

    - Pandas Eating Lots -

    - - - About - - {children} -
    - ) -} -``` - -```jsx:title=src/pages/index.js -import React from "react" -import Layout from "../components/layout" - -export default function Home() { - return ( - -

    Amazing Pandas Eating Things

    -
    - Group of pandas eating bamboo -
    -
    - ) -} -``` - -```jsx:title=src/pages/about.js -import React from "react" -import Layout from "../components/layout" - -export default function About() { - return ( - -

    About Pandas Eating Lots

    -

    - We're the only site running on your computer dedicated to showing the - best photos and videos of pandas eating lots of food. -

    -
    - ) -} -``` - -```javascript:title=src/utils/typography.js -import Typography from "typography" -import kirkhamTheme from "typography-theme-kirkham" - -const typography = new Typography(kirkhamTheme) - -export default typography -export const rhythm = typography.rhythm -``` - -`gatsby-config.js` (must be in the root of your project, not under src) - -```javascript:title=gatsby-config.js -module.exports = { - plugins: [ - `gatsby-plugin-emotion`, - { - resolve: `gatsby-plugin-typography`, - options: { - pathToConfigModule: `src/utils/typography`, - }, - }, - ], -} -``` - -Add the above files and then run `gatsby develop`, per usual, and you should see the following: - -![start](start.png) - -You have another small site with a layout and two pages. - -Now you can start querying 😋 - -## Your first GraphQL query - -When building sites, you'll probably want to reuse common bits of data -- like the _site title_ for example. Look at the `/about/` page. You'll notice that you have the site title (`Pandas Eating Lots`) in both the layout component (the site header) as well as in the `

    ` of the `about.js` page (the page header). - -But what if you want to change the site title in the future? You'd have to search for the title across all your components and edit each instance. This is both cumbersome and error-prone, especially for larger, more complex sites. Instead, you can store the title in one location and reference that location from other files; change the title in a single place, and Gatsby will _pull_ your updated title into files that reference it. - -The place for these common bits of data is the `siteMetadata` object in the `gatsby-config.js` file. Add your site title to the `gatsby-config.js` file: - -```javascript:title=gatsby-config.js -module.exports = { - // highlight-start - siteMetadata: { - title: `Title from siteMetadata`, - }, - // highlight-end - plugins: [ - `gatsby-plugin-emotion`, - { - resolve: `gatsby-plugin-typography`, - options: { - pathToConfigModule: `src/utils/typography`, - }, - }, - ], -} -``` - -Restart the development server. - -### Use a page query - -Now the site title is available to be queried; Add it to the `about.js` file using a [page query](/docs/how-to/querying-data/page-query): - -```jsx:title=src/pages/about.js -import React from "react" -import { graphql } from "gatsby" // highlight-line -import Layout from "../components/layout" - -// highlight-next-line -export default function About({ data }) { - return ( - -

    About {data.site.siteMetadata.title}

    {/* highlight-line */} -

    - We're the only site running on your computer dedicated to showing the - best photos and videos of pandas eating lots of food. -

    -
    - ) -} - -// highlight-start -export const query = graphql` - query { - site { - siteMetadata { - title - } - } - } -` -// highlight-end -``` - -It worked! 🎉 - -![Page title pulling from siteMetadata](site-metadata-title.png) - -The basic GraphQL query that retrieves the `title` in your `about.js` changes above is: - -```graphql:title=src/pages/about.js -{ - site { - siteMetadata { - title - } - } -} -``` - -> 💡 In [part five](/docs/tutorial/part-five/#introducing-graphiql), you'll meet a tool that lets us interactively explore the data available through GraphQL, and help formulate queries like the one above. - -Page queries live outside of the component definition -- by convention at the end of a page component file -- and are only available on page components. - -### Use a StaticQuery - -[StaticQuery](/docs/how-to/querying-data/static-query/) is a new API introduced in Gatsby v2 that allows non-page components (like your `layout.js` component), to retrieve data via GraphQL queries. Let's use its newly introduced hook version — [`useStaticQuery`](/docs/how-to/querying-data/use-static-query/). - -Go ahead and make some changes to your `src/components/layout.js` file to use the `useStaticQuery` hook and a `{data.site.siteMetadata.title}` reference that uses this data. When you are done, your file will look like this: - -```jsx:title=src/components/layout.js -import React from "react" -import { css } from "@emotion/react" -// highlight-next-line -import { useStaticQuery, Link, graphql } from "gatsby" - -import { rhythm } from "../utils/typography" -// highlight-start -export default function Layout({ children }) { - const data = useStaticQuery( - graphql` - query { - site { - siteMetadata { - title - } - } - } - ` - ) - return ( - // highlight-end -
    - -

    - {data.site.siteMetadata.title} {/* highlight-line */} -

    - - - About - - {children} -
    - // highlight-start - ) -} -// highlight-end -``` - -Another success! 🎉 - -![Page title and layout title both pulling from siteMetadata](site-metadata-two-titles.png) - -Why use two different queries here? These examples were quick introductions to the query types, how they are formatted, and where they can be used. For now, keep in mind that only pages can make page queries. Non-page components, such as Layout, can use StaticQuery. [Part 7](/docs/tutorial/part-seven/) of the tutorial explains these in greater depth. - -But let's restore the real title. - -One of the core principles of Gatsby is that _creators need an immediate connection to what they're creating_ ([hat tip to Bret Victor](http://blog.ezyang.com/2012/02/transcript-of-inventing-on-principle/)). In other words, when you make any change to code you should immediately see the effect of that change. You manipulate an input of Gatsby and you see the new output showing up on the screen. - -So almost everywhere, changes you make will immediately take effect. Edit the `gatsby-config.js` file again, this time changing the `title` back to "Pandas Eating Lots". The change should show up very quickly in your site pages. - -![Both titles say Pandas Eating Lots](pandas-eating-lots-titles.png) - -## What's coming next? - -Next, you'll be learning about how to pull data into your Gatsby site using GraphQL with source plugins in [part five](/docs/tutorial/part-five/) of the tutorial. diff --git a/docs/docs/tutorial/part-four/pandas-eating-lots-titles.png b/docs/docs/tutorial/part-four/pandas-eating-lots-titles.png deleted file mode 100644 index 64d209363ea8e..0000000000000 Binary files a/docs/docs/tutorial/part-four/pandas-eating-lots-titles.png and /dev/null differ diff --git a/docs/docs/tutorial/part-four/site-metadata-title.png b/docs/docs/tutorial/part-four/site-metadata-title.png deleted file mode 100644 index 942947eeca087..0000000000000 Binary files a/docs/docs/tutorial/part-four/site-metadata-title.png and /dev/null differ diff --git a/docs/docs/tutorial/part-four/site-metadata-two-titles.png b/docs/docs/tutorial/part-four/site-metadata-two-titles.png deleted file mode 100644 index 86f498fcf6313..0000000000000 Binary files a/docs/docs/tutorial/part-four/site-metadata-two-titles.png and /dev/null differ diff --git a/docs/docs/tutorial/part-four/start.png b/docs/docs/tutorial/part-four/start.png deleted file mode 100644 index 2591cff41c04b..0000000000000 Binary files a/docs/docs/tutorial/part-four/start.png and /dev/null differ