Hello! JAMstack!

ODK Media

김태희

목차

  • JAMstack이란 무엇인가
  • 적용경험
  • Headless CMS

JAMstack?

대충_잼이_쌓여있는_사진.png

JAMstack?

대충_잼이_쌓여있는_사진.png

JAMstack

  • JavaScript

JAMstack

  • JavaScript
  • APIs

JAMstack

  • JavaScript
  • APIs
  • Markup
  • JavaScript
  • APIs
  • Markup
Fast and secure sites and apps delivered by pre-rendering files and serving them directly from a CDN, removing the requirement to manage or run web servers.

쉽게 말해서

  • 별도의 웹서버를 통해 컨텐츠를 동적으로 렌더링하는 게 아니라

쉽게 말해서

  • 별도의 웹서버를 통해 컨텐츠를 동적으로 렌더링하는 게 아니라
  • 데이터에 따라 대응하는 컨텐츠 페이지를 정적으로 렌더링

쉽게 말해서

  • 별도의 웹서버를 통해 컨텐츠를 동적으로 렌더링하는 게 아니라
  • 데이터에 따라 대응하는 컨텐츠 페이지를 정적으로 렌더링
  • 렌더링 된 결과물(HTML, JS, CSS)을 Static hosting을 통해 서비스
  • server side의 CMS를 통해 제공되는 사이트
    WordPress, Drupal, Joomla 등

JAMstack이 아닌 것

  • server side의 CMS를 통해 제공되는 사이트
    WordPress, Drupal, Joomla 등
  • 특정 backend 언어 기반의 웹 서버 앱이 있고,
    해당 앱을 통해 사이트를 받는 경우

JAMstack이 아닌 것

  • server side의 CMS를 통해 제공되는 사이트
    WordPress, Drupal, Joomla 등
  • 특정 backend 언어 기반의 웹 서버 앱이 있고,
    해당 앱을 통해 사이트를 받는 경우
  • SPA앱이지만 rendering 되는 시점에 서버를
    거쳐서 추가적인 렌더링을 하는 경우
    예를 들면 odc-frontend(aws lambda edge 사용)

JAMstack이 아닌 것

JAMstack의 장점

  • pre-render된 HTML을 static hosting을 통해
    서빙 받기 때문에 배포가 매우 간편하고 성능에도 큰 잇점이 있음

JAMstack의 장점

  • pre-render된 HTML을 static hosting을 통해
    서빙 받기 때문에 배포가 매우 간편하고 성능에도 큰 잇점이 있음
  • 이미 pre-render된 컨텐츠이기 때문에 SSR의 장점을 누릴 수 있음
    • 컨텐츠 페이지별 meta tag 생성
    • 빠른 초기 렌더링

JAMstack의 장점

  • pre-render된 HTML을 static hosting을 통해
    서빙 받기 때문에 배포가 매우 간편하고 성능에도 큰 잇점이 있음
  • 이미 pre-render된 컨텐츠이기 때문에 SSR의 장점을 누릴 수 있음
    • 컨텐츠 페이지별 meta tag 생성
    • 빠른 초기 렌더링
  • Scaling의 용이성
    • 트래픽이 몰린다고 서버를 증설할 필요 없음
      호스팅 서비스가 알아서 해줄꺼야

Tools

....and many more

실제로 좀 써본 것

실제로 좀 써본 것

실제로 좀 써본 것

gatsby의 아키텍쳐

  • 데이터를 markdown, yaml, json 등의 정적인 파일로 표현
  • 외부 API를 통해 데이터를 표현
  • HTML/CSS/React를 이용해
    컨텐츠를 pre-rendering
  • graphql을 통해 데이터 소스에서
    데이터를 불러옴
  • 데이터를 markdown, yaml, json 등의 정적인 파일로 표현
  • 외부 API를 통해 데이터를 표현
  • pre-rendering의 결과를
    Static hosting service에 배포
  • 데이터를 markdown, yaml, json 등의 정적인 파일로 표현
  • 외부 API를 통해 데이터를 표현
  • HTML/CSS/React를 이용해
    컨텐츠를 pre-rendering
  • graphql을 통해 데이터 소스에서
    데이터를 불러옴

저는 이걸로
밴드 홈페이지를 만들었어요.

멜론에서 이디어츠를 검색하세요

gatsby에 대한 간략한 소개

Routing 방식

/contact

/discography

/

/live

/movies

