├── .prettierignore ├── src ├── images │ ├── gatsby-icon.png │ └── gatsby-astronaut.png ├── markdown-pages │ └── 1.md ├── pages │ ├── 404.js │ ├── page-2.js │ └── index.js ├── components │ ├── header.js │ ├── image.js │ ├── layout.js │ ├── seo.js │ └── layout.css └── templates │ └── blogTemplate.js ├── .prettierrc ├── gatsby-browser.js ├── gatsby-ssr.js ├── LICENSE ├── .gitignore ├── gatsby-node.js ├── package.json ├── gatsby-config.js └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaedahBatool/Optimizing-Gatsby-Site-For-Production/HEAD/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /src/images/gatsby-astronaut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MaedahBatool/Optimizing-Gatsby-Site-For-Production/HEAD/src/images/gatsby-astronaut.png -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /src/markdown-pages/1.md: -------------------------------------------------------------------------------- 1 | --- 2 | path: "/blog/my-first-post" 3 | date: "2019-09-25" 4 | title: "My blog post for WordSesh September 2019 edition." 5 | --- 6 | 7 | ## Hello, John Doe! 8 | 9 | `youtube: https://www.youtube.com/watch?v=2Xc9gXyf2G4` 10 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import Layout from "../components/layout" 4 | import SEO from "../components/seo" 5 | 6 | const NotFoundPage = () => ( 7 | 8 | 9 |

NOT FOUND

10 |

You just hit a route that doesn't exist... the sadness.

11 |
12 | ) 13 | 14 | export default NotFoundPage 15 | -------------------------------------------------------------------------------- /src/pages/page-2.js: -------------------------------------------------------------------------------- 1 | import { Link } from "gatsby" 2 | import React from "react" 3 | import Layout from "../components/layout" 4 | import SEO from "../components/seo" 5 | 6 | const SecondPage = () => ( 7 | 8 | 9 |

Hi from the second page

10 | Go back to the homepage 11 |
12 | ) 13 | 14 | export default SecondPage 15 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import { Link } from "gatsby" 2 | import React from "react" 3 | import Image from "../components/image" 4 | import Layout from "../components/layout" 5 | import SEO from "../components/seo" 6 | 7 | const IndexPage = () => ( 8 | 9 | 10 |

Hi people

11 |

Welcome to your new Gatsby site.

12 |

Now go build something great.

13 | `youtube: 2Xc9gXyf2G4` 14 |
15 | 16 |
17 | Go to page 2 18 |
19 | ) 20 | 21 | export default IndexPage 22 | -------------------------------------------------------------------------------- /src/components/header.js: -------------------------------------------------------------------------------- 1 | import { Link } from "gatsby" 2 | import PropTypes from "prop-types" 3 | import React from "react" 4 | 5 | const Header = ({ siteTitle }) => ( 6 |
12 |
19 |

20 | 27 | {siteTitle} 28 | 29 |

30 |
31 |
32 | ) 33 | 34 | Header.propTypes = { 35 | siteTitle: PropTypes.string, 36 | } 37 | 38 | Header.defaultProps = { 39 | siteTitle: ``, 40 | } 41 | 42 | export default Header 43 | -------------------------------------------------------------------------------- /src/templates/blogTemplate.js: -------------------------------------------------------------------------------- 1 | // Step #4: Create a page template for the Markdown files 2 | import { graphql } from "gatsby" 3 | import React from "react" 4 | 5 | export default function Template({ 6 | data, // this prop will be injected by the GraphQL query below. 7 | }) { 8 | const { markdownRemark } = data // data.markdownRemark holds our post data 9 | const { frontmatter, html } = markdownRemark 10 | return ( 11 |
12 |
13 |

{frontmatter.title}

14 |

{frontmatter.date}

