dygresje.info / IT / JavaScript

Spis treści

GatsbyJS

CRA, NextJS, Gatsby - różnice

"React vs. Next vs. Gatsby – czym się różnią? ⌨️ hello roman #84" [YT 18:19] - O związkach pomiędzy CRA, NextJS i Gatsbym, a przede wszystkim o różnicach pomiędzy nimi. Z grubsza rzecz biorąc:

  • CRA: aplikacja wrzucana na serwer w formie plików statycznych i pobierana z serwera; pobrana działa po stronie klienta. Strona to pusty HTML, wszystko jest w app (<div id="app"></div>), React wstrzykuje tam DOM i wszystkie funkcje. W procesie renderowania aplikacji pobierane są dane z jakiegoś API (może być CMS). Słabe SEO. Natychmiastowe przetwarzanie danych.
  • Next.js: Server Side Rendering, aplikacja Node.js działająca na serwerze, która renderuje zapytanie klienta i wysyła gotową stronę. Duże wymagania wobec dewelopera i serwera (nie wszędzie jest usługa Noe.js). Dobre SEO. Do elemetów strony można dodać w plikach JS reaktywność: walidacja formularza, ankieta. Tzw rehydration czyli wstrzyknięcie Reacta do HTML. Wydajność i łatwość indeksowania, ranking. Dane pobierane są na serwerze w czasie renderowania. Next renderuje zmiany z API natychmiast na serwerze.
  • Gatsby: Build time server rendering. Podczas builda wszystkie pliki są przygotowane do wysłania na serwer, wszystkie routy wyrenderowane, wtedy też pobierane są dane przez graphQL z API. Po wysłaniu na serwer dostęp do danych normalnie nie jest możliwy. Klient dostaje wyrenderowana strone statyczną z serwera oraz JS, który zapewnia mu reaktywność reactową, tak samo rehydration. To React z dodatkami, generator PWA. Dane moga byc pobierane w momencie wykonywania pliku JS axios w komponencie do API. Wszystko co jest mozliwe w Reaccie jest możliwe w Gatsbym. Gatsby circleCI buduje na nowo za każdą zmiana w API, trzeba chwilkę poczekać.

Porównanie SSR i stron statycznych: Next.js: Server-side Rendering vs. Static Generation

Instalacja

Wymagania:

  • Node.js (a więc i npm)
  • git

Instalacja globalna Gatsby CLI. 70 MB node_modules.


 npm install -g gatsby-cli
  

Utworzenie nowej strony i przejście tam (gatsby-site to przykładowa nazwa, może być z dużej litery). 250 MB


 gatsby new gatsby-site
 cd gatsby-site
  

Ewentualnie z gotowego startera wg schematu: gatsby new [SITE_DIRECTORY_NAME] [URL_OF_STARTER_GITHUB_REPO].


 gatsby new hello-world https://github.com/gatsbyjs/gatsby-starter-hello-world
  

Poniższe polecenia Gatsby CLI uruchamia się z katalogu gatsby-site

  • Serwer deweloperski (http://localhost:8000)
    gatsby develop
  • Produkcja
    gatsby build
  • Produkcja lokalnie (http://localhost:9000)
    gatsby serve
  • Pomoc
    gatsby --help

Instalacja najnowszej wersji Gatsby'ego


     $ npm i gatsby@latest
      

Instalacja pluginów


 $ npm i gatsby-source-filesystem gatsby-transformer-remark gatsby-plugin-catch-links
  

Dodanie do sekcji plugins w gatsby-config.js wg wzoru podanego na stronie pluginu.

Gatsby from Scratch


 $ npm init -y
 $ git init
  

.gitignore:


 # Project dependencies
 .cache
 node_modules
 # Build directory
 public
 # Other
 .DS_Store
 yarn-error.log
  

Instalacja


 npm i gatsby react react-dom
  

/src/pages/index.js


 import React from 'react'
 export default () => {
   return (
 <h1>Hello World!</h1>)
 }
  

package.json


  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "start": "npm run develop",
    "serve": "gatsby serve",
    "clean": "gatsby clean",
  },
  

MDX

Generowanie stron przy użyciu plików .mdx. Uzywany bardzo często do mechanizmu blogowego. Tu zakładamy, że wszystkie wpisy w są w plikach .mdx w jednym katalogu.

Można to zrobić na dwa sposoby

  • gatsby-node.js
  • File System Route API

gatsby-node.js

Wpis w gatsby-config.js, określający skąd mają być pobierane wpisy.


{ resolve: `gatsby-source-filesystem`,
      options: {
  name: `posts`,
  path: `${__dirname}/src/posts/`,
      },
    },
    

To jest cała zawartość pliku gatsby-node.js, który automatycznie generuje strony wpisów na podanej ścieżce ze wskazanego szablonu na podstawie plików wpisów.


const path = require(`path`);

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions
  const postTemplate = path.resolve("./src/templates/postTemplate.js");
  return graphql(`	{
    posts: allMdx(
      filter: { fileAbsolutePath: { glob: "**/src/posts/*.mdx" } }
      ) {
    nodes {
        frontmatter {
  title
  date
 }
 slug
        }
      }
    }
  `).then((result) => {
    if (result.errors) {
      throw result.errors;
    }
    const posts = result.data.posts.nodes;
    posts.forEach(post => {
      createPage({
        path: "/post/" + post.slug,
        component: postTemplate,
        ...post,
        context: {
...post.context,
slug: post.slug,
        },
      });
    });
  });
};

