Skip to content

Latest commit

 

History

History
1283 lines (955 loc) · 46.7 KB

notes.md

File metadata and controls

1283 lines (955 loc) · 46.7 KB

2 - Tooling and Starter File Setup

sudo npm install gatsby-cli @sanity/cli -g -- Install Gatsby + Sanity CLI globally on your computer gatsby --version sanity --version

3 - What is Gatsby?

Gatsby Basics

4 - What is Gatsby?

  • Framework for building modern websites
    • Manages data
    • Routing strategy
    • Build process
  • React is a library for rendering out data to HTML very quickly
    • Gatsby uses React under the hood
    • Adds on additional stuff for building a modern website
  • Examples:
    • wesbos.com
  • Advantages
    • Pushes from one page to another
    • We aren't going from page to page
      • Loading different pieces of the website
      • Then updates the URL

Overview

  • Gatsby is a static site generator
    • There is a build-step in your website
    • Performs what WordPress does at build time
    • HTML is generated when you build the website
      • This allows the website to load that much faster
  • Smart about CSS
    • Figures out what CSS is needed for that page
    • Loads before the content
    • Avoids the flash of "unstyled" content appearance
  • "Rehydration"
    • WesBos.com is a React application
    • Gatsby will load HTML onto a page...
      • Then pick it up and turn it into a fully-featured React application
    • This is known as "rehydration" in the browser
  • Lazy Loading
    • Dont need to download the image until you are about to see it
    • Compresses images, converts them to a modern format
    • Routing and loading is baked into it
  • Plugins
    • Thousands
      • Offline access
      • Code Highighting
  • What Gatsby is NOT
    • CMS (WordPress, Sanity, etc.)
    • No backend that you log into and update your content
  • Shortcomings (because of static nature)
    • Need to code things in a particular way
    • Example: Dynamic pages (will cover in the course)

Performance on LightHouse

  • Gives a score on website best practices
  • By default, makes you code in a way to create a fast, performant, SEO friendly website

5 - Pages in Gatsby

  • node_modules - Where dependencies are installed
  • public --> Generated by Gatsby (same as gatsby clean)
  • src --> Where most of Gatsby will live
    • pages is the only Gatsby-specific folder
      • Top level pages (About, Order, etc)
    • The others are made up
    • assets --> Fonts/images
    • components --> Nav, order button, React components
    • templates --> Similar to pages, but reusable (e.g. pagination)
    • utils --> Smaller functions (e.g., format money)
  • static --> Files that you want to be served up as HTML
    • TIP: Generally do not put stuffff intno static
    • Dont want to reference or import anything into Gatsby by their static path
    • Everything must go through Gatsby (imported through Gatsby)
      • By importing it, Gatsby knows about your assets and does the cool performance stuff
    • Think twice about using the static folder

How Pages are Created

  • Can be dynamically generated or based on file system routing
    • If you go into pages directory and make a new file...
      • That will be the page that shows up when someone visits
      • Need to export a function from the file
      • That will be rendered as a page
  • Function must be exported from the file
    • All Gatsby files (except a few) are modules
      • Can export things from them
      • Assumes that the main export is what is rendered when someone visits the page
    • Then need to start the gatsby build
      • Must be in gatsby folder
      • Scripts in package.json execute gatsby commands (build, start, clean, etc)
      • develop puts us into live reload mode
    • npm start runs gatsby develop
    • GraphQL - How we are going to source our data (remember for later)
  • Renders a 404 page by default

404 Dev Mode

  • Will see 404 page when loaded into production

Scaffolding

  • Creating the bar bones of all pages

5 - Routing and Navigation in Gatsby

  • Component: Reusable pieces inside of pages
  • Instead of using anchor links, we use the link tag
    • Renders an anchor link
    • Loaded with JavaScript needed
  • { Link } - Component exported by Gatsby
    • Does HTML Push State
    • There are times when you want to programatically change pages
      • Submit form, click specific button, etc

Declarative vs Imperative

  • Declarative: Use Link
  • Imperative: Write code to define what happens as a result of a form submit

6 - Creating Reusable Layouts

  • Using react components with children components
  • Typically wont see props passed as a huge payload
  • Props will be destructured in the function
    • Grab children directly from the function
    • Place in a top level variable

Props Validation

  • When you have a component that expects a prop, you assign prop types
  • Ensures that the right things are being passed in development
  • Other ways to do props (e.g., TypeScript)

Custom Files

  • Gatsby browser + Gatsby SSR Files
  • Automaticlly wrap files for us
  • Create gatsby.browser.js IN THE ROOT FOLDER of gatsby
    • Allows us to hook into different Gatsby APIs
    • Wrap page element hook wraps Components for us
    • Avoid having to do this on every single page
  • By Default, Gatsby does not wrap your page elements
  • NOTE: Whenever you modify, you need to quit the build and restart it
    • Kill the process and restart via npm start

React Fragments

  • Ghost Fragments allow you to return two or more elements
  • JSX only allows you to return one element
  • Wrap with <> </>

Gatsby-SSR vs Gatsby-Browser

  • Browser runs when the page is loaded and generated in the browser
  • Gatsby also generates everything on the server so that it renders fast
    • That is what gatsby-ssr.js is for
  • Can copy/paste everything from gatsby-browser.js into gatsby-ssr.js

