맞춤형 정적 사이트 생성기로 스택 단순화
게시 됨: 2022-03-10Jamstack 운동의 도래와 함께 정적으로 제공되는 사이트가 다시 유행하고 있습니다. 정적 HTML을 제공하는 대부분의 개발자는 기본 HTML을 작성하지 않습니다. 견고한 개발자 경험을 위해 종종 SSG(정적 사이트 생성기)라는 도구를 사용합니다.
이러한 도구에는 대규모 정적 사이트를 즐겁게 만드는 많은 기능이 포함되어 있습니다. Gatsby의 데이터 소스와 같은 타사 API에 대한 간단한 후크를 제공하든 11ty의 방대한 템플릿 엔진 컬렉션과 같은 심층 구성을 제공하든 정적 사이트 생성에 있는 모든 사람을 위한 것이 있습니다.
이러한 도구는 다양한 사용 사례에 맞게 제작되었기 때문에 많은 기능을 포함해야 합니다. 이러한 기능은 그들을 강력하게 만듭니다. 또한 새로운 개발자에게는 매우 복잡하고 불투명합니다. 이 기사에서 우리는 SSG를 기본 구성 요소로 가져 와서 자체 구성 요소를 만들 것입니다.
정적 사이트 생성기란 무엇입니까?
기본적으로 정적 사이트 생성기는 파일 그룹에서 일련의 변환을 수행하여 HTML과 같은 정적 자산으로 변환하는 프로그램입니다. 어떤 종류의 파일을 받아들일 수 있는지, 어떻게 변환하는지, 어떤 종류의 파일이 나오는지에 따라 SSG가 달라집니다.
초기에 여전히 인기 있는 SSG인 Jekyll은 Ruby를 사용하여 Liquid 템플릿과 Markdown 콘텐츠 파일을 HTML로 처리합니다.
Gatsby는 React와 JSX를 사용하여 구성 요소와 콘텐츠를 HTML로 변환합니다. 그런 다음 한 단계 더 나아가 정적으로 제공될 수 있는 단일 페이지 애플리케이션을 만듭니다.
11ty는 Liquid, Handlebars, Nunjucks 또는 JavaScript 템플릿 리터럴과 같은 템플릿 엔진에서 HTML을 렌더링합니다.
이러한 각 플랫폼에는 우리의 삶을 더 쉽게 만들어주는 추가 기능이 있습니다. 테마, 빌드 파이프라인, 플러그인 아키텍처 등을 제공합니다. 기능이 추가될 때마다 복잡성, 마법, 종속성이 증가합니다. 확실히 중요한 기능이지만 모든 프로젝트에 필요한 것은 아닙니다.
이 세 가지 다른 SSG 사이에서 데이터 + 템플릿 = 최종 사이트라는 또 다른 공통 주제를 볼 수 있습니다. 이것이 제너레이터 정적 사이트의 핵심 기능인 것 같습니다. 이것이 SSG의 기반이 될 기능입니다.
기본적으로 정적 사이트 생성기는 파일 그룹에서 일련의 변환을 수행하여 HTML과 같은 정적 자산으로 변환하는 프로그램입니다.
"
새로운 정적 사이트 생성기의 기술 스택: 핸들바, Sanity.io 및 Netlify
SSG를 구축하려면 템플릿 엔진, 데이터 원본, SSG를 실행하고 사이트를 구축할 수 있는 호스트가 필요합니다. 많은 생성기가 Markdown을 데이터 소스로 사용하지만 한 단계 더 나아가 기본적으로 SSG를 CMS에 연결하면 어떻게 될까요?
- 데이터 출처: Sanity.io
- 데이터 가져오기 및 템플릿: 노드 및 핸들바
- 호스트 및 배포: Netlify.
전제 조건
- NodeJS 설치
- Sanity.io 계정
- 힘내 지식
- 커맨드 라인에 대한 기본 지식
- Netlify와 같은 서비스 배포에 대한 기본 지식.
참고 : 따라하기 위해 GitHub의 이 리포지토리에서 코드를 찾을 수 있습니다.
HTML에서 문서 구조 설정하기
문서 구조를 시작하기 위해 일반 HTML을 작성할 것입니다. 아직 문제를 복잡하게 만들 필요가 없습니다.
프로젝트 구조에서 소스 파일을 저장할 장소를 만들어야 합니다. 이 경우 src
디렉토리를 만들고 그 안에 index.html
을 넣습니다.
index.html
에서 원하는 내용을 간략하게 설명합니다. 이것은 페이지에 대해 비교적 간단합니다.
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Title of the page!</title> </head> <body> <h1>The personal homepage of Bryan Robinson</h1> <p>Some pagraph and rich text content next</p> <h2>Bryan is on the internet</h2> <ul> <li><a href="linkURL">List of links</a></li> </ul> </body> </html>
이것을 간단하게 유지합시다. 페이지용 h1
부터 시작하겠습니다. 우리는 전기 정보의 몇 단락을 따라갈 것이고 더 많은 것을 볼 수 있는 링크 목록으로 페이지를 고정할 것입니다.
HTML을 데이터를 허용하는 템플릿으로 변환
기본 구조를 만든 후에는 이를 일정량의 데이터와 결합하는 프로세스를 설정해야 합니다. 이를 위해 Handlebars 템플릿 엔진을 사용합니다.
핵심에서 Handlebars는 HTML과 유사한 문자열을 사용하고 문서에 정의된 규칙을 통해 데이터를 삽입한 다음 컴파일된 HTML 문자열을 출력합니다.
핸들바를 사용하려면 package.json을 초기화하고 패키지를 설치해야 합니다.
npm init -y
를 실행하여 일부 기본 콘텐츠가 포함된 package.json 파일의 구조를 만듭니다. 이것이 있으면 핸들바를 설치할 수 있습니다.
npm install handlebars
우리의 빌드 스크립트는 노드 스크립트가 될 것입니다. 이것은 우리가 로컬에서 빌드하는 데 사용할 스크립트이지만 배포 공급업체와 호스트가 라이브 사이트용 HTML을 빌드하는 데 사용할 스크립트이기도 합니다.
스크립트를 시작하려면 index.js
파일을 만들고 맨 위에 두 개의 패키지가 필요합니다. 첫 번째는 핸들바이고 두 번째는 현재 파일 시스템에 액세스하기 위한 Node의 기본 모듈입니다.
const fs = require('fs'); const Handlebars = require('handlebars');
fs
모듈을 사용하여 소스 파일에 액세스하고 배포 파일에 쓸 것입니다. 빌드를 시작하기 위해 파일이 호출될 때 실행할 main
함수와 데이터와 마크업을 결합하는 buildHTML
함수를 만듭니다.
function buildHTML(filename, data) { const source = fs.readFileSync(filename,'utf8').toString(); const template = Handlebars.compile(source); const output = template(data); return output } async function main(src, dist) { const html = buildHTML(src, { "variableData": "This is variable data"}); fs.writeFile(destination, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); } main('./src/index.html', './dist/index.html');
main()
함수는 HTML 템플릿에 대한 경로와 빌드된 파일이 살기를 원하는 경로라는 두 가지 인수를 허용합니다. 우리의 주요 기능에서 우리는 일정량의 데이터가 있는 템플릿 소스 경로에서 buildHTML
을 실행합니다.
빌드 함수는 소스 문서를 문자열로 변환하고 해당 문자열을 핸들바에 전달합니다. 핸들바는 해당 문자열을 사용하여 템플릿을 컴파일합니다. 그런 다음 데이터를 컴파일된 템플릿에 전달하고 핸들바는 모든 변수 또는 템플릿 논리를 데이터 출력으로 대체하는 새 HTML 문자열을 렌더링합니다.
해당 문자열을 main
함수로 반환하고 Node의 파일 시스템 모듈에서 제공하는 writeFile
메서드를 사용하여 디렉터리가 있는 경우 지정된 위치에 새 파일을 씁니다.
오류를 방지하려면 .gitkeep
파일이 있는 프로젝트에 dist
디렉토리를 추가하십시오. 빌드된 파일을 커밋하고 싶지는 않지만(빌드 프로세스가 이를 수행할 것입니다) 스크립트용으로 이 디렉토리가 있는지 확인하고 싶습니다.
이 페이지를 관리할 CMS를 만들기 전에 작동하는지 확인하겠습니다. 테스트를 위해 방금 전달한 데이터를 사용하도록 HTML 문서를 수정합니다. 핸들바 변수 구문을 사용하여 variableData
내용을 포함할 것입니다.
<h1>{{ variableData }}</h1>
이제 HTML에 변수가 있으므로 노드 스크립트를 실행할 준비가 되었습니다.
node index.js
스크립트가 완료되면 /dist/index.html
에 파일이 있어야 합니다. 브라우저에서 이것을 열면 마크업이 렌더링되는 것을 볼 수 있을 뿐만 아니라 "This is variable data" 문자열도 표시됩니다.
CMS에 연결
템플릿을 사용하여 데이터를 결합하는 방법이 있으므로 이제 데이터 소스가 필요합니다. 이 방법은 API가 있는 모든 데이터 소스에서 작동합니다. 이 데모에서는 Sanity.io를 사용합니다.
Sanity는 콘텐츠를 구조화된 데이터로 취급하는 API 우선 데이터 소스입니다. 편집자와 개발자 모두에게 데이터를 보다 편리하게 관리하고 추가할 수 있는 오픈 소스 콘텐츠 관리 시스템이 있습니다. CMS는 종종 "헤드리스" CMS라고 합니다. 데이터가 프레젠테이션과 밀접하게 연결되어 있는 기존 관리 시스템 대신 헤드리스 CMS는 모든 프런트엔드 또는 서비스(및 아마도 동시에 많은 서비스)에서 사용할 수 있는 데이터 계층을 생성합니다.
Sanity는 유료 서비스이지만 이러한 사이트에 필요한 모든 기능을 갖춘 무료 "표준" 플랜이 있습니다.
온전함 설정
새 Sanity 프로젝트를 시작하고 실행하는 가장 빠른 방법은 Sanity CLI를 사용하는 것입니다. 이를 전역적으로 설치하는 것으로 시작하겠습니다.
npm install -g @sanity/cli
CLI를 통해 관리, 배포 및 생성을 위한 도우미 그룹에 액세스할 수 있습니다. 일을 시작하기 위해 sanity init
를 실행할 것입니다. 이것은 우리 스튜디오(Sanity가 오픈 소스 CMS라고 부르는 것)를 부트스트랩하는 데 도움이 되는 설문지를 통해 우리를 실행할 것입니다.
Select a Project to Use: Create new project HTML CMS Use the default dataset configuration? Y // this creates a "Production" dataset Project output path: studio // or whatever directory you'd like this to live in Select project template Clean project with no predefined schemas
이 단계에서는 Sanity 계정에 새 프로젝트와 데이터세트를 만들고, Studio의 로컬 버전을 만들고, 데이터와 CMS를 함께 연결합니다. 기본적으로 studio
디렉토리는 프로젝트 루트에 생성됩니다. 대규모 프로젝트에서는 이것을 별도의 리포지토리로 설정할 수 있습니다. 이 프로젝트에서는 이것을 함께 묶는 것이 좋습니다.
Studio를 로컬로 실행하기 위해 디렉토리를 studio
디렉토리로 변경하고 sanity start
를 실행합니다. 그러면 localhost:3333
에서 Studio가 실행됩니다. 로그인하면 "빈 스키마"가 있음을 알리는 화면이 표시됩니다. 이제 데이터가 구조화되고 편집되는 방식인 스키마를 추가할 차례입니다.
온전성 스키마 생성
Sanity Studio 내에서 문서와 필드를 생성하는 방법은 schemas/schema.js
파일 내에서 스키마를 생성하는 것입니다.
우리 사이트의 경우 "About Details"라는 스키마 유형을 생성합니다. 우리의 스키마는 HTML에서 흐를 것입니다. 일반적으로 웹 페이지의 대부분을 단일 서식 있는 텍스트 필드로 만들 수 있지만 콘텐츠를 분리된 방식으로 구조화하는 것이 가장 좋습니다. 이것은 우리가 미래에 이 데이터를 사용하기를 원하는 방식에 더 큰 유연성을 제공합니다.
웹 페이지의 경우 다음을 포함하는 데이터 세트가 필요합니다.
- 제목
- 성명
- 전기(서식 있는 텍스트 편집 포함)
- 이름과 URL이 있는 웹사이트 목록입니다.
스키마에서 이것을 정의하기 위해 문서에 대한 개체를 만들고 해당 필드를 정의합니다. 필드 type
이 있는 주석이 달린 콘텐츠 목록:
- 제목 — 문자열
- 전체 이름 — 문자열
- 전기 — "블록" 배열
- 웹 사이트 목록 — 이름 및 URL 문자열 필드가 있는 개체 배열입니다.
types: schemaTypes.concat([ /* Your types here! */ { title: "About Details", name: "about", type: "document", fields: [ { name: 'title', type: 'string' }, { name: 'fullName', title: 'Full Name', type: 'string' }, { name: 'bio', title: 'Biography', name: 'content', type: 'array', of: [ { type: 'block' } ] }, { name: 'externalLinks', title: 'Social media and external links', type: 'array', of: [ { type: 'object', fields: [ { name: 'text', title: 'Link text', type: 'string' }, { name: 'href', title: 'Link url', type: 'string' } ] } ] } ] } ])
이것을 스키마 유형에 추가하고 저장하면 Studio가 다시 컴파일하여 첫 번째 문서를 제공합니다. 여기에서 새 문서를 만들고 정보를 입력하여 콘텐츠를 CMS에 추가합니다.
재사용 가능한 방식으로 콘텐츠 구조화
이 시점에서 "성명"과 "직위"가 있는 이유가 궁금할 것입니다. 콘텐츠가 다목적으로 활용되기를 원하기 때문입니다. 제목에 이름을 포함하는 대신 이름 필드를 포함함으로써 해당 데이터를 더 많이 사용할 수 있습니다. 그런 다음 이 CMS의 정보를 사용하여 이력서 페이지나 PDF에도 사용할 수 있습니다. 전기 필드는 다른 시스템이나 웹사이트에서 프로그래밍 방식으로 사용될 수 있습니다. 이를 통해 이 특정 사이트의 직접적인 사용 사례에 따라 결정되는 대신 이 콘텐츠의 대부분에 대한 단일 정보 소스를 확보할 수 있습니다.
데이터를 프로젝트로 가져오기
이제 API를 통해 데이터를 사용할 수 있게 만들었으므로 프로젝트에 가져와 보겠습니다.
Sanity JavaScript 클라이언트 설치 및 구성
먼저 Node.js의 데이터에 액세스해야 합니다. Sanity JavaScript 클라이언트를 사용하여 해당 연결을 위조할 수 있습니다.
npm install @sanity/client
그러면 JavaScript SDK를 가져와 설치합니다. 여기에서 이전에 설정한 프로젝트에서 데이터를 가져오도록 구성해야 합니다. 이를 위해 /utils/SanityClient.js
에 유틸리티 스크립트를 설정합니다. SDK에 프로젝트 ID와 데이터 세트 이름을 제공하고 기본 스크립트에서 사용할 준비가 되었습니다.
const sanityClient = require('@sanity/client'); const client = sanityClient({ projectId: '4fs6x5jg', dataset: 'production', useCdn: true }) module.exports = client;
GROQ로 데이터 가져오기
index.js
파일로 돌아가서 데이터를 가져오는 새 함수를 만듭니다. 이를 위해 Sanity의 기본 쿼리 언어인 오픈 소스 GROQ를 사용합니다.
변수에 쿼리를 작성한 다음 쿼리를 기반으로 데이터를 가져오도록 구성한 클라이언트를 사용합니다. 이 경우 about
이라는 속성을 사용하여 객체를 빌드합니다. 이 개체에서 특정 문서에 대한 데이터를 반환하려고 합니다. 이를 위해 문서를 생성할 때 자동으로 생성되는 문서 _id
를 기반으로 쿼리합니다.
문서의 _id
를 찾기 위해 Studio에서 문서로 이동하고 URL에서 문서를 복사하거나 "검사" 모드로 이동하여 문서의 모든 데이터를 봅니다. Inspect에 들어가려면 오른쪽 상단의 "kabob" 메뉴를 클릭하거나 단축키 Ctrl + Alt + I 를 사용하십시오. 이 보기는 _id
를 포함하여 이 문서의 모든 데이터를 나열합니다. Sanity는 문서 객체의 배열을 반환하므로 단순화를 위해 0th
항목을 반환합니다.
그런 다음 Sanity 클라이언트의 fetch
메서드에 쿼리를 전달하면 문서에 있는 모든 데이터의 JSON 개체가 반환됩니다. 이 데모에서 모든 데이터를 반환하는 것은 큰 문제가 아닙니다. 더 큰 구현을 위해 GROQ는 원하는 명시적 필드만 반환하는 선택적 "프로젝션"을 허용합니다.
const client = require('./utils/SanityClient') // at the top of the file // ... async function getSanityData() { const query = `{ "about": *[_id == 'YOUR-ID-HERE'][0] }` let data = await client.fetch(query); }
서식 있는 텍스트 필드를 HTML로 변환
데이터를 반환하기 전에 서식 있는 텍스트 필드에서 변환을 수행해야 합니다. 많은 CMS가 HTML을 직접 반환하는 서식 있는 텍스트 편집기를 사용하는 반면 Sanity는 Portable Text라는 오픈 소스 사양을 사용합니다. 이식 가능한 텍스트는 링크, 각주 및 기타 주석과 같은 속성 및 서식 있는 텍스트 스타일에 대한 모든 데이터와 함께 개체 배열( 서식 있는 텍스트를 단락 및 기타 미디어 블록의 목록으로 생각)을 반환합니다. 이를 통해 음성 도우미 및 기본 앱과 같이 HTML을 지원하지 않는 시스템에서 텍스트를 이동하고 사용할 수 있습니다.
우리의 사용 사례에서는 객체를 HTML로 변환해야 함을 의미합니다. 휴대용 텍스트를 다양한 용도로 변환하는 데 사용할 수 있는 NPM 모듈이 있습니다. 우리의 경우 block-content-to-html이라는 패키지를 사용할 것입니다.
npm install @sanity/block-content-to-html
이 패키지는 서식 있는 텍스트 편집기의 모든 기본 마크업을 렌더링합니다. 각 유형의 스타일은 사용 사례에 필요한 마크업을 준수하도록 재정의할 수 있습니다. 이 경우 패키지가 작업을 수행하도록 합니다.
const blocksToHtml = require('@sanity/block-content-to-html'); // Added to the top async function getSanityData() { const query = `{ "about": *[_type == 'about'][0] }` let data = await client.fetch(query); data.about.content = blocksToHtml({ blocks: data.about.content }) return await data }
핸들바에서 Sanity.io의 콘텐츠 사용하기
이제 데이터가 사용할 수 있는 모양이 되었으므로 이를 데이터 인수로 buildHTML
함수에 전달합니다.
async function main(src, dist) { const data = await getSanityData(); const html = buildHTML(src, data) fs.writeFile(dist, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); }
이제 새 데이터를 사용하도록 HTML을 변경할 수 있습니다. 대부분의 데이터를 가져오기 위해 템플릿에서 더 많은 변수 호출을 사용할 것입니다.
서식 있는 텍스트 content
변수를 렌더링하려면 변수에 추가 중괄호 레이어를 추가해야 합니다. 이것은 HTML을 문자열로 표시하는 대신 HTML을 렌더링하도록 핸들바에 지시합니다.
externalLinks
배열의 경우 Studio에 추가한 모든 링크를 표시하기 위해 Handlebars의 내장 루핑 기능을 사용해야 합니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ about.title }}</title> </head> <body> <h1>The personal homepage of {{ about.fullName }}</h1> {{{ about.content }}} <h2>Bryan is on the internet</h2> <ul> {{#each about.externalLinks }} <li><a href="{{ this.href }}">{{ this.text }}</a></li> {{/each}} </ul> </body> </html>
배포 설정
라이브로 합시다. 이 작업을 수행하려면 두 가지 구성 요소가 필요합니다. 먼저 파일을 빌드할 정적 호스트가 필요합니다. 다음으로 CMS에서 콘텐츠가 변경되면 사이트의 새 빌드를 트리거해야 합니다.
Netlify에 배포
호스팅의 경우 Netlify를 사용합니다. Netlify는 정적 사이트 호스트입니다. 정적 자산을 제공하지만 사이트가 원활하게 작동하도록 하는 추가 기능이 있습니다. 그들은 우리의 노드 스크립트를 실행할 수 있는 기본 제공 배포 인프라, 빌드를 트리거하는 웹훅, HTML 페이지가 빠르게 제공될 수 있도록 전 세계적으로 분산된 CDN을 가지고 있습니다.
Netlify는 GitHub의 리포지토리를 보고 대시보드에 추가할 수 있는 명령을 기반으로 빌드를 생성할 수 있습니다.
먼저 이 코드를 GitHub에 푸시해야 합니다. 그런 다음 Netlify의 대시보드에서 새 저장소를 Netlify의 새 사이트에 연결해야 합니다.
연결되면 Netlify에 프로젝트 빌드 방법을 알려야 합니다. 대시보드에서 설정 > 빌드 및 배포 > 빌드 설정으로 이동합니다. 이 영역에서 "빌드 명령"을 "노드 index.js"로 변경하고 "게시 디렉토리"를 "./dist"로 변경해야 합니다.
Netlify가 사이트를 구축하면 명령을 실행한 다음 목록에 있는 폴더에 콘텐츠가 있는지 확인하고 그 안에 콘텐츠를 게시합니다.
웹훅 설정
또한 누군가 콘텐츠를 업데이트할 때 새 버전을 게시하도록 Netlify에 알려야 합니다. 이를 위해 Netlify에 사이트를 재구축해야 함을 알리도록 Webhook을 설정합니다. Webhook은 다른 서비스(예: Sanity)에서 프로그래밍 방식으로 액세스하여 원본 서비스(이 경우 Netlify)에서 작업을 생성할 수 있는 URL입니다.
설정 > 빌드 및 배포 > 빌드 후크의 Netlify 대시보드에서 특정 "빌드 후크"를 설정할 수 있습니다. 후크를 추가하고 이름을 지정하고 저장합니다. 이렇게 하면 Netlify에서 빌드를 원격으로 트리거하는 데 사용할 수 있는 URL이 제공됩니다.
다음으로, 변경 사항을 게시할 때 이 URL에 요청하도록 Sanity에 알려야 합니다.
Sanity CLI를 사용하여 이를 수행할 수 있습니다. /studio
디렉토리 내에서 sanity hook create
를 실행하여 연결할 수 있습니다. 이 명령은 이름, 데이터 세트 및 URL을 요청합니다. 이름은 원하는 대로 지정할 수 있고 데이터 세트는 당사 제품의 production
이어야 하며 URL은 Netlify가 제공한 URL이어야 합니다.
이제 Studio에 콘텐츠를 게시할 때마다 웹사이트가 자동으로 업데이트됩니다. 프레임워크가 필요하지 않습니다.
- 코드는 이 GitHub 저장소에서 찾을 수 있습니다 →
다음 단계
이것은 자신만의 도구를 만들 때 수행할 수 있는 작업의 아주 작은 예입니다. 모든 기능을 갖춘 SSG가 대부분의 프로젝트에 필요한 것일 수 있지만 자신의 미니 SSG를 만드는 것은 선택한 발전기에서 무슨 일이 일어나고 있는지 더 많이 이해하는 데 도움이 될 수 있습니다.
- 이 사이트는 한 페이지만 게시하지만 빌드 스크립트에 약간의 추가 사항을 추가하면 더 많은 페이지를 게시할 수 있습니다. 블로그 게시물을 게시할 수도 있습니다.
- "개발자 경험"은 저장소에서 약간 부족합니다. Nodemon과 같은 패키지를 구현하여 모든 파일 저장에서 Node 스크립트를 실행하거나 BrowserSync와 같은 것으로 "핫 리로딩"을 추가할 수 있습니다.
- Sanity에 있는 데이터는 여러 사이트와 서비스를 구동할 수 있습니다. 이것을 사용하고 웹 페이지 대신 PDF를 게시하는 이력서 사이트를 만들 수 있습니다.
- CSS를 추가하여 실제 사이트처럼 보이게 할 수 있습니다.