Każda zmiana w plikach gatsby-config.js i gatsby-node.js oznacza, że musimy zrestartować Gatsby'ego. To niestety trwa.

Szablon wpisu: postTemplate.js


import { Link, graphql } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import React from "react"
import Layout from "../components/layout"

const postTemplate = ({ data }) => {
    const { frontmatter, body } = data.mdx;
    return (
        <Layout>
 // content here
        </Layout>
    );
};
export default postTemplate

export const query = graphql`
query PostBySlug($slug: String!) {
    mdx(slug: { eq: $slug } ) {
      body
       frontmatter {
        title
        date(formatString: "YYYY-MM-DD")
   }
      }
  }
`;
      

To jest strona listy wpisów - index.js


import * as React from "react"
import { graphql, Link } from "gatsby"
import Layout from "../components/layout"

const PostPage = ({ data }) => {
    return (
        <Layout>
  <p>Posts:</p>
  <ul>
      {data.allMdx.nodes.map(({ frontmatter, slug }) => (
<li key={frontmatter.post}><Link to={`/post/${slug}`}>{frontmatter.post}</Link></li>
      ))}
  </ul>
  </Layout>
    )
}

export default PostPage

export const query = graphql`
query AllPosts {
  allMdx {
        nodes {
  id
  frontmatter {
    title
    date(formatString: "YYYY-MM-DD")
    published
        }
         slug
  }
pageInfo {
  currentPage
}
    }
  }
`;

Przykładowy wpis/post.


---
title: "This is the title"
date: 2021-01-21
published: true
---

## secondary header

content here
  

File System Route API

Ten sam efekt można uzyskać używając wprowadzonego w listopadzie 2020 File System Route API. Wtedy cała ta komplikacja z gatsby-node.js nie jest potrzebna.

pages/{mdx.slug}.js


import { graphql, Link } from 'gatsby'
import { MDXRenderer } from 'gatsby-plugin-mdx'
import React from 'react'
import Layout from "../components/layout"

export default function PostPage({ data }) {
    const {
        body,
        frontmatter: { location },
        frontmatter: { date },
    } = data.mdx
    return (
        <Layout>
            <h2>{title}</h2>
            <p>This is File System Route API page</p>
            <p>updated: {date}</p>
            <MDXRenderer>{body}</MDXRenderer>
                   </Layout>
    )
}
export const query = graphql`
    query PostBySlug($slug: String) {
            mdx(slug: {eq: $slug }) {
            id
        slug
        body
        frontmatter {
            date
          location
        }
      }
    }
  `
            

CSS

Active classnames in menu on a one-page website using GatsbyJS

Komponenty layoutu

Global CSS

W gatsby-browser.js:


 import "./src/styles/global.css"
  

CSS Modules

CSS-in-JS

Styled Components

JSX


      <Icon primary border='solid 10px' progress='70%' day={2} />
      

Komponent


    import styled, { keyframes } from 'styled-components'

    const fadeIn = keyframes`
    0% {opacity: 0;}
    100% {opacity: 1;}
  `
    const StyledIcon = styled.div`
    background-color: ${({ primary }) => primary ? 'green' : 'yellow'};
    width: 30px;
    height: 30px;
    border-radius: 15px;
    margin: 5px;
    border: ${({ border }) => border || 0}
    border-color: ${({progress}) => {
      let numeric =  progress.slice(0,-1)
      let integer = parseInt(numeric)      
      if (integer >= 80) return 'red';
      else if (integer >= 60) return 'orange';
      else if (integer >= 40) return 'yellow';
      else return 'green';
   }};
   animation: 5s ${fadeIn} ease-in;
`

const TodayIcon = styled(Icon)`
    background-color: purple;
`
const Icon = ({primary, border, day}) => {

  let today = new Date()
  let dayOfTheWeek = today.getDay()  
  const isToday = day === dayOfTheWeek

    return (
      {isToday && <STodayIcon border={border} primary={primary} progress={progress} />}
      {!isToday && <StyledIcon border={border} primary={primary} progress={progress} /}
    )
}

Biblioteki i frameworki

Font Awesome

Najprostszy sposób na użycie glifów Font Awesome to ściągnięcie i rozpakowanie paczki np do /styles, potrzebujemy tylko katalogów css i fonts. Potem pobranie np. do /src/components/header.js


 import "../styles/css/font-awesome.css"
  

Teraz można już używać Font Awesome. Trzeba tylko zmienić domyślne class, na className - bo to jest JavaScript. I działa, bez żadnych dodatków czy koniguracji.