15 |
19 |
20 |
21 | ) 22 | } 23 | 24 | export const pageQuery = graphql` 25 | query($path: String!) { 26 | markdownRemark(frontmatter: { path: { eq: $path } }) { 27 | html 28 | frontmatter { 29 | date(formatString: "MMMM DD, YYYY") 30 | path 31 | title 32 | } 33 | } 34 | } 35 | ` 36 | -------------------------------------------------------------------------------- /src/components/image.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useStaticQuery, graphql } from "gatsby" 3 | import Img from "gatsby-image" 4 | 5 | /* 6 | * This component is built using `gatsby-image` to automatically serve optimized 7 | * images with lazy loading and reduced file sizes. The image is loaded using a 8 | * `useStaticQuery`, which allows us to load the image from directly within this 9 | * component, rather than having to pass the image data down from pages. 10 | * 11 | * For more information, see the docs: 12 | * - `gatsby-image`: https://gatsby.dev/gatsby-image 13 | * - `useStaticQuery`: https://www.gatsbyjs.org/docs/use-static-query/ 14 | */ 15 | 16 | const Image = () => { 17 | const data = useStaticQuery(graphql` 18 | query { 19 | placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) { 20 | childImageSharp { 21 | fluid(maxWidth: 300) { 22 | ...GatsbyImageSharpFluid 23 | } 24 | } 25 | } 26 | } 27 | `) 28 | 29 | return 30 | } 31 | 32 | export default Image 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /src/components/layout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Layout component that queries for data 3 | * with Gatsby's useStaticQuery component 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import { useStaticQuery, graphql } from "gatsby" 11 | 12 | import Header from "./header" 13 | import "./layout.css" 14 | 15 | const Layout = ({ children }) => { 16 | const data = useStaticQuery(graphql` 17 | query SiteTitleQuery { 18 | site { 19 | siteMetadata { 20 | title 21 | } 22 | } 23 | } 24 | `) 25 | 26 | return ( 27 | <> 28 |
29 |
37 |
{children}
38 |
39 | © {new Date().getFullYear()}, Built with 40 | {` `} 41 | Gatsby 42 |
43 |
44 | 45 | ) 46 | } 47 | 48 | Layout.propTypes = { 49 | children: PropTypes.node.isRequired, 50 | } 51 | 52 | export default Layout 53 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Node APIs in this file. 3 | * 4 | */ 5 | 6 | // Step #5: Create static pages using createPage API 7 | const path = require(`path`) 8 | 9 | exports.createPages = async ({ actions, graphql, reporter }) => { 10 | const { createPage } = actions 11 | 12 | const blogPostTemplate = path.resolve(`src/templates/blogTemplate.js`) 13 | 14 | const result = await graphql(` 15 | { 16 | allMarkdownRemark( 17 | sort: { order: DESC, fields: [frontmatter___date] } 18 | limit: 1000 19 | ) { 20 | edges { 21 | node { 22 | frontmatter { 23 | path 24 | } 25 | } 26 | } 27 | } 28 | } 29 | `) 30 | 31 | // Handle errors 32 | if (result.errors) { 33 | reporter.panicOnBuild(`Error while running GraphQL query.`) 34 | return 35 | } 36 | 37 | result.data.allMarkdownRemark.edges.forEach(({ node }) => { 38 | createPage({ 39 | path: node.frontmatter.path, 40 | component: blogPostTemplate, 41 | context: {}, // additional data can be passed via context 42 | }) 43 | }) 44 | } 45 | 46 | const { createFilePath } = require(`gatsby-source-filesystem`) 47 | 48 | exports.onCreateNode = ({ node, actions, getNode }) => { 49 | const { createNodeField } = actions 50 | if (node.internal.type === `MarkdownRemark`) { 51 | const value = createFilePath({ node, getNode }) 52 | createNodeField({ 53 | name: `slug`, 54 | node, 55 | value, 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-default", 3 | "private": true, 4 | "description": "A simple starter to get up and developing quickly with Gatsby", 5 | "version": "0.1.0", 6 | "author": "Kyle Mathews ", 7 | "dependencies": { 8 | "gatsby": "^2.15.11", 9 | "gatsby-image": "^2.2.17", 10 | "gatsby-plugin-feed": "^2.3.13", 11 | "gatsby-plugin-manifest": "^2.2.15", 12 | "gatsby-plugin-offline": "^2.2.10", 13 | "gatsby-plugin-react-helmet": "^3.1.6", 14 | "gatsby-plugin-sharp": "^2.2.20", 15 | "gatsby-plugin-sitemap": "^2.2.11", 16 | "gatsby-remark-embed-video": "^1.7.1", 17 | "gatsby-remark-images": "^3.1.20", 18 | "gatsby-remark-responsive-iframe": "^2.2.14", 19 | "gatsby-source-filesystem": "^2.1.21", 20 | "gatsby-transformer-remark": "^2.6.21", 21 | "gatsby-transformer-sharp": "^2.2.13", 22 | "prop-types": "^15.7.2", 23 | "react": "^16.9.0", 24 | "react-dom": "^16.9.0", 25 | "react-helmet": "^5.2.1" 26 | }, 27 | "devDependencies": { 28 | "prettier": "^1.18.2" 29 | }, 30 | "keywords": [ 31 | "gatsby" 32 | ], 33 | "license": "MIT", 34 | "scripts": { 35 | "build": "gatsby build", 36 | "develop": "gatsby develop", 37 | "format": "prettier --write \"**/*.{js,jsx,json,md}\"", 38 | "start": "npm run develop", 39 | "serve": "gatsby serve", 40 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing \"" 41 | }, 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 45 | }, 46 | "bugs": { 47 | "url": "https://github.com/gatsbyjs/gatsby/issues" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/components/seo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SEO component that queries for data with 3 | * Gatsby's useStaticQuery React hook 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import Helmet from "react-helmet" 11 | import { useStaticQuery, graphql } from "gatsby" 12 | 13 | function SEO({ description, lang, meta, title }) { 14 | const { site } = useStaticQuery( 15 | graphql` 16 | query { 17 | site { 18 | siteMetadata { 19 | title 20 | description 21 | author 22 | } 23 | } 24 | } 25 | ` 26 | ) 27 | 28 | const metaDescription = description || site.siteMetadata.description 29 | 30 | return ( 31 | 72 | ) 73 | } 74 | 75 | SEO.defaultProps = { 76 | lang: `en`, 77 | meta: [], 78 | description: ``, 79 | } 80 | 81 | SEO.propTypes = { 82 | description: PropTypes.string, 83 | lang: PropTypes.string, 84 | meta: PropTypes.arrayOf(PropTypes.object), 85 | title: PropTypes.string.isRequired, 86 | } 87 | 88 | export default SEO 89 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: `WordSesh September 2019`, 4 | description: `Kick off with your next, Gatsby website by optimizing it for sitemaps, handling markdown pages, embedding videos and rss feed.`, 5 | author: `@MaedahBatool`, 6 | siteUrl: `https://maedahbatool.com`, 7 | siteUrlNoSlash: `https://maedahbatool.com`, 8 | }, 9 | plugins: [ 10 | // Adding RSS Feed to Your Gatsby Blog 11 | 12 | { 13 | resolve: `gatsby-plugin-feed`, 14 | options: { 15 | query: ` 16 | { 17 | site { 18 | siteMetadata { 19 | title 20 | description 21 | siteUrl 22 | site_url: siteUrl 23 | } 24 | } 25 | } 26 | `, 27 | feeds: [ 28 | { 29 | serialize: ({ query: { site, allMarkdownRemark } }) => { 30 | return allMarkdownRemark.edges.map(edge => { 31 | return Object.assign({}, edge.node.frontmatter, { 32 | description: edge.node.excerpt, 33 | date: edge.node.frontmatter.date, 34 | url: site.siteMetadata.siteUrl + edge.node.fields.slug, 35 | guid: site.siteMetadata.siteUrl + edge.node.fields.slug, 36 | custom_elements: [{ "content:encoded": edge.node.html }], 37 | }) 38 | }) 39 | }, 40 | query: ` 41 | { 42 | allMarkdownRemark( 43 | sort: { order: DESC, fields: [frontmatter___date] }, 44 | ) { 45 | edges { 46 | node { 47 | excerpt 48 | html 49 | fields { slug } 50 | frontmatter { 51 | title 52 | date 53 | } 54 | } 55 | } 56 | } 57 | } 58 | `, 59 | output: "/rss.xml", 60 | title: "My Demo Site's RSS Feed", 61 | // optional configuration to insert feed reference in pages: 62 | // if `string` is used, it will be used to create RegExp and then test if pathname of 63 | // current page satisfied this regular expression; 64 | // if not provided or `undefined`, all pages will have feed reference inserted 65 | match: "^/blog/", 66 | }, 67 | ], 68 | }, 69 | }, 70 | // Adding Sitemap to Your Gatsby Blog 71 | { 72 | resolve: `gatsby-plugin-sitemap`, 73 | options: { 74 | query: ` 75 | { 76 | site { 77 | siteMetadata { 78 | siteUrl 79 | } 80 | } 81 | 82 | allSitePage { 83 | edges { 84 | node { 85 | path 86 | } 87 | } 88 | } 89 | }`, 90 | serialize: ({ site, allSitePage }) => 91 | allSitePage.edges.map(edge => { 92 | return { 93 | url: site.siteMetadata.siteUrl + edge.node.path, 94 | changefreq: `daily`, 95 | priority: 0.7, 96 | } 97 | }), 98 | }, 99 | }, 100 | { 101 | resolve: `gatsby-source-filesystem`, 102 | options: { 103 | name: `images`, 104 | path: `${__dirname}/src/images`, 105 | }, 106 | }, 107 | `gatsby-transformer-sharp`, 108 | `gatsby-plugin-sharp`, 109 | { 110 | resolve: `gatsby-source-filesystem`, 111 | options: { 112 | name: `markdown-pages`, 113 | path: `${__dirname}/src/markdown-pages`, 114 | }, 115 | }, 116 | // Remark. 117 | { 118 | resolve: `gatsby-transformer-remark`, 119 | options: { 120 | plugins: [ 121 | { 122 | // Using gatsby-remark-embed-video before gatsby-remark-images & gatsby-remark-responsive-iframe plugins. 123 | resolve: `gatsby-remark-embed-video`, 124 | options: { 125 | maxWidth: 800, 126 | ratio: 1.77, 127 | height: 400, 128 | related: false, 129 | noIframerder: true, 130 | }, 131 | }, 132 | { 133 | resolve: `gatsby-remark-images`, 134 | options: { 135 | maxWidth: 590, 136 | }, 137 | }, 138 | { 139 | resolve: `gatsby-remark-responsive-iframe`, 140 | options: { 141 | wrapperStyle: `margin-bottom: 1.0725rem`, 142 | }, 143 | }, 144 | ], 145 | }, 146 | }, 147 | ], 148 | } 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | gatsby-site-production 3 | 4 |
Optimizing Your Gatsby.js Website for Production 5 |