8 - Global Styles

  • Gatsby needs to know about everything in project
  • Data, pages, links, even CSS
  • All CSS dumped into HTML is dumped before any of the content
  • Gatsby knows what CSS that was written is the critical CSS for that page to render with a flash of unstyled text
  • Instead of linking to CSS, we need to import it through Gatsby

CSS Options

  • Import CSS files into gatsby-browser.js
  • We are going to use **Styled Components**
    • A way to used Scoped CSS within a React application
    • Used to scope CSS and make reusable, styled components

Styled Components - Steps

  1. Set global styles in application
  • On any website you will have global styles
    • Background, scroll bar appearance, max-width on images etc.
  • Doesnt make sense to reset them every time you make a new component
  • First Step: Normalize entire application
    • normalize.css
    • Normalizes browsers so that you start with the same foundation in each one
    • This is an npm package that was already installed by Wes
  • Created global styles in styles directory
  • Gatsby allows you to import anything, including images and CSS
    • It knows not to render it out to JS, but to render out to correct format
    • Not being added to assets folder because:
      • If so, they would have to go in the static folder which Gatsby doesnt know about
  • Stick global styles into a variable and export them

Loading Images

  • Gatsby renders out a base64 string before loading onto the server
    • Gatsby ships the image as text (20px by 20px)
    • You can scale that image up as the larger one is pulled down from the CDN
  • Gatsby will take an SVG, compress it and place a random identifier on it
    • Never have to do a hard refresh - literally a different filename than the original image - it will be cached
  1. Create typography styles
  2. Write CSS

8 - Typography

  • Keep in a separate file
  • Create in the src/styles folder

9 - Styling the Nav and Logo // 10 - Styling our Layout

  1. Import styled
  2. Define the element you want to style (e.g., .nav)
  3. Add styles
  4. Replace tags with the variable name (NavStyles)

Styles in Nav.js

  • Any styles that we put here will not be applied to anywhere else on our website
  • Any link inside of the nav element will be red

Global Style - Inheritance

  • Styles written w/o any selector are applied to the mainn element (nav)
  • TIP: Make main components a style
    • Use child selectors to grab things inside of them
    • If you need to reuse styles multiple times, you can create a new var

Nesting components

  • If you unencessarily nest, it gets tricky (for media queries etc)

CSS Variables

  • Helpful for when you want to redefine a single CSS attribute on an element
  • PROBLEM: For properties like transform, other attributes will be overwritten
  • SOLUTION: Assign properties with variables
    • For elements that you want to update, you only need to reference the variable

Module 4: Headless CMS

10 - Headless CMS

  • Sanity
  • Headless = No frontend
  • No way to view the data in your website with Sanity
    • Just the backend
  • Front-end is what we are building (Slick Slices)
  • That data is pulled in via Gatsby with a Plugin
  • Steps are roughly the same as any CMS you use
    • Create data --> Inject into site
  • Sanity - Pros:
    • Balance between up and running quickly + done for you
    • Customizable

File Structure

Configuration

  • sanity init --reconfigure
    • Prompt you to create a new account
    • To relogin, enter sanity login
    • Default dataset is a public DB called "production"
    • can have multiple datasets (for dev environments ex)
  • Can delete the yarn.lock file if it appears
    • package-lock.json is the same thing

Using Sanity

  • npm start
    • Fires up a local server that will give us Sanity Studios
    • Sanity Studios - UI that we use to configure CRUD operations on data
    • sanity - CLI
  • sanity start

Sanity.JSON

  • Parts --> pieces of JS that need to be loaded
    • Only need to touch when doing custom ones
    • Goes to the schema.js file

Schema.js

  • File is preloaded
  • Take all data types and concatenate them into our schema

Making Our Own Schema

  • Schema file - create new file pizza.js
  • Exporting an object with data in it
  • name Computer name
  • title Visible title

12 - Creating the Toppings Content Type and custom previews

  • Second data type called topping
    • Pizza has many toppings
    • "Based on this topping, show me pizzas with this topping"

Importing Icons

  • Can import Font-Awesome icons, other icons from other librarie
  • Just imports that icon, not the entire library

Merging Fields into the schema

  • After creating the topping.js file, you need to merge it into schema.js

13 - Creating Data Relationships

  • Need a way to select what toppings to put on the pizza

  • Go into the pizza.js and create a new object (toppings)

  • Anytime you have a websocket and reload the page, Firefox will complain

    • Ignore

Sanity

14 - Creating our Personn Data Type

Overview

  • Person schema (to create people)
    • Involves pagination
  • Settings page
    • Want to be able to specify:
      • Who is "slicing" pizza
      • What pizza is currently by the case

15 - Custom CMS Inputs in Sanity

Overview

  • Inputting cents for pizza
  • Want to display actual price in the editor
  • Good use case for custom input components
  • We have full control over the code that runs in Sanity

Challenge

  • Put a veggie symbol next to the pizza name if all of the toppings are vegetarian
  • Would need to go into the preview, select all toppings, loop through and select the icon if all are vegetarian

Custom Components

  1. Create a folder components
  2. Create a file PriceInput.js
  3. Add a boilerplate React component
  4. Go into schema pizza.js and import PriceInput.js
  • NOTE: Styling does not perfectly match Sanity Studio
    • Sanity Studio adds classes
    • There are docs, but more trouble than its worth
    • Going to make it easier

