|
| 1 | +--- |
| 2 | +date: 2021-08-05T02:45:01Z |
| 3 | +tags: |
| 4 | +- gatsby |
| 5 | +- " react " |
| 6 | +title: What I Learned from 100 Days of Gatsby |
| 7 | + |
| 8 | +--- |
| 9 | +Earlier this year I worked my way through the #100DaysOfGatsby challenges. This year's project has been divided into sprints, with each sprint having a new set of features to implement. While I didn't keep up with the schedule exactly (and this blog post is very belated!), I really enjoyed having the project broken down into manageable chunks like this. |
| 10 | + |
| 11 | +I had played with Gatsby a bit previously, but this project really helped me to dive deeper and get comfortable with the Gatsby framework and the wonderful world of Gatsby plugins! In this post I will highlight some of the hiccups I encountered and things I learned along the way. |
| 12 | + |
| 13 | +## [Challenge 1](https://www.gatsbyjs.com/blog/100days-challenge-1) |
| 14 | + |
| 15 | +The first challenge involved a few things to get a Proof of Concept site up and running: |
| 16 | + |
| 17 | +* Use Gatsby’s Contentful plugin and connect to a test Contentful site |
| 18 | +* Create the following pages: |
| 19 | + * home |
| 20 | + * about |
| 21 | + * a collection of pages for every city |
| 22 | +* Build it on Gatsby Cloud and use their preview URL |
| 23 | + |
| 24 | +The `npm init gatsby` command makes setting up a new site easy, and prompts to choose your preferred CMS, styling tools and additional features. Per the challenge instructions, I selected Contentful as the CMS and configured a few additional plugins (“responsive images”, “sitemap”, and “metatags”). |
| 25 | + |
| 26 | +Since creating a page in Gatsby is as easy as exporting a React component from a page located in the src/pages directory, I created the `src/pages/about.js` to create a route at /about. The "home" page is `src/pages/index.js` which is automatically created by the `npm init gatsby` command. To create the pages for each city, I had to learn something new! |
| 27 | + |
| 28 | +This was my first time using Gatsby's [File System Route API](https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api/), which allows you to programmatically create pages from your GraphQL data, without touching the `gatsby-node.js` file at all. |
| 29 | + |
| 30 | +For this case, I wanted to create pages for each city that audioC0RE operates in, nested under the `/location/` route. |
| 31 | +First, the cities were created as a content type in [Contentful](https://www.contentful.com/): |
| 32 | + |
| 33 | +Since the `gatsby-source-contentful` plugin was already configured, after creating the content model, I could now see the contentfulCity type in the GraphiQL explorer: |
| 34 | + |
| 35 | + |
| 36 | +So, to create the city pages, I created a new file, `src/pages/location/{contentfulCity.name}.js`. At build time, Gatsby uses the content within the curly braces to generate GraphQL queries to retrieve the nodes that should be built for this collection (allContentfulCity), and create a page for each of them. In this case, the following query is generated: |
| 37 | + |
| 38 | +```graphql |
| 39 | +allContentfulCity { |
| 40 | + nodes { |
| 41 | + id |
| 42 | + name |
| 43 | + } |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +Inside the `src/pages/location/{contentfulCity.name}.js` component itself, I used the following query to get all the data needed for each page that is being created: |
| 48 | + |
| 49 | +```graphql |
| 50 | +query ($id: String = "") { |
| 51 | + contentfulCity(id: {eq: $id}) { |
| 52 | + name |
| 53 | + description |
| 54 | + coordinates { |
| 55 | + lat |
| 56 | + lon |
| 57 | + } |
| 58 | + skylineImage { |
| 59 | + title |
| 60 | + gatsbyImageData |
| 61 | + } |
| 62 | + } |
| 63 | + } |
| 64 | +``` |
| 65 | + |
| 66 | +And voila! 3 pages have been created for the 3 cities that are stored in Contentful: |
| 67 | + |
| 68 | +* /location/toronto/ |
| 69 | +* /location/new-york/ |
| 70 | +* /location/san-fransisco/ |
| 71 | + |
| 72 | +*** |
| 73 | + |
| 74 | +## [Challenge 2](https://www.gatsbyjs.com/blog/challenge-2/) |
| 75 | + |
| 76 | +Challenge 2 involved actually getting the website up and running, styling with ChakraUI, adding a contact form with Formium, and adding a skyline image for each city page. |
| 77 | + |
| 78 | +Having never used ChakraUI before (and admittedly rusty on my frontend skills), I had to search for some inspiration. I found this fantastic [blog post](https://raptis.wtf/blog/build-a-landing-page-with-chakra-ui-part-1/) from Jim Raptis, and used it to help me build the home page and header, with a few adjustments. |
| 79 | + |
| 80 | + |
| 81 | + |
| 82 | +I wanted to have the header contain links to all cities, but was encountering an error: |
| 83 | + |
| 84 | +```console |
| 85 | +Exported queries are only executed for Page components. It's possible you're |
| 86 | +trying to create pages in your gatsby-node.js and that's failing for some |
| 87 | +reason. |
| 88 | + |
| 89 | +If the failing component(s) is a regular component and not intended to be a page |
| 90 | +component, you generally want to use a <StaticQuery> (https://gatsbyjs.org/docs/static-query) |
| 91 | +instead of exporting a page query. |
| 92 | +``` |
| 93 | + |
| 94 | +This led me to discover Gatsby's [<StaticQuery>](https://www.gatsbyjs.com/docs/how-to/querying-data/static-query/)! From the Gatsby docs: |
| 95 | + |
| 96 | +> By using StaticQuery, you can colocate a component with its data. It is no longer required to, say, pass data down from Layout to Header. |
| 97 | +
|
| 98 | +That's exactly what I needed it for! So I used the `<StaticQuery>` to populate my header with the links to the cities: |
| 99 | + |
| 100 | +```react |
| 101 | +<StaticQuery |
| 102 | + query={graphql` |
| 103 | + query AllCities { |
| 104 | + allContentfulCity { |
| 105 | + edges { |
| 106 | + node { |
| 107 | + name |
| 108 | + gatsbyPath(filePath: "/location/{contentfulCity.name}") |
| 109 | + } |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + ` |
| 114 | + } |
| 115 | + render={data => <HeaderComponent data={data} />} |
| 116 | + /> |
| 117 | +``` |
| 118 | + |
| 119 | +**A Hiccup**: When building the dropdown menu for the cities, I was trying to use `ChevronDownIcon` in my <HeaderComponent>, but I was importing it from `@chakra-ui/react` instead of `@chakra-ui/icons`, and the error message was a bit confusing: |
| 120 | + |
| 121 | +```console |
| 122 | +Uncaught Error: Undefined component passed to createElement() |
| 123 | + |
| 124 | +You likely forgot to export your component or might have mixed up default and named imports |
| 125 | +``` |
| 126 | + |
| 127 | +_Lesson_: always double check your imports! |
| 128 | + |
| 129 | +*** |
| 130 | + |
| 131 | +## [Challenge 3](https://www.gatsbyjs.com/blog/100days-challenge-3/) |
| 132 | + |
| 133 | +Challenge 3 involved using Gatsby's new [WordPress integration](https://www.gatsbyjs.com/plugins/gatsby-source-wordpress/) to add a blog to the site! |
| 134 | + |
| 135 | +This would involve setting up a `/blog` page, and creating a new page for each blog post sourced from WordPress. The [docs](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-wordpress/docs/tutorials/building-a-new-site-wordpress-and-gatsby.md#creating-pages-for-each-blog-post-and-linking-to-them) suggest using `gatsby-node.js` and the `createPages` API, but I had a hunch that this wasn't necessary - I could simply use the [File System Route API](https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api/), as I had with the Contentful cities. |
| 136 | + |
| 137 | +First, I had to setup the `src/pages/blog` page, which would list out all the posts, using the following query: |
| 138 | + |
| 139 | +```graphql |
| 140 | +query wpPosts { |
| 141 | + allWpPost(sort: { fields: date, order: DESC}) { |
| 142 | + edges { |
| 143 | + node { |
| 144 | + title |
| 145 | + date |
| 146 | + id |
| 147 | + slug |
| 148 | + excerpt |
| 149 | + } |
| 150 | + } |
| 151 | + } |
| 152 | + } |
| 153 | +``` |
| 154 | + |
| 155 | +This was used to create a grid of posts excerpts, linking to the actual blog post page: |
| 156 | + |
| 157 | +```react |
| 158 | +{data.allWpPost.edges.map(({node:post}) => ( |
| 159 | + <Box m="10px" p="10px" grow="1" maxW="400px" key={post.slug}> |
| 160 | + <Link to={'/blog/' + post.slug}> |
| 161 | + <Heading as="h4" size="lg" color="primary.800" mb="1.5" textAlign="center"> |
| 162 | + {post.title} |
| 163 | + </Heading> |
| 164 | + <Text dangerouslySetInnerHTML={{ __html: post.excerpt }} isTruncated="true"> |
| 165 | + </Text> |
| 166 | + </Link> |
| 167 | + </Box> |
| 168 | +))} |
| 169 | +``` |
| 170 | + |
| 171 | +Next, I created the collection route & template for the actual blog post itself, at `src/pages/blog/{wpPost.slug}.js`, which uses the following query: |
| 172 | + |
| 173 | +```graphql |
| 174 | +query ($id: String = "") { |
| 175 | + wpPost(id: {eq: $id}) { |
| 176 | + title |
| 177 | + date(formatString: "DD MMMM, YYYY") |
| 178 | + content |
| 179 | + slug |
| 180 | + id |
| 181 | + } |
| 182 | + } |
| 183 | +``` |
| 184 | + |
| 185 | +This would create a page for each blog post, which were already linked from the `/blog` page! Fantastic! |
| 186 | + |
| 187 | +*** |
| 188 | + |
| 189 | +## [Challenge 4](https://www.gatsbyjs.com/blog/100days-challenge-4/) |
| 190 | + |
| 191 | +Challenge 4 involved setting up a Shopify e-commerce store to sell swag for the popular fictional startup, audioC0RE! |
| 192 | + |
| 193 | +So, I setup a Shopify developer account, installed the necessary plugin and configured everything according to the [docs](https://github.com/gatsbyjs/gatsby-source-shopify). Unfortunately, I encountered an error: |
| 194 | + |
| 195 | + |
| 196 | +Hmm...that's not very helpful, is it? I searched everywhere, asked twitter and couldn't find anything! So, I opened an [issue](https://github.com/gatsbyjs/gatsby-source-shopify/issues/108#event-4518155849) on Github! This was my first time opening an issue, so I was a little intimidated, but thankfully the maintainer was incredibly nice and helpful! After lots of back and forth, I eventually determined the source of the error: a typo 🤦 |
| 197 | + |
| 198 | +I had trailing commas in my `.env` file, which were causing the unauthenticated error because it was adding an extra character to the API key! I felt a little foolish for missing this, but ultimately I'm glad for it! I had a great first issue experience, and it resulted in some additional logging being added to the plugin, which will hopefully help other developers to debug their own issues faster! |
| 199 | + |
| 200 | +After getting that issue sorted out, setting up the `/shop` page went smoothly. I was able to use the [File System Route API](https://www.gatsbyjs.com/docs/reference/routing/file-system-route-api/) again, with a `src/pages/shop/{shopifyProduct.handle.}js` to create the individual pages for each product, and had a listing of all products on the `/src/pages/shop.js` page. |
| 201 | + |
| 202 | +I'll spare you the details once again, but if you want to see the code feel free to look through the [repo](https://github.com/megfh/100daysofgatsby2021)! |
| 203 | + |
| 204 | +## Conclusion |
| 205 | + |
| 206 | +Ultimately, the #100DaysOfGatsby challenge was a great experience! I was able to add a new project to my resume, learn some new things, and I now feel more confident working with both React & Gatsby. |
| 207 | + |
| 208 | +I highly recommend anyone who is interested in learning Gatsby give this challenge a try! |
0 commit comments