6 | 7 |
8 | 9 | Building static sites with `React.js` using **Gatsby** provides an **easy to deploy setup**, **blazing fast speed**, and **smooth developer experience**. We are all aware of the three fundamentals of website development i.e., 10 | 11 | - Development 12 | - Staging 13 | - Production 14 | 15 | **JAMstack (JavaScript APIs Markup)** is awesome and being the recent trend I am going to explain some of the best ways through which you can optimize your `Gatsby.js` website before production. 16 | 17 | Before we start make sure you have configured a basic Gatsby project setup. 18 | 19 | ## Optimizing Gatsby.js Site 20 | 21 |
22 | Step #0: Don't have a Gatsby site setup? Read this. (CLICK TO EXPAND!) 23 | 24 | In case you are an absolute beginner and this is your first time with Gatsby.js, all you need to do is follow these steps mentioned below. These will help you set up a basic Gatsby project. 25 | 26 | - Install the Gatsby CLI by typing the following command in your terminal 27 | 28 | ```sh 29 | npm install -g gatsby-cli 30 | ``` 31 | 32 | - Next, create a new Gatsby.js site through the following. 33 | 34 | ```sh 35 | gatsby new site-name 36 | ``` 37 | 38 | - To access your site folder contents type the following. 39 | 40 | ```sh 41 | cd site-name 42 | ``` 43 | 44 | - Finally, start the development server to begin building your Gatsby.js site. 45 | 46 | ```sh 47 | gatsby develop 48 | ``` 49 | 50 |
51 | 52 | To optimize a Gatsby site make sure you have the following functionalities set up and running: 53 | 54 | - Sitemaps 55 | - Markdown Pages 56 | - Embed Videos 57 | - RSS Feed 58 | 59 | ### 🔘Adding Custom Sitemaps 60 | 61 | Sitemaps maintains a list of all pages to tell search engines like Google about the organization of your site content. These prompts information about an unindexed 62 | page to get it appropriately indexed. They are equally important for new and old sites. But a new website needs sitemap since it is difficult for search engines to find posts and pages of a new site. 63 | 64 | You can add custom sitemaps in Gatsby through the `[gatsby-plugin-sitemap]` plugin. 65 | 66 | Inside your terminal type the following to install this plugin. 67 | 68 | ```sh 69 | npm install -- save gatsby-plugin-sitemap 70 | ``` 71 | 72 | ### 🔘 Adding Markdown Pages 73 | 74 | Gatsby plugins can read folders/files with markdown and create pages from them. Is important since writing in markdown is always easy of eyes, user friendly with less errors. So, the process of adding and rendering markdown in Gatsby is that the plugins read files from filesystem. Then it transforms markdown to html and frontmatter to data. Finally, using the create page API you build page components. 75 | 76 | All this is done via using the `gatsby-source-filesystem` plugin. 77 | 78 | Inside your terminal type the following to install this plugin. 79 | 80 | ```sh 81 | npm install -- save gatsby-file-sourcesystem 82 | ``` 83 | 84 | But to make this plugin work you need a pre-requisite plugin i.e., `gatsby-transformer-remark` which is installed via the following: 85 | 86 | ```sh 87 | npm install -- save gatsby-transformer-remark 88 | ``` 89 | 90 | ### 🔘 Embedding Videos in Gatsby.js 91 | 92 | Different web applications render media files especially videos and GIFs differently. With Gatsby, plugins helps you source videos from a variety of video hosts like YouTube, Vimeo, Dailymotion, etc. 93 | 94 | The `gatsby-remark-embed-video` plugin is a great piece of software for this purpose. 95 | 96 | In your terminal type the following for plugin installation: 97 | 98 | ```sh 99 | npm i gatsby-remark-embed-video 100 | ``` 101 | 102 | Also, this plugin require some other plugins to be installed first. These are: 103 | 104 | - `gatsby-remark-responsive-iframe` 105 | - `gatsby-transformer-remark` 106 | - `gatsby-remark-images` 107 | 108 | Note that if you’re using the `gatsby-remark-responsive-iframe` plugin, you have to ensure that the `gatsby-remark-embed-video` plugin is defined first. 109 | 110 | ### 🔘 Adding RSS Feed 111 | 112 | When developing a Gatsby.js, website it is important to optimize for RSS Feed since it makes your site content easy to subscribe through feed reader apps. 113 | 114 | The `gatsby-plugin-feed` serves the purpose really well. 115 | 116 | Install it via the following command: 117 | 118 | ```sh 119 | npm install -- save gatsby-plugin-feed 120 | ``` 121 | 122 | It needs the following two plugins as a pre-reqs: 123 | 124 | - `gatsby-transformer-remark` 125 | - `gatsby-source-filesystem` 126 | 127 | ### 🔘 Final Build & Deploy 128 | 129 | After you have optimized your Gatsby website for the aforementioned functionalities you can run the final build command and then deploy it to some live environment. I am a huge fan of **Netlify** and host all my JAMstack sites through it. 130 | 131 | That's about it! I hope you find this learning material helpful. You can share your feedback by 🌟this repo. For any queries and suggestions PRs are welcomed. 132 | 133 | 🔘 **SLIDES**: https://Maedah.dev/WDSlidesSep19 134 | 135 | > 👋 **[Follow @MaedahBatool on Twitter](https://twitter.com/MaedahBatool/) →** 136 | -------------------------------------------------------------------------------- /src/components/layout.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: sans-serif; 3 | -ms-text-size-adjust: 100%; 4 | -webkit-text-size-adjust: 100%; 5 | } 6 | body { 7 | margin: 0; 8 | -webkit-font-smoothing: antialiased; 9 | -moz-osx-font-smoothing: grayscale; 10 | } 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | main, 19 | menu, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | audio, 26 | canvas, 27 | progress, 28 | video { 29 | display: inline-block; 30 | } 31 | audio:not([controls]) { 32 | display: none; 33 | height: 0; 34 | } 35 | progress { 36 | vertical-align: baseline; 37 | } 38 | [hidden], 39 | template { 40 | display: none; 41 | } 42 | a { 43 | background-color: transparent; 44 | -webkit-text-decoration-skip: objects; 45 | } 46 | a:active, 47 | a:hover { 48 | outline-width: 0; 49 | } 50 | abbr[title] { 51 | border-bottom: none; 52 | text-decoration: underline; 53 | text-decoration: underline dotted; 54 | } 55 | b, 56 | strong { 57 | font-weight: inherit; 58 | font-weight: bolder; 59 | } 60 | dfn { 61 | font-style: italic; 62 | } 63 | h1 { 64 | font-size: 2em; 65 | margin: 0.67em 0; 66 | } 67 | mark { 68 | background-color: #ff0; 69 | color: #000; 70 | } 71 | small { 72 | font-size: 80%; 73 | } 74 | sub, 75 | sup { 76 | font-size: 75%; 77 | line-height: 0; 78 | position: relative; 79 | vertical-align: baseline; 80 | } 81 | sub { 82 | bottom: -0.25em; 83 | } 84 | sup { 85 | top: -0.5em; 86 | } 87 | img { 88 | border-style: none; 89 | } 90 | svg:not(:root) { 91 | overflow: hidden; 92 | } 93 | code, 94 | kbd, 95 | pre, 96 | samp { 97 | font-family: monospace, monospace; 98 | font-size: 1em; 99 | } 100 | figure { 101 | margin: 1em 40px; 102 | } 103 | hr { 104 | box-sizing: content-box; 105 | height: 0; 106 | overflow: visible; 107 | } 108 | button, 109 | input, 110 | optgroup, 111 | select, 112 | textarea { 113 | font: inherit; 114 | margin: 0; 115 | } 116 | optgroup { 117 | font-weight: 700; 118 | } 119 | button, 120 | input { 121 | overflow: visible; 122 | } 123 | button, 124 | select { 125 | text-transform: none; 126 | } 127 | [type="reset"], 128 | [type="submit"], 129 | button, 130 | html [type="button"] { 131 | -webkit-appearance: button; 132 | } 133 | [type="button"]::-moz-focus-inner, 134 | [type="reset"]::-moz-focus-inner, 135 | [type="submit"]::-moz-focus-inner, 136 | button::-moz-focus-inner { 137 | border-style: none; 138 | padding: 0; 139 | } 140 | [type="button"]:-moz-focusring, 141 | [type="reset"]:-moz-focusring, 142 | [type="submit"]:-moz-focusring, 143 | button:-moz-focusring { 144 | outline: 1px dotted ButtonText; 145 | } 146 | fieldset { 147 | border: 1px solid silver; 148 | margin: 0 2px; 149 | padding: 0.35em 0.625em 0.75em; 150 | } 151 | legend { 152 | box-sizing: border-box; 153 | color: inherit; 154 | display: table; 155 | max-width: 100%; 156 | padding: 0; 157 | white-space: normal; 158 | } 159 | textarea { 160 | overflow: auto; 161 | } 162 | [type="checkbox"], 163 | [type="radio"] { 164 | box-sizing: border-box; 165 | padding: 0; 166 | } 167 | [type="number"]::-webkit-inner-spin-button, 168 | [type="number"]::-webkit-outer-spin-button { 169 | height: auto; 170 | } 171 | [type="search"] { 172 | -webkit-appearance: textfield; 173 | outline-offset: -2px; 174 | } 175 | [type="search"]::-webkit-search-cancel-button, 176 | [type="search"]::-webkit-search-decoration { 177 | -webkit-appearance: none; 178 | } 179 | ::-webkit-input-placeholder { 180 | color: inherit; 181 | opacity: 0.54; 182 | } 183 | ::-webkit-file-upload-button { 184 | -webkit-appearance: button; 185 | font: inherit; 186 | } 187 | html { 188 | font: 112.5%/1.45em georgia, serif; 189 | box-sizing: border-box; 190 | overflow-y: scroll; 191 | } 192 | * { 193 | box-sizing: inherit; 194 | } 195 | *:before { 196 | box-sizing: inherit; 197 | } 198 | *:after { 199 | box-sizing: inherit; 200 | } 201 | body { 202 | color: hsla(0, 0%, 0%, 0.8); 203 | font-family: georgia, serif; 204 | font-weight: normal; 205 | word-wrap: break-word; 206 | font-kerning: normal; 207 | -moz-font-feature-settings: "kern", "liga", "clig", "calt"; 208 | -ms-font-feature-settings: "kern", "liga", "clig", "calt"; 209 | -webkit-font-feature-settings: "kern", "liga", "clig", "calt"; 210 | font-feature-settings: "kern", "liga", "clig", "calt"; 211 | } 212 | img { 213 | max-width: 100%; 214 | margin-left: 0; 215 | margin-right: 0; 216 | margin-top: 0; 217 | padding-bottom: 0; 218 | padding-left: 0; 219 | padding-right: 0; 220 | padding-top: 0; 221 | margin-bottom: 1.45rem; 222 | } 223 | h1 { 224 | margin-left: 0; 225 | margin-right: 0; 226 | margin-top: 0; 227 | padding-bottom: 0; 228 | padding-left: 0; 229 | padding-right: 0; 230 | padding-top: 0; 231 | margin-bottom: 1.45rem; 232 | color: inherit; 233 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 234 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 235 | font-weight: bold; 236 | text-rendering: optimizeLegibility; 237 | font-size: 2.25rem; 238 | line-height: 1.1; 239 | } 240 | h2 { 241 | margin-left: 0; 242 | margin-right: 0; 243 | margin-top: 0; 244 | padding-bottom: 0; 245 | padding-left: 0; 246 | padding-right: 0; 247 | padding-top: 0; 248 | margin-bottom: 1.45rem; 249 | color: inherit; 250 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 251 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 252 | font-weight: bold; 253 | text-rendering: optimizeLegibility; 254 | font-size: 1.62671rem; 255 | line-height: 1.1; 256 | } 257 | h3 { 258 | margin-left: 0; 259 | margin-right: 0; 260 | margin-top: 0; 261 | padding-bottom: 0; 262 | padding-left: 0; 263 | padding-right: 0; 264 | padding-top: 0; 265 | margin-bottom: 1.45rem; 266 | color: inherit; 267 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 268 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 269 | font-weight: bold; 270 | text-rendering: optimizeLegibility; 271 | font-size: 1.38316rem; 272 | line-height: 1.1; 273 | } 274 | h4 { 275 | margin-left: 0; 276 | margin-right: 0; 277 | margin-top: 0; 278 | padding-bottom: 0; 279 | padding-left: 0; 280 | padding-right: 0; 281 | padding-top: 0; 282 | margin-bottom: 1.45rem; 283 | color: inherit; 284 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 285 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 286 | font-weight: bold; 287 | text-rendering: optimizeLegibility; 288 | font-size: 1rem; 289 | line-height: 1.1; 290 | } 291 | h5 { 292 | margin-left: 0; 293 | margin-right: 0; 294 | margin-top: 0; 295 | padding-bottom: 0; 296 | padding-left: 0; 297 | padding-right: 0; 298 | padding-top: 0; 299 | margin-bottom: 1.45rem; 300 | color: inherit; 301 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 302 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 303 | font-weight: bold; 304 | text-rendering: optimizeLegibility; 305 | font-size: 0.85028rem; 306 | line-height: 1.1; 307 | } 308 | h6 { 309 | margin-left: 0; 310 | margin-right: 0; 311 | margin-top: 0; 312 | padding-bottom: 0; 313 | padding-left: 0; 314 | padding-right: 0; 315 | padding-top: 0; 316 | margin-bottom: 1.45rem; 317 | color: inherit; 318 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 319 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 320 | font-weight: bold; 321 | text-rendering: optimizeLegibility; 322 | font-size: 0.78405rem; 323 | line-height: 1.1; 324 | } 325 | hgroup { 326 | margin-left: 0; 327 | margin-right: 0; 328 | margin-top: 0; 329 | padding-bottom: 0; 330 | padding-left: 0; 331 | padding-right: 0; 332 | padding-top: 0; 333 | margin-bottom: 1.45rem; 334 | } 335 | ul { 336 | margin-left: 1.45rem; 337 | margin-right: 0; 338 | margin-top: 0; 339 | padding-bottom: 0; 340 | padding-left: 0; 341 | padding-right: 0; 342 | padding-top: 0; 343 | margin-bottom: 1.45rem; 344 | list-style-position: outside; 345 | list-style-image: none; 346 | } 347 | ol { 348 | margin-left: 1.45rem; 349 | margin-right: 0; 350 | margin-top: 0; 351 | padding-bottom: 0; 352 | padding-left: 0; 353 | padding-right: 0; 354 | padding-top: 0; 355 | margin-bottom: 1.45rem; 356 | list-style-position: outside; 357 | list-style-image: none; 358 | } 359 | dl { 360 | margin-left: 0; 361 | margin-right: 0; 362 | margin-top: 0; 363 | padding-bottom: 0; 364 | padding-left: 0; 365 | padding-right: 0; 366 | padding-top: 0; 367 | margin-bottom: 1.45rem; 368 | } 369 | dd { 370 | margin-left: 0; 371 | margin-right: 0; 372 | margin-top: 0; 373 | padding-bottom: 0; 374 | padding-left: 0; 375 | padding-right: 0; 376 | padding-top: 0; 377 | margin-bottom: 1.45rem; 378 | } 379 | p { 380 | margin-left: 0; 381 | margin-right: 0; 382 | margin-top: 0; 383 | padding-bottom: 0; 384 | padding-left: 0; 385 | padding-right: 0; 386 | padding-top: 0; 387 | margin-bottom: 1.45rem; 388 | } 389 | figure { 390 | margin-left: 0; 391 | margin-right: 0; 392 | margin-top: 0; 393 | padding-bottom: 0; 394 | padding-left: 0; 395 | padding-right: 0; 396 | padding-top: 0; 397 | margin-bottom: 1.45rem; 398 | } 399 | pre { 400 | margin-left: 0; 401 | margin-right: 0; 402 | margin-top: 0; 403 | margin-bottom: 1.45rem; 404 | font-size: 0.85rem; 405 | line-height: 1.42; 406 | background: hsla(0, 0%, 0%, 0.04); 407 | border-radius: 3px; 408 | overflow: auto; 409 | word-wrap: normal; 410 | padding: 1.45rem; 411 | } 412 | table { 413 | margin-left: 0; 414 | margin-right: 0; 415 | margin-top: 0; 416 | padding-bottom: 0; 417 | padding-left: 0; 418 | padding-right: 0; 419 | padding-top: 0; 420 | margin-bottom: 1.45rem; 421 | font-size: 1rem; 422 | line-height: 1.45rem; 423 | border-collapse: collapse; 424 | width: 100%; 425 | } 426 | fieldset { 427 | margin-left: 0; 428 | margin-right: 0; 429 | margin-top: 0; 430 | padding-bottom: 0; 431 | padding-left: 0; 432 | padding-right: 0; 433 | padding-top: 0; 434 | margin-bottom: 1.45rem; 435 | } 436 | blockquote { 437 | margin-left: 1.45rem; 438 | margin-right: 1.45rem; 439 | margin-top: 0; 440 | padding-bottom: 0; 441 | padding-left: 0; 442 | padding-right: 0; 443 | padding-top: 0; 444 | margin-bottom: 1.45rem; 445 | } 446 | form { 447 | margin-left: 0; 448 | margin-right: 0; 449 | margin-top: 0; 450 | padding-bottom: 0; 451 | padding-left: 0; 452 | padding-right: 0; 453 | padding-top: 0; 454 | margin-bottom: 1.45rem; 455 | } 456 | noscript { 457 | margin-left: 0; 458 | margin-right: 0; 459 | margin-top: 0; 460 | padding-bottom: 0; 461 | padding-left: 0; 462 | padding-right: 0; 463 | padding-top: 0; 464 | margin-bottom: 1.45rem; 465 | } 466 | iframe { 467 | margin-left: 0; 468 | margin-right: 0; 469 | margin-top: 0; 470 | padding-bottom: 0; 471 | padding-left: 0; 472 | padding-right: 0; 473 | padding-top: 0; 474 | margin-bottom: 1.45rem; 475 | } 476 | hr { 477 | margin-left: 0; 478 | margin-right: 0; 479 | margin-top: 0; 480 | padding-bottom: 0; 481 | padding-left: 0; 482 | padding-right: 0; 483 | padding-top: 0; 484 | margin-bottom: calc(1.45rem - 1px); 485 | background: hsla(0, 0%, 0%, 0.2); 486 | border: none; 487 | height: 1px; 488 | } 489 | address { 490 | margin-left: 0; 491 | margin-right: 0; 492 | margin-top: 0; 493 | padding-bottom: 0; 494 | padding-left: 0; 495 | padding-right: 0; 496 | padding-top: 0; 497 | margin-bottom: 1.45rem; 498 | } 499 | b { 500 | font-weight: bold; 501 | } 502 | strong { 503 | font-weight: bold; 504 | } 505 | dt { 506 | font-weight: bold; 507 | } 508 | th { 509 | font-weight: bold; 510 | } 511 | li { 512 | margin-bottom: calc(1.45rem / 2); 513 | } 514 | ol li { 515 | padding-left: 0; 516 | } 517 | ul li { 518 | padding-left: 0; 519 | } 520 | li > ol { 521 | margin-left: 1.45rem; 522 | margin-bottom: calc(1.45rem / 2); 523 | margin-top: calc(1.45rem / 2); 524 | } 525 | li > ul { 526 | margin-left: 1.45rem; 527 | margin-bottom: calc(1.45rem / 2); 528 | margin-top: calc(1.45rem / 2); 529 | } 530 | blockquote *:last-child { 531 | margin-bottom: 0; 532 | } 533 | li *:last-child { 534 | margin-bottom: 0; 535 | } 536 | p *:last-child { 537 | margin-bottom: 0; 538 | } 539 | li > p { 540 | margin-bottom: calc(1.45rem / 2); 541 | } 542 | code { 543 | font-size: 0.85rem; 544 | line-height: 1.45rem; 545 | } 546 | kbd { 547 | font-size: 0.85rem; 548 | line-height: 1.45rem; 549 | } 550 | samp { 551 | font-size: 0.85rem; 552 | line-height: 1.45rem; 553 | } 554 | abbr { 555 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 556 | cursor: help; 557 | } 558 | acronym { 559 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 560 | cursor: help; 561 | } 562 | abbr[title] { 563 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 564 | cursor: help; 565 | text-decoration: none; 566 | } 567 | thead { 568 | text-align: left; 569 | } 570 | td, 571 | th { 572 | text-align: left; 573 | border-bottom: 1px solid hsla(0, 0%, 0%, 0.12); 574 | font-feature-settings: "tnum"; 575 | -moz-font-feature-settings: "tnum"; 576 | -ms-font-feature-settings: "tnum"; 577 | -webkit-font-feature-settings: "tnum"; 578 | padding-left: 0.96667rem; 579 | padding-right: 0.96667rem; 580 | padding-top: 0.725rem; 581 | padding-bottom: calc(0.725rem - 1px); 582 | } 583 | th:first-child, 584 | td:first-child { 585 | padding-left: 0; 586 | } 587 | th:last-child, 588 | td:last-child { 589 | padding-right: 0; 590 | } 591 | tt, 592 | code { 593 | background-color: hsla(0, 0%, 0%, 0.04); 594 | border-radius: 3px; 595 | font-family: "SFMono-Regular", Consolas, "Roboto Mono", "Droid Sans Mono", 596 | "Liberation Mono", Menlo, Courier, monospace; 597 | padding: 0; 598 | padding-top: 0.2em; 599 | padding-bottom: 0.2em; 600 | } 601 | pre code { 602 | background: none; 603 | line-height: 1.42; 604 | } 605 | code:before, 606 | code:after, 607 | tt:before, 608 | tt:after { 609 | letter-spacing: -0.2em; 610 | content: " "; 611 | } 612 | pre code:before, 613 | pre code:after, 614 | pre tt:before, 615 | pre tt:after { 616 | content: ""; 617 | } 618 | @media only screen and (max-width: 480px) { 619 | html { 620 | font-size: 100%; 621 | } 622 | } 623 | --------------------------------------------------------------------------------