React Requirement - Adding dynamic values to inputs

  • Anytime you put a value into an input, you must also supply an onChange handler
  • Within PriceInput.js, import a helper function called PatchEvent, { set, unset } from 'part:@sanity/form-builder/patch-event';

Module 5: Getting Data into Gatsby with GraphQL

16 - An intro to gatsby-config and sourcing data

Overview

  • How do you take the data that lives in Sanity and get it into Gatsby?
  • Allows you to see "GraphQL Queries"
    • Can run queries in there and see what it returns
    • Use to write queries

Connection to Gatsby

  • When we build (before deploying to internet), Gatsby collects all the data it needs to run
  • Gatsby will go to sanity -- all data, relationships, images, etc. -- and will stick it into a temporary database -- it's memory
  • Gatsby then allows us to query that data with GraphQL queries
  • GraphQL provides queries that come standard with Gatsby
    • allSite, allFile, directory, etc.
    • This is not helpful for devs - more for lower-level authors
  • Question: How do we surface our data from Sanity and surface it in the GraphQL explorer?
    • Answer: Plugins
    • These are defined in Gatsby-config.js
    • Used to specify plugins for your website
    • Can also specify metadata, URls, titles etc.
    • Have lesser-used ones (path-prefix) (eg wesbos.com/blog)

Creating the File

  • Will add metadata to show how to add it + how it is sourced to GraphQL explorer
  • Will also add plugins
  • Create file in root of gatsby folder caleld gatsby-config.js
  • Gatsby Config API

17 - Sourcing Sanity ata and GraphQL Introduction

Overview

  • Plugins make it easy to work with other packages and libraries
  • To specify plugins, do so via a plugins array that live in gatsby-config.js
  • Ways to use a plugin:
    1. Specify name of the plugin; accept all default options
    2. Styled component plugin that surfaces the CSS to Gatsby
    • Gatsby can then figure out the critical CSS
    1. If there are settings that need to be set, you pass in an object and add a resolve object to the plugin that you are adding
  • NOTE: To add your own plugins, npm install gatsby-plugin-styled-components etc or whatever you want

Storing Sensitive Data

  • Save in a .env file
  • Import the dotenv package
  • By default, Sanity will surface tokens starting with GATSBY_
  • To access ENV vars in Gatsby-config, you need to use dotenv.config({ path: '.env' });

Deploying a GraphQL API for Sanity

  • By default, Sanity has a 'grok' API
  • For GraphQL (built with Grok), you need to enable that
  • Docs for Sanity GraphQL
  • Command: sanity graphql deploy production
    • NOTE: Production is the name of the dataset

Moving data from Sanity API to Gatsby API

  • Sanity API is
  • Not working with it directly
  • Want to move it from Sanity API to Gatsby API
  • Solution: Restart Gatsby server with Ctrl + C // npm start

GraphQL - Querying Data

  • Can query as much data as you want
  • If you query all pizzas, you can also query allSanityPerson in the same query
  • There is only one endpoint, and you can grab all of the data that you want query MyQuery { allSanityPizza { nodes { name price slug { current } } } allSanityPerson { nodes { name } } }
  • Can select individual pizzas (grab the ID)

18 - Learning Gatsby Queries

Page Queries

  • Can be dynamic with variables
  • Can only be run on a top level page
  • To specify, export a query from the page
    • Gatsby will identify that as a query and fetch the data during the build
    • It will then pass that data to the page component

Static Queries

  • Can not be dynamic, no variables can be passed in
  • Can be run anywhere

Example - Pizzas Page

  • On pizzas page
  • We want to query all of the pizzas that have a toppinng, OR - if there is no topping specified, we will query all of the pizzas
  • NOTE: If you want to have variables in your query, it has to happen at a page level
    • Slight limitation of Gatsby

CONSOLE TIP - $r

  • If you select a React component and then go to your Console and enter $r...
  • ... It will return the React component as an object
  • This is helpful for digging into the props of a component

Module 6: Puttin in Work

19 - Gatsby Images

  • Images make your website very slow
  • The steps needed to make your site fast are often too hard for regular web devs
  • Gatsby makes the progressive loading, resizing, and compression of your images much faster

What is Wrong with images on internet?

  • Too big
  • Not compressed (file size might be the right size, but it could be 50% smaller w/ an algo)
    • "Lossless" [no sacrifice on quality] vs "Lossy" compression
  • Width / Height --> You want to resize to a perfect square but maybe dont have the right tools
  • Poor loading performance. Can load in, but as it downloads you can see nothing
  • Not the right format. Lots of different formats (PNG, JPG, WebP)

Solution

  • Tell Gatsby the info that you want to know
  • It will deliver to you a Gatsby image
    • Has all of the info that you need
  • Takes care of ratios (can be hard in CSS)
  • Gives a data-image --> image shown while the actual image is loading
    • (Images are blurry for a moment while the full version is downloaded)
  • <picture> element - tries to serve you a WebP version, otherwise it will serve a JPEG
    • Will serve multiple versions of the image depending on the size of the actual image