Pseudoelementy uzyskuje się wpisując w arkuszu stylów:


 ::before {
  font-family: "FontAwesome";
  display: block;
  content: "18e";
  position: absolute;
  top: 0;
  left: -8rem;
  color: rgba(51, 51, 51, 0.5);
  

Inna możliwość: React Icons / Font Awesome

Deploy na Githubie

Instalacja gh-pages

Ustawienie nazwy repozytorium w gatsby-config.js


 {
  module.exports =
    pathPrefix: "/reponame",
  }
  

Utworzenie skryptu w package.json


 {
  "scripts":
      "deploy": "gatsby build --prefix-paths && gh-pages -d public"
    }
  

Utworzenie origin remote na Githubie


 git remote add origin git@github.com:username/reponame.git
  

Najpierw tworzymy builda. Testujemy go poleceniem gatsby serve (port 9000). Potem wysłanie


 npm run deploy
  

I właśnie w takim cyklu odbywa się tworzenie stron w Gastbym.

  • budowanie witryny przy użyciu
    gatsby develop
  • tworzenie builda, czyli wygenerowanej, zoptymalizowanej strony statycznej:
    gatsby build
  • testowanie lokalne tej strony:
    gatsby serve
  • npm run deploy
    i testy już online

Integracja z NetlifyCMS

Netlify: "A Step-by-Step Guide: Gatsby on Netlify"

Google Analytics

gatsby-plugin-gtag

Headless Drupal

Instalacja Drupala z bazą danych.

Włączenie wszystkich Usług Web


 HAL
 Serializacja encji przy użyciu formatu Hypertext Application Language.
 
 HTTP Basic Authentication
 Dostarcza uwierzytelnienie w trybie HTTP Basic authentication
 
 JSON:API
 Exposes entities as a JSON:API-specification-compliant web API.
 
 RESTful Web Services
 Udostępnia encje i inne zasoby w postaci RESTful web API
 
 Serialization
 Provides a service for (de)serializing data to/from formats such as JSON and XML.
  

Utworzenie nwego rodzaju zawartości, np. Blog.

Utworzenie nwego widoku np. "Blog API"


 Ścieżka: /api/blog
 Uwierzytelnianie: Bez autoryzacji
 Dostęp: Rola | Użytkownik anonimowy
  

Sprawdzic w trybie anonimowym czy jest dostepny pod adresem /jsonapi

Trzeba opublikować przynajmniej jeden wpis.

Instalacja pluginu gatsby-source-drupal


 {
  resolve: `gatsby-source-drupal`,
  options: {
  baseUrl: `http://api.domena/`,
  apiBase: `jsonapi`, // optional, defaults to `jsonapi` ; old 'api' - z każdą zmianą trzeba restartować Gatsby'ego
  },
  

I dopiero teraz można znowu uruchomić Gatsbiego, tak żeby pociągnął dane z Drupala.

graphQL


 query MyQuery {
  allNodeBlog {
  nodes {
  id
  title
  body {
  value
  }
  }
  }
  }
  

Brian Perry "Understanding the Limitations of Gatsby-Source Drupal", Andrew Larcombe "Gatsby, Drupal, inline images and friends"

Contenta CMS an API-First Drupal distribution

Headless Wordpress

Pluginy

  • Headless Mode (jedno rozszerzenie działające w prosty sposób, które załatwia większość spraw)
  • WP Editor.md (albo klasyczny edytor)

API


 adres/wp-json/
  

login: domena/wp-login.php

Strapi

Cyril Lopez "How to change the WYSIWYG in Strapi" - Image upload on custom CKEditor #4369

gatsby-source-strapi

GraphGL i query i import. Potem {data} w propsie i mapowanie po wynikach zapytania. W gatsby-config podać typy importowanych danych.

Netlify CI

Drupal: Build Hooks - Drupal 9 compatibility (ta łata niestety stawia nadzwyczajne opory, więc trzeba pójść za radą Hunk #1 FAILED at 1. What's that mean? i (zakładając, że jesteśmy w rozpakowanym /build_hooks a łata jest w tym samym katalogu co katalog modułu) zadać jej:


 patch --ignore-whitespace --fuzz 3 -p1 < ../3153199-5.patch
  

Potem zzipowanie i instalacja z pliku.

"Deploy content changes for your Gatsby Drupal site on Netlify - Daily Dose of Gatsby Episode 9" [YT 12:45]

PrismJS


 npm install --save gatsby-transformer-remark gatsby-remark-prismjs prismjs
  

Odnośniki

Strony

Kursy, tutoriale

Artykuły

YT

Narzędzia

GraphQL

GraphQL - YT

GraphQL - API

Headless CMS

Strapi

Strapi YT

ContentfulCMS

Drupal

WordPress

CI/CD

AWS

Netlify

Contact Form

Axios

MDX

Storybook

Inne

Dark mode

GSAP i animacja

Animacja przykłady