/photos

src/pages 아래에 있는 컴포넌트의
확장자를 제외한 파일명이 url이 됩니다.

md 파일 + yaml을 이용한 컨텐츠 표현

Text

...    
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: 'src',
        path: `${__dirname}/src/`,
      },
    },
    'gatsby-transformer-remark',
...

md 파일을 데이터로 사용하는 법

  • gatsby-source-filesystem: path 아래에 있는 파일들을 읽어와 graphql로 조회할 수 있도록 만들어줌
  • gatsby-transformer-remark: md 파일을 파싱
---
type: 'live'
title: '2020 PUNK Marathon'
posterUrl: ''
posterUrls:
  [
    {
      src: '/images/posters/2020-02/82191077_479553396078214_6170799798740844544_o.jpg',
      alt: '2020 펑크마라톤 공식 포스터',
      width: 680,
      height: 960,
    },
    {
      src: '/images/posters/2020-02/goinmul.jpg',
      alt: '2020 펑크마라톤 포스터',
      width: 1926,
      height: 1926,
    },
  ]
place: '고인물'
date: '2020.02.22'
teams: ['링고포레스트', '노앤써', '오버헤드', '코인클래식']
priceInfos:
  [
    '예매 5일권: 50,000원 (full pass) (50% 할인) + 1일권 게스트 티켓 2매 증정',
    '예매 4일권: 45,000원 (4-day pass)(44% 할인) + 1일권 게스트 티켓 1매 증정',
    '예매 3일권: 35,000원 (3-day pass)(42% 할인)',
    '예매 2일권: 25,000원 (2-day pass)(37% 할인)',
    '예매 1일권: 15,000원 (1-day pass)(25% 할인)',
    '당일 현매: 20,000원',
  ]
eventLink: 'https://www.facebook.com/hippytokki/posts/479149026118651'
ticketLink: 'https://docs.google.com/forms/d/e/1FAIpQLSeh6-iz-uWGq2LB8uvcSG6Wtm4QAAuBTmWy4hSU-WKa19Bd9w/viewform?vc=0&c=0&w=1&fbclid=IwAR0ajB3k7KoW-QwAzET_UBUEPWIBONWar7ZN1DdCOFecboytpY3fY2bMqfw'
---

test

src/pages/live/2020-punk-marathon.md

md 파일 path를 url으로 사용합니다.
/live/2020-punk-marathon/

graphql로 markdown 조회하기

{
  allMarkdownRemark(
  	filter: { frontmatter: { type: { eq: "live" } } }
    	sort: { fields: [frontmatter___date], order: DESC }
  ) {
    edges {
      node {
        id
        frontmatter {
          date
          title
        }
        fields {
          slug
        }
      }
    }
  }
}

graphql로 markdown 조회하기

{
  "data": {
    "allMarkdownRemark": {
      "edges": [
        {
          "node": {
            "id": "9cf14b80-b26a-5a37-a280-5e2881fb8b00",
            "frontmatter": {
              "date": "2020.2.22",
              "title": "2020 PUNK Marathon"
            },
            "fields": {
              "slug": "/live/2020-punk-marathon/"
            }
          }
        },
        {
          "node": {
            "id": "b7d7fd44-9f6b-5941-adf2-d1739e2df65a",
            "frontmatter": {
              "date": "2020.01.09",
              "title": "오롯한 라이브와 함께"
            },
            "fields": {
              "slug": "/live/o-rot-han-live/"
            }
          }
        },
        {
          "node": {
            "id": "35a154ac-53b2-5cf5-b74a-c505da1e06c0",
            "frontmatter": {
              "date": "2019.12.12",
              "title": "LIVE in DEC 2019"
            },
            "fields": {
              "slug": "/live/live-in-dec-2019/"
            }
          }
        },
        {
          "node": {
            "id": "aaadce5a-9584-51f2-95ef-389166a62bc3",
            "frontmatter": {
              "date": "2019.11.28",
              "title": "LIVE in NOV 2019"
            },
            "fields": {
              "slug": "/live/live-in-nov-2019/"
            }
          }
        },
        {
          "node": {
            "id": "3117ad79-83d6-53dd-bf05-01d4e0d65ced",
            "frontmatter": {
              "date": "2019.1.29",
              "title": "이디어츠 1st EP 발매기념 공연"
            },
            "fields": {
              "slug": "/live/idiots-1st-ep/"
            }
          }
        }
      ]
    }
  }
}