Using Gatsby Image

  • You need something to process those images
  • As a dev, you can add a JPEG into Gatsby, but shouldnt load it onto the website
  • You need either:
    • A service
    • A compute
  • ... That will manually process the images, make versions of them (small/large, JPEG/WebP etc.)
  • To process images, there are two ways:
    1. Source your images
    • If you have images in a directory
      • Similar to Sanity
    • Pipe them through Gatsby Sharp
      • Runs on your computer or Netlify build
      • This can take a long time
      • Ex: Fresh build for Wes can take up to 20 min (has ~300 images)
      • Image processing is very expensive (takes a lot of compute)
    1. Use Gatsby image, but with a service
    • You can upload images directly or feed your image
    • Images will be produced as the customer requests them
    • Sanity has an image pipeline -- what we will be using
      • Compatible with Gatsby Image
    • Cloudinary
    • Imgix
    • NOTE: Gatsby image works the same way regardless of your service

Putting Images Together

  • We can use a custom image element that ships with Gatsby
  • Then feed all props.image data to Gatsby

Types of Images

  • Fixed: Fixed width/height
  • Fluid: Responsive. Can resize the image (suggested)
  • Gatsby will only load images on demand as you scroll them into view
    • Means you aren't using unecessary bandwidth - both on your server and the customer

Getting a Different Sized Image

  • Go to page pizza.js (where we are querying the data)
  • In the GraphQL query, we can:
    • Simply update the GraphQL query fixed(width: 200, height: 200) { ...GatsbySanityImageFixed }
  • You can then pass these to an <Img fixed={pizza.image.asset.fixed}>

Funky Image Dimensions

  • Sanity will chop the images for you
    • Suppose you wanted a height of 200 & width of 600 (very wide)
    • There is also functionality to ensure that the images aren't chopped in a poor way

20 - Loading in Sample Data

  • Sanity --> Sample Data -->
    • all-sample-data.gz: All pizza toppings, slicemasters etc
  • In sanity root, run sanity dataset import ./sample-data/all-sample-data.gz production --replace
    • --replace --> overwrite
  • If you go to localhost:3333, all of the data is immediatelly loaded into Sanity

21 - Styling our Pizza Grid with CSS

Overivew

  • Open up PizzaList.js
  • We are going to create a styled component called PizzaGridStyles

CSS Grid

CSS SubGrid

22 - Static Queries and Building the Toppings Filter

Overview

  • Want to create a filter that will:
    • List all of the toppings
    • Pizza that has that topping
    • Click on each one and filter for pizzas that have that topping

Steps

  • Creating a new component called ToppingsFilter.js

Module 7 - Making Gatsby Dynamic

23 - Dynamically creating pages with gatsby-node

  • Creating dynamic pages with gatsby-node.js
    • API for controlling your sites data in the GraphQL layer
    • Do things at various points during the Gatsby build cycle
  • graphql --> GraphQL queries
  • actions --> used for creating pages

Steps

  • Store in folder templates
  • Create file Pizza.js
    • Because it is reused multiple times, it is a Class and should be capitalized
  • We need just enough data in the await graphql(''); statement to:
    • Render out the template
    • The template itself will go off and fetch the data

Inspecting Pizza Pages

  • In React Dev tools, there is a prop pageContext
  • If you need to pass data from .createPage method to the template, that can be done with context
    • Displays as pageContext within props

Updating Pizza.JS

  • Can use graphql as if it were a standard page
  • Interpolate variables into query
    • Variables are passed into graphql query as arguments
    • Here we are passing the slug that is specified in the context of actions.createPage() in gatsby-node.js
  • Then, when using graphql on Pizza.js page, the outputs will be for the $slug variabe from gatsby-node.js

Alternative

  • Query the entire pizza in gatsby-node.js
  • Then pass the entire pizza as context
  • You can then skip the graphql query in Pizza.js
    • That is valid
  • TIP: Prefers to keep actual query in page itself
  • Avoids having to jump back into Gatsby-node.js
  • PLUS -- you would have to kill the process each time. Allows for faster iterating

Beefing Out query

  • We want name, id, image (asset, etc),

24 - Templating and Styling our Single Pizza Page

Go into Pizza.js

  • Now rendering out the page
  • Imports:
    • React
    • graphql
    • Img from 'gatsby-image' (NOTE: Not called Img so auto import will not work)

25 - Dynamically Creating Toppings Pages

Overview

  • We are going to reuse pizza.js age, but pass it the ability to insert for a specific topping
  • Ex --> Click on roasted garlic --> should see the pizzas that have roasted garlic

DIFFERENCE

  • We already have a page that shows what pizzas have what toppings - pages/pizza.js
  • Modify the PizzaQuery to take in an argument for what topping to filter for

Filtering for Toppings

  • Add a filter for toppings in GraphQL
  • Filters are never standard across GraphQL implementations
    • We are seeing the way that Gatsby does it
  • Use a regex expression elemMatch on the name of each topping
  • The query on the pizza.js page also takes in an argument
    • This arg comes from the toppings query in gatsby-node.js
    • (Same concept as the Pizza query)
  • The original query is simply enriched with a filter

Highlighting the Current Topping

  • Go to ToppingsFilter and pass it the activeTopping
    • Can destructure pageContext in the PizzasPage component
  • Then, in ToppingsFilter.js, we can then destructure that value activeTopping
    • Display output to see that it is working

26 - Sourcing Data from an external API

Overview

  • Probable that your website has data that must be pulled in from an API
  • Ex -- REST API (Tweets, posts, GitHub etc) that you need to pull in?
  • Still want to reap all the benefits of server-rendered, pre-rendered, SEO-friendly etc.
  • https://sampleapis.com/beers
    • We are going to be fetching this at build time
  • How do we get this data into our Gatsby GraphQL API, query, and pull it in?
    • ANSWER: Gatsby-node.js
    • We are already hooking into the createPages API
    • There is also an API for Sourcing Nodes
      • SOURCING: Putting the data into your Gatsby API
      • NODE: Piece of data
        • When we do our pizza query, we ask for the nodes (each piece of data is a node)
      • We want to put data into the GraphQL API by Sourcing them

Steps

  • Add an additional export async function fetchBeersAndTurnIntoNodes as well as export async function sourceNodes in gatsby-node.js
    • Await the output of fetchBeers within the sourceNodes hook. Wrap with Promise.all()
  • NOTE: Remember to pass the params down into the beers funnction from sourceNodes
  • Con of Gatsby: Feedback cycle for gatsby-node.js is slow (at the moment)

Thoughts

  • Difference between writing a plugin for Gatsby and writing it in your gatsby-node.js is nothing
  • If you were to open the sanity-source plugin, they are doing the same thing
    • Grabbing some data, looping over data, then putting it into your GraphQL API for you
  • Next: queries to pull data into your beers page
    • Challenge: Write queries to pull this into our beers page
      • Query all the beers and display them (if they have a photo or not, rating, etc)

27 - Querying, Displaying and Stlying the Beers Page

Module 8 - Pages & Filterirng

28 - Querying and Displaying Pagination

Overview

  • Query data
  • Loop over data
  • Modify data in next module for pagination

29 - Paginating Data in Gatsby

Overview

  • Instead of having everything on one page, add next/prev page content
  • When doing pagination, need to know the total number of people
    • For this we can query the totalCount
  • Not going to be querying every person all at once
    • Therefore, wont know unless asking GraphQL for the info
  • We need to store the number of people to go on each page
  • Usually pagination is done on demand
    • Because Gatsby is pre-generated at build time, we need to know at build time how many pages there are
    • We will go into gatsby-node.js and do things like:

Steps

  • Set environment variables in .env file
    • (Can also go in a settings.js file)
  • NOTE: For variables to show up in Gatsby, they must be prefixed with GATSBY_
    • Other variables will not be surfaced (e.g., SANITY_TOKEN)
    • <p>{process.env.GATSBY_PAGE_SIZE}</p>
      • The value gets pulled in from your .env file
  • TIP: Gatsby is currently testing a new hot reloader w/ the var GATSBY_HOT_LOADER=fast-refresh
  • Go into gatsby-node.js; create a new function to turn the Slicemasters into pages

TIP - Looping through index

  • Array.from({ length: 5}).forEach((_, i) => console.log(i));

30 - Filtering the data based on Pagination

Overview

  • query on slicemasters will take the incoming content from gatsby-node.js and modify the # of people on the page

31 - Creating a reusable Pagination Component

Overview

  • General use pagination
  • Make a new file in components pagination.js

Module 9 - Custom Pages + SEO

32 - Single Slicemaster Pages

33 - Gatsby SEO and Head Tags

Overview

  • Highest level we get is the Layout.js

    • There are no HTML, body, etc tags - all gets added by Gatsby
    • Question: How do you stick things into the ?
  • SOLUTION: React Helmet

    • Known as a side effect - JS takes the component and update it outside of itself

    • You can take the GraphQL results and load them into the head element

    • Allows us to stick tags into React helmet

    • Will transport them out from wherever you put them into the document's head

    • Useful for HTLM attributes, SEO, OpenGraph meta tags, etc.

  • Example: pizza.js

    • import { Helmet } from 'react-helmet';
    • You can stick a helmet wherever you want in your component and then just start putting tags into it

Tip - Reusable SEO

  • TIP: Create a reusable SEO component that has a set of default
  • Remove Helmet from Pizza.js
  • Go into gatsby-config.js
    • We are going to us a gatsby plugin
    • *When we get into server rendering / pre-building, there is a plugin needed for server-rendered, which is very important for seo
    • Add 'gatsby-plugin-react-helmet', to list of plugins
  • Go into components folder, create SEO.js

More on React Helmet

  • You can see which attributes were added by React Helmet bc they will have data-react-helmet attributes on them
  • After creating the SEO base, we need to go through every single page (everything that lives in pages as well as templates) and add the SEO

Module 10 - Order Form, Custom Hooks and state management

34 - Creating the order page with Custom Hooks

Overview

  • list all the pizzas we have
  • Can add pizzas to the order
  • Add name, email
  • Provide total
  • This is a regular form in React
  • When someone submits, we take this data and sends it off to an email
  • To do this, we need a backend -- going to use serverless functions

Steps

  • Adding to order.js
  • Loop through menu; loop over everything an
    • Can use a page Query (on a page) or a Static query (no specific variable)

35 - Styling our Order Form

Overview

  • Going to keep styles in a separate file
  • In styles, create OrderStyles.js
    • This is for the fieldsets menu and order
  • Also want to style the individual pizzas
    • Create another page in Styles called MenuItemStyles.js