live md 파일로 공연 페이지 빌드하기

// gatsby-node.js
exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }

  // graphql로 type이 live인 md 파일만 가져옴
  // slug는 src를 기준으로 폴더명과 파일명  
  const result = await graphql(`
  {
    allMarkdownRemark(filter: {frontmatter: {type: {eq: "live"}}}) {
      edges {
        node {
          fields {
            slug
          }
        }
      }
    }
  }`)
  
  // 위에서 가져온 md 파일로 slug에 해당하는 파잉 생성  
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve('./src/components/LiveDetail.tsx'),
      context: {
        slug: node.fields.slug,
      },
    })
    console.log(`${node.fields.slug} created,`)
  })
 }

빌드 결과

gatsby-node.js 에서 createPage한 페이지들이
pre-rendering 되고, slug 경로에 맞게
pre-rendering 된 결과물이 index.html로 생성

/live/2020-03-20-for-the-new-kids/

/live/2020-03-bbang/

/live/idiots-1st-ep/

createPage로 정의하지 않은 모든 url

배포하기

생성된 static resources만 배포하면 끝!

...and many more

static hosting만 필요하기 때문에,
별도로 관리해야하는 웹서버가 필요🙅‍♂️

  • github repository가 변경되면 알아서
    npm run build 해주고 빌드된 파일들 hosting 해줌
  • repo 연동 후 content md 파일을 추가하거나 수정하고 commit + push하면 자동으로 빌드해서 배포까지 끝남
  • 클릭 몇번으로 배포가 끝나는 신세계를 경험할 수 있습니다.
  • pr이나 branch 별로 preview 서버를 띄워주는 기능
    • front-end가 완전히 독립적이기 때문에 쉽게 가능

그외 자세한 내용은

outsider님의 블로그 https://blog.outsider.ne.kr/1426 를 참고하시면 됩니다.

빌드된 결과물 한번 볼까요?

SPA에서 단골로 등장하는 meta 태그 생성 문제를
pre-render로 해결가능합니다.

pre-render된 html이기 때문에 렌더링 속도가 정말 빠릅니다.

SSR 신경 안 써도 됩니다!

그외에도 많은 장점이 있습니다.

그런데 말입니다...

공연섭외 잘 안 될 땐
md 파일 만들고
커밋하는 거 할만했는데
공연이 점점 자주 잡히니까
상당히 귀찮아지더라구요..

그래서 CMS를 만들까 했습니다.
제가 어드민은 기깔나게 만들거든요.

그러다 알게 된 Headless CMS

Headless CMS

  • 컨텐츠를 관리하는 어드민만 있고, 해당 컨텐츠를 노출하는 Front-end가 없는 것
  • 쉽게 말해서 컨텐츠 관리기능만 있는 툴

사실 headless cms를 안 쓰고
wordpress 등에서 cms 기능만 써도
되긴 합니다.

Headless CMS

...and many more

요 친구를 써봤습니다.

트위터 친구분이 추천해주심

  • 잘 만들어진 어드민 화면
  • 데이터 모델링을 코드 수정 없이 가능함
  • 모델 정의만 하면 해당 모델의 REST API 생성됨
  • graphql 연동 쉬움
    • 클릭 한번으로 끝남
  • gatsby 연동 쉬움
    • 플러그인 설치로 끝남
  • 다양한 DB 지원

strapi로 공연 정보 받기

strapi로 공연 정보 받기

graphql 형태

gatsby와 연동하기

// gatsby-config.js

...
    {
      resolve: 'gatsby-source-strapi',
      options: {
        apiURL: 'https://admin.idiots.band',
        contentTypes: [
          // List of the Content Types you want to be able to request from Gatsby.
          'albums',
          'lives',
          'home-content',
        ],
        queryLimit: 1000,
      },
    },
    ...

자동으로 gatsby의 graphql에 통합됨

webhook 연동

  • 컨텐츠에 변경이 있는 경우 호출
  • 해당 url이 호출되면, netlify build + deploy

아직 보완해봐야 하는 것

개별 빌드 및 배포

  • 지금은 컨텐츠가 변경될 때마다 전체를 빌드하고 생성하고
    배포해야 하는 구조
  • 변경된 컨텐츠만 pre-rendering을 다시 하고, 해당 결과만
    배포할 수 있도록 하는 것을 테스트 해볼 예정

Q & A

감사합니다!