36 - Custom Hook for our Order Form

Overview

  • When someone clicks one of the buttons, we want to add that to our order
  • Going to create a custom hook with custom state to manage
  • Creating usePizza.js in utils
  • In components, we are going to make a new component that holds the displaying of order items
    • File PizzaOrder.js

37 - Calculating our Order Total

Module 11 - Serverless Functions

38 - Moving our Order State to React Context with a Custom Provider

Overview

  • The state we are saving this in exists in our order page
  • When we navigate away, Gatsby will unmount and remount the components - thus any state is lost
  • To maintain state across page changes, you need to put that state at the highest level in Gatsby so that it doesn't unmount and remount

Gatsby-browser.js

  • There is a hook called wrapRootElement that allows us to wrap the actual Gatsby Root
  • In React dev tools, can see the Root element
    • Only element on the page that stays there
    • All other elements mount and remount when you switch pages
    • Wrapping around the root element allow us to persist that data
  • How to do that:
    • We are currently sticking state into a hook at an order level. Need to do it at a root level
    • Will stick all of the data into context
      • Allows us to store data at a high level and access it at a lower level w/o using props
    • Create a new filed called components/OrderContext.js
    • In gatsby-browser.js, export a function wrapRootElement
    • Once added to gatsby-browser.js, the wrapRootElement must also be added to gatsby-ssr.js
  • Now, how do we access that state at a deeper level?
    • Go to usePizza.js hook
    • Calling the function useContext(OrderContext), which takes in OrderContext as an argument

Refreshing the Page

  • Data will disappear on a page refresh
  • Can stick into localStorage and pull it back in when it mounts

Creating Unique Keys

  • Need a unique key since there can be identical pizzas
  • Use the index

39 - An Intro To Serverless Functions

Overview

  • When you build Gatsby, it uses HTMl, CSS, and JS to handle custom functionality
  • Doing things on the backend is challenging
    • Sanity handles the backend
    • What about sending email? Needs to happen on the server-side
  • Gatsby works well with serverless functions (Lambda)
    • Similar to running a Node server, except it runs only for the duration of code execution
    • Going to be using Netlify functions (hosts serverless functions)
    • Can host wherever you want

Steps

  • Make a new folder functions

  • Make a new file netlify.toml in the root of your directory

    • Need to tell Netlify where your serverless functions live
  • Inspect package.json

    • We have been running npm start, which runs npm develop which then runs gatsby develop
    • We now need to run npm run netlify which will run netlify dev
      • Both will run npm run start under the hook and set itself up properly for running serverless functions
  • From the gatsby folder, kill the gatsby build

    • Run npm run netlify
    • Will provide a URL where we can run the website off of (localhost:8888)
    • Netlfy dev will proxy gatsby for us
    • PROBLEM: --> Ran into an error when attempting to run npm run netlify:
      • Error: ENOENT: no such file or directory, open '/Users/kevingrimm_/Desktop/LEARN_JAVASCRIPT/GATSBY/master-gatsby/starter-files/gatsby/node_modules/netlify-redirector/lib/redirects.wasm'
      • Googled around / tried different options but didn't have any luck with the command.
      • SOLUTION: Follow steps in this Blog Post and execute netlify dev
  • Make the first serverless function

    • For each function we have, we want to create a new folder
    • Inside of that, create a .js folder that is the same name as the folder that it is in
    • Here we code the handler
  • To visit the URL:

    1. Go to http://localhost:8888/.netlify/functions/hello

What We Are Doing

  • Creating a function placeorder with nodemailer to connect to an external email service
  • Create a new folder and file placeOrder
  • NOTE: Sometimes your serverless functions are so large that you want to have your own package.json for your serverless
    • Go into the folder placeOrder
    • Netlify facilitates this with npm init to create a package.json (press Enter through options)
    • Then, execute npm i nodemailer --> allows us to send email w/ JS
  • Now flesh out placeOrder.js function

Configuring Ethereal.email in Handler

  • Set up a new account at https://ethereal.email
  • Code functionality
    • const transporter = nodemailer.createTransport({...})
    • const info = await transporter.sendMail({ (within handler)
  • For the return component, can use JSON.stringify(info) to inspect results
  • View mail at Ethereal --> Messages
  • NOTE: Besides swapping out credentials, there is no difference between Ethereal and a transactional email service

40 - Modifying our Custom Hook to send the order data

Overview

  • How do we take the users order from the client, send it to the serverless function, and then template out the HTMl that displays what they have in their order

Steps

  • Go into usePizza.js hook
    • Need to add new state
      • handle errors
      • handle loading state
      • handle returned messages
  • Back in order.js
    • Destructure the new functionality passed into the hook
  • Back in usePizza.js
    • Need to create a handler for when someone clicks on the "Order" button
    • Called submitOrder
  • Effect of submitOrder
    • Executes a SyntheticEvent
    • Changes the text on the button to reflect the changed state in loading
  • Configure a body var which contains order, name + email info
  • Create a new function to modify the order object (currently returns ID + pizza size)
    • attachnameAndPrices.js in utils
  • Send the data to the server upon checkout

41 - Coding our Serverless Function

Overview

  • Open up placeOrder.js and open handler
    • Adding in logic for required fields. Logging them for initial visiblity
    • You should see that the function is running within the netlify terminal
    • NOTE: If nothing shows up, kill netlify and restart with netlify dev
    • Within a for loop of required fields we are checking that each is included within the body
      • If not included, return an error message
      • Go to Network --> placeOrder --> Response --> message from bad results is displayed there

42 - Setting Error, Loading and Success States

Overview

  • Making placeOrder.js handler take a few more seconds
    • Can use a package caleld wait or write ann async function

Disabling Fieldsets during testing

  • Add the attribute disabled={loading} to each fieldset
  • This will prevent you from editing any fields while loading is set to True

43 - Creating a Honey Pot to defend against bots

Overview

  • For forms that are submittable w/o bot detection, they get submitted with spam
  • Deters bots from submitting thousands per second
  • Podcast on Syntax.FM - Hasty Treat - Forms, Captchas, Honeypots, Dealing with Malicious Users
  • Best way to do it is to add a CAPTCHA
  • Other suggestionn is to add a honeypot

Honeypot

  • A field in your contact form that a user isn't supposed to fill out

Hiding the Attribute

  • Cant just use the hidden attribute - bot is smarter than that
  • Give the honeypot a className of pestoSauce
  • Go to OrderStyles.js
    • Add display: none; to .pestoSauce { }
  • Apparently, bots are unable to figure out if an element is visible via CSS or not (comes from ppl working on prod/client sites)
    • Can also scale to 0 or 1 pixel, text-indent, etc
    • Also want to make sure that you aren't throwing off screen-readers (some CSS attributes will read out loud to screen readers)

44 - Creating a one-off Store Settings Page

Overview

  • Common thing in a site is to have a settings page
  • Control everything from headlines to selecting content that you want to display on the home page
  • Otherwise known as Option or One-Off pages
  • Not going to be multiple of them, but still need to be stored in databases
  • On the home page, we want someone to be able to go into the backenda nd then be able to select:
    • Who is currently working
    • What pizzas are currently available by the slice
  • We want to be able to pull that into our frontend

Steps

  • kill sanity & restart
  • make a schema for that setting
  • NOTE: Done the same way as any other data type
    • Allows you to create multiple versions of a settings page
    • But, we are going to restrict creating multiple versions by modifying the sidebar we have in the Sanity backend
  • In Sanity, open schemas/pizza.js and copy over to storeSettings.js
    • Create a schema for storeSettings. Fields are an array that references another array, slicemasters
    • Import storeSettings into schema.js and pass into the function createSchema
  • This will now be visible in the Sanity backend and we can create store settings

Preventing Changes to the Store Schema

  • We want a feature that goes directly to the single Settings file that is configured in the DB with no potential for them to make any overwrites or new Stores
  • In the root of your Sanity folder, create a file called sidebar.js
    • Import a custom plugin for sanity in
  • Go to sanity.json and add the new part to the parts array

45 - Custom Hook for Client Side Data Fetching

Overview

  • Pulling currently slicing pizzas + slicemasters
  • Downside of Gatsby:
    • This data is very time sensitive
    • Can change within a second and the website must be updated in a second
    • Probably not best suited for running through Gatsby's GraphQL
    • People that were slicing + pizzas availalbe are going to be those listed UNTIL the site is regenerated
  • There is probably a way to trigger a build, but it makes more sense to fetch this client side rather than at build time
  • Gatsby doesnt have an API
    • There is only an API at build time
    • No GraphQL API that we can hit after
  • Must go directly to the source of the data - from the client side on the browser
    • This is common
  • So, we are going to build client side
    • When you load the page, it will go and fetch the data

Steps

  • In gatsby, open up index.js
  • Fetching the data
    • If we cant get it from our Gatsby GraphQL, we have to get it from Sanity
    • To get your Sanity endpoint:
      • Quit the process and run sanity graphql list
      • This will give you a URL to your graph database
  • Difference betweenn Sanity GraphQL + Gatsby GraphQL
    • Queries wont be exactly the same
    • will be allPizza instead of sanityallPizza

Creating a Custom Hook

  • In gatsby, create a new file in utils called useLatestData.js
  • Create a function w/ the same name
  • NOTE: You need to run sanity graphql deploy production to add the storeSetting schema to your GrapQL database
    • As soon as the data changes in the Sanity backend, the updated data will be visible in the browser (next page load)
  • Fetching the data

DEBUGGING TIP -- SyntaxError at position 0 // line 1 column 1

  • Means you got data back and tried to turn it into an object, but it wasn't JSON to begin with
  • APPROACH: Go into Network, look for the XHR request
    • Tried to ping undefined as the URL when in reality we need to hit the GraphQL endpoint
    • Likely need to restart the gatsby process to take into account the additional env value

CORS Issue - Accessing the GraphQL Endpoint

  • In order to go to the graphQL endpoint from a URL, you have to allow that URL in Sanity
  • Go to sanity.io --> Login --> Project --> Settings --> API
    • CORS Origins --> Hosts that can connect to the project API are limited to http://localhost:3333
    • Add a new origin http://localhost:*
    • Allow credentials
    • Add new origin
  • This will return the data to the API

Setting API data to the state

  • In useLatestData.js:
    • Set the state of hotSlices and slicemasters to the API results with setHotSlices and setSlicemasters
  • Now, we want to confirm that this is being set to state
    • In index.js, log the results and confirm that the state is updated
  • NOTE: When checking the console you will see the Object is output three times:
    • First output is the initial state, which has undefined values
    • Second output is the updated state from the first setState function executed from useEffect
    • Third output is the updated state from the second setstate function
    • No performance impact to update the state twice
  • Take the Data and Pass it into components

Module 12 - Client Side Data

46 - Creating a Skeleton Screen while Loading Items

Overview

  • Going to use several grids
  • Wes prefers to put all grids into separate files
  • In styles, create new file Grids.js

Loading Itmems

  • Because the page loads once you actually load the page, we need something to put there to indicate something is happening
  • In Grids.js, create a new component called IemsGrid
  • Add another component called LoadingGrid to hold the items
  • On index.js, add the LoadingGrid to each component (slicemasters and hotSlices)
    • Mapping over the count prop and creating both <p> and <img> elements for the page load
    • Getting an image placeholder while the image loads
  • In Grid.js, adding styles for a single grid item

Conditionally Show Loading While in Loading State

  • Go to index.js

47 - Displaying the Home Page Data

Overview

  • Need to amend GraphQL query to get more data
  • TIP If you add gql in front of a graphql query (as a string), VSCode will auto format it for you + do syntax highlighting
  • PROBLEM: We aren't importing a graphQL library into our frontend - isnt necessary
    • But, we can fake out VSCODE
    • Create a tag gql and assign to String.raw; in useLatestDatajs
    • Good for syntax highlighting w/o importing a library
  • Add more content to query in useLatestData.js

DEBUGGING - Cannot access property "StoreSettings"

  • Happens when something goes wrong with the fetch request
  • Didnt catch the error --> go back to useLatestData and catch the error

Getting Data onto the Page + Styling

  • Passing slicemasters and hotSlices into a component ItemGrid
  • Create new component ItemGrid.js in components
  • Add a .tilt {} style to the GlobalStyles.js

Module 13 - Building, Deployment and Responsive Design

48 - Building and Deploying our Headless Sanity CMS

Overview

  • Backend Deployment
    • Need the entire Sanity CMS to be online somewhere
    • Santiy Studios has been our backend and you can host it directly on Sanity
      • sanity deploy
      • Studio Name: Enter a hostname
      • NOTE: You need a static folder in Sanity for this to work
    • You can also host it yourself
      • sanity --> dist
      • If you wanted to host it yourself, you can use these files
      • Just add the domain name to the allowed API routes
    • Wes suggests hosting on Sanity

49 - Building our Gatsby Site

Overview

  • Remember, Gatsby is just a static site generator
  • To generate the JS, execute npm run build, which will run gatsby build
  • Can take anywhere from 15-20S up to 15 minutes
    • If you have images that need to be resized on build time, that is what causes a lot of time
    • (Wes' personal site takes ~15 min to build w/ 500 images)
  • Sanity or any other image hosting service does image resizing on their side

Reviewing the Public Folder

  • Gatsby --> public will contain all of the pages that you need
  • There are a few options for hosting (to cover next)

50 - Deploying to Netlify

Overview

  • Netflify is the most popular option
    • Takes care of making the website fast to load + hosting
    • Will also do the build for you
      • Can be triggered from (1) changes in data to sanity (2) changes to Git repo
    • Also host serverless functions
  • Create an account on Netlify
  • Go to New site from Git
  • Connect to Git provider
    • Add site to GitHub
      • (You can either put the Gatsby folder or Gatsby + Sanity)
    • Initialize git with git init
    • Add .gitignore contents (can drop in generic contents from Wes' repo)
    • Push contents
  • You can allow all access to Git repos or a single one
  • Select Branch to deploy
  • Build command: npm run build
  • Publish directory: gatsby/public

Additional Steps

  • Won't work immediately
  • Sanity will look in main repo for your site - not in the gastby subdirectory
    • Option didn't seem to be available when deploying the site
  • Now go back to Site settings --> Build & deploy --> edit settings
    • Base directory: Directory to change to before starting a build. This is where we will look for package.json/.nvmrc/etc.
      • Set to gastby
    • Publish directory: Set to gatsby/ public
  • Now, go back to Site Overview --> Production deploys
    • TIP: If you are ever having trouble with your deploy, choose Clear cache and deploy site
      • Deploy site will just use the currently cached items
  • This will run the same process that we did

Passing in Environment Variables

  • Our site won't load properly because our environment variables are not in Git
  • Go to Deploy Settings --> Environment --> Environment variables
    • Move variables into page
    • GATSBY_HOT_RELOADER isnt necessary -- only for development
    • GATSBY_SERVERLESS_BASE is no longer going to be locahost
      • Instead, you can use a relative path
      • *This is fine because Netliffy always runs the site on a new domain / sub domain
  • Double check to remove any console.log statements for a production website

CORS Issue with New Site

  • Because it is now hosted on Netlify, Sanity is not going to allow fetch requests
  • Login to Sanity.io --> go to project --> API --> Add new CORS origin
    • Add the domain name for your site
    • You can either put the entire domain name or `*.

51 - Hosting the Gatsby Website on your own server

Overview

52 - Making the Website Responsive

Overview