내가 항상 원했던 SSG 구축: 11ty, Vite 및 JAM 샌드위치

게시 됨: 2022-03-10
요약 요약 ↬ 2020년 1월로 돌아가서 Ben Holmes는 거의 모든 웹 개발자가 매년 하는 일을 시작했습니다. 바로 개인 사이트를 재구축하는 것입니다. 이 기사에서 그는 절대적인 그라운드 제로에서 자신의 빌드 파이프라인을 구축하고 Slinkity를 만든 방법에 대한 이야기를 공유합니다.

나는 당신에 대해 모르지만 나는 요즘 우리가 가지고 있는 모든 웹 개발 도구에 압도당했습니다 . Markdown, 일반 HTML, React, Vue, Svelte, Pug 템플릿, 핸들바, Vibranium을 좋아하든 상관없이 일부 CMS 데이터와 혼합하여 멋진 정적 사이트 칵테일을 얻을 수 있습니다.

프로젝트의 요구 사항에 따라 모든 UI 개발 도구가 훌륭하기 때문에 어떤 UI 개발 도구를 사용해야 하는지 말하지 않겠습니다. 이 게시물은 모든 경우에 완벽한 정적 사이트 생성기를 찾는 것에 관한 것입니다. 마크다운과 같은 JS가 없는 템플릿을 사용하여 시작하고 필요에 따라 구성 요소 중심 상호 작용의 "섬"을 가져올 수 있는 것입니다.

1년치의 배움을 여기 하나의 포스트에 담았습니다. 우리는 코드(덕트 테이핑 11ty와 Vite를 함께 사용)에 대해 이야기할 뿐만 아니라 이 접근 방식이 Jamstackian 문제에 보편적인 이유 도 탐구할 것입니다. 우리는 다음을 다룰 것입니다:

  • 정적 사이트 생성에 대한 두 가지 접근 방식과 그 간극을 메워야 하는 이유
  • Pug 및 Nunjucks와 같은 템플릿 언어가 여전히 유용함을 입증하는 곳;
  • React 또는 Svelte와 같은 구성 요소 프레임워크가 작동해야 할 때
  • 새롭게 핫 리로딩되는 Vite의 세계가 거의 제로에 가까운 구성으로 HTML에 JS 상호작용성을 가져오는 데 어떻게 도움이 되는지,
  • 이것이 11ty의 데이터 캐스케이드를 보완하여 CMS 데이터를 원하는 모든 구성 요소 프레임워크 또는 HTML 템플릿으로 가져오는 방법입니다.

그래서 더 이상 고민하지 않고 끔찍한 빌드 스크립트, 번들러 혁신 및 스파게티 코드 덕트 테이프에 대한 내 이야기가 있습니다. (결국) 제가 항상 원했던 SSG를 얻었습니다. 11ty, Vite and Jam 샌드위치라고 불리는 Slinkity!

정적 사이트 생성의 큰 격차

자세히 알아보기 전에 정적 사이트 생성에서 두 개의 "캠프"라고 부르는 것에 대해 논의하고 싶습니다.

첫 번째 캠프에는 "단순한" 정적 사이트 생성기가 있습니다. 이러한 도구는 JavaScript 번들, 단일 페이지 앱 및 기타 우리가 기대하는 유행어를 가져오지 않습니다. 그들은 Jamstack의 기본 사항을 잘 알고 있습니다. 원하는 CMS의 JSON blob에서 데이터를 가져오고 해당 데이터를 일반 HTML 템플릿 + CSS로 밀어넣습니다. Jekyll, Hugo 및 11ty와 같은 도구가 이 진영을 지배하므로 마크다운 및 유동 파일의 디렉토리를 완전한 기능의 웹사이트로 전환할 수 있습니다. 주요 혜택:

  • 얕은 학습 곡선
    HTML을 안다면, 당신은 갈 수 있습니다!
  • 빠른 빌드 시간
    우리는 복잡한 것을 처리하지 않으므로 각 경로가 순식간에 구축됩니다.
  • 인터랙티브할 수 있는 즉각적인 시간
    클라이언트에서 구문 분석할 JavaScript가 없거나 거의 없습니다.

이제 두 번째 캠프에는 "동적" 정적 사이트 생성기가 있습니다. 여기에는 React, Vue 및 Svelte와 같은 구성 요소 프레임워크가 도입되어 Jamstack에 상호 작용성을 제공합니다. 이는 빌드 시 CMS 데이터를 사이트의 경로와 결합한다는 동일한 핵심 약속을 이행합니다. 주요 혜택:

  • 상호 작용을 위해 구축됨
    애니메이션 이미지 캐러셀이 필요하십니까? 다단계 양식? HTML, CSS 및 JS의 구성 요소화된 너겟을 추가하기만 하면 됩니다.
  • 상태 관리
    Svelte 저장소의 React Context와 같은 것은 경로 간에 원활한 데이터 공유를 허용합니다. 예를 들어 전자 상거래 사이트의 장바구니.

두 접근 방식에는 뚜렷한 장단점이 있습니다. 그러나 Jekyll과 같은 첫 번째 캠프에서 SSG를 선택하고 프로젝트를 시작한 지 6개월 만에 구성 요소와 상호 작용이 필요하다는 사실을 깨닫는다면 어떻게 될까요? 아니면 React의 학습 곡선이나 정적 블로그 게시물에서 불필요한 JavaScript KB와 씨름하기 위해 강력한 구성 요소를 위해 NextJS와 같은 것을 선택합니까?

제 생각에는 어느 한 진영에 맞는 프로젝트는 거의 없습니다. 그들은 스펙트럼에 존재하며 프로젝트의 요구 사항이 발전함에 따라 지속적으로 새로운 기능 세트를 선호합니다. 그렇다면 첫 번째 캠프의 간단한 도구로 시작 하여 필요할 때 두 번째 캠프에서 점차 기능을 추가할 수 있는 솔루션을 찾는 방법은 무엇입니까?

자, 제 학습 여정을 잠시 살펴보겠습니다.

참고: 정적 사이트를 구축하기 위해 이미 11ty를 사용하여 정적 템플릿을 판매하고 있다면 주저 없이 유용한 코드 연습으로 뛰어들 수 있습니다.

점프 후 더! 아래에서 계속 읽기 ↓

구성 요소에서 템플릿 및 웹 API로 이동

2020년 1월에 저는 거의 모든 웹 개발자가 매년 하는 일을 하기 시작했습니다. 바로 개인 사이트를 재구축하는 것입니다. 하지만 이번에는 달랐을 것이다 . 프레임워크나 빌드 파이프라인이 허용되지 않는 등 뒤로 묶인 손으로 사이트를 구축하는 데 도전했습니다!

이것은 React 신봉자로서 간단한 작업이 아닙니다. 하지만 고개를 높이 들고 절대 그라운드 제로에서 나만의 빌드 파이프라인을 구축하기 시작했습니다. 내 개인 사이트의 v1에서 공유 할 수 있는 잘못 작성된 코드가 많이 있습니다. 하지만 용기가 있다면 이 README를 클릭할 수 있습니다. 대신, 나는 JS 죄책감에 굶주려 배운 더 높은 수준의 테이크 아웃에 집중하고 싶습니다.

템플릿은 생각하는 것보다 훨씬 더 많이 사용됩니다.

나는 JavaScript 중독을 복구하는 이 프로젝트에 왔습니다. 구성 요소 기반 프레임워크를 사용하여 채우는 것을 좋아하는 몇 가지 정적 사이트 관련 요구 사항이 있습니다.

  1. 내 사이트를 JS 개체를 매개변수("props"라고도 함)로 받아들일 수 있는 재사용 가능한 UI 구성 요소로 나누고 싶습니다 .
  2. 프로덕션 사이트에 들어갈 수 있도록 빌드 시 정보를 가져와야 합니다.
  3. 파일 디렉토리 또는 콘텐츠의 뚱뚱한 JSON 개체에서 URL 경로를 생성해야 합니다 .

내 개인 블로그의 이 게시물에서 가져온 목록입니다.

하지만 눈치채셨겠지만… 이들 중 어느 것도 실제로 클라이언트 측 JavaScript가 필요하지 않습니다. React와 같은 구성 요소 프레임워크는 주로 React에 영감을 주는 Facebook 웹 앱과 같은 상태 관리 문제를 처리하도록 구축되었습니다. 사이트를 한 입 크기의 구성 요소 또는 디자인 시스템 요소로 나누는 경우 Pug와 같은 템플릿도 꽤 잘 작동합니다!

이 탐색 모음을 예로 들어 보겠습니다. Pug에서는 데이터를 props로 수신하는 "mixin"을 정의할 수 있습니다.

 // nav-mixins.pug mixin NavBar(links) // pug's version of a for loop each link in links a(href=link.href) link.text

그런 다음 해당 믹스인을 사이트 어디에서나 적용할 수 있습니다.

 // index.pug // kinda like an ESM "import" include nav-mixins.pug html body +NavBar(navLinksPassedByJS) main h1 Welcome to my pug playground

일부 데이터와 함께 이 파일을 "렌더링"하면 사용자에게 제공할 아름다운 index.html 을 얻을 수 있습니다.

 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] }) // use the NodeJS filesystem helpers to write a file to our build await writeFile('build/index.html', html)

물론 이것은 믹스인을 위한 범위가 지정된 CSS나 원하는 곳에 상태 저장 JavaScript와 같은 멋진 기능을 제공하지 않습니다. 그러나 React와 같은 것에 비해 몇 가지 매우 강력한 이점이 있습니다.

  1. 우리가 이해하지 못하는 멋진 번들러는 필요하지 않습니다.
    방금 pug.render 호출을 직접 작성했으며 배포할 준비가 된 사이트의 첫 번째 경로가 이미 있습니다.
  2. 최종 사용자에게 JavaScript를 제공하지 않습니다.
    React를 사용한다는 것은 종종 사람들의 브라우저를 실행하기 위해 큰 ole 런타임을 보내는 것을 의미합니다. 빌드 시 pug.render 와 같은 함수를 호출하여 모든 JS를 우리 편으로 유지하면서 마지막에는 깨끗한 .html 파일을 보냅니다.

이것이 템플릿이 정적 사이트를 위한 훌륭한 "기반"이라고 생각하는 이유입니다. 그래도 우리가 실제로 혜택을 볼 수 있는 구성 요소 프레임워크에 도달할 수 있다면 좋을 것입니다. 나중에 자세히 설명합니다.

추천 자료 : Zara Cooper 의 Pug로 더 나은 각도 템플릿을 만드는 방법

단일 페이지 앱을 빌드하는 데 프레임워크가 필요하지 않습니다.

거기에 있는 동안 내 사이트에서 섹시한 페이지 전환도 원했습니다. 그러나 프레임워크 없이 어떻게 이와 같은 것을 해낼 수 있습니까?

수직 와이프 전환이 있는 크로스페이드
수직 와이프 전환이 있는 크로스페이드. (큰 미리보기)

모든 페이지가 고유한 .html 파일인 경우에는 이 작업을 수행할 수 없습니다. 한 HTML 파일에서 다른 HTML 파일로 이동할 때 전체 브라우저가 새로 고쳐지므로 좋은 크로스 페이드 효과를 가질 수 없습니다(서로 위에 두 페이지를 간략하게 표시하기 때문에).

우리는 탐색하는 곳마다 HTML과 CSS를 "가져오기"하고 JavaScript를 사용하여 보기에 애니메이션을 적용하는 방법이 필요합니다. 이것은 단일 페이지 앱을 위한 작업처럼 들립니다! 이를 위해 간단한 브라우저 API 메들리를 사용했습니다.

  1. 이벤트 리스너를 사용하여 모든 링크 클릭을 가로챕니다.
  2. API 가져오기 : 방문하려는 페이지의 모든 리소스를 가져오고 애니메이션을 적용하고 싶은 부분을 가져옵니다.
  3. 웹 애니메이션 API : 새 콘텐츠에 애니메이션을 적용하여 키프레임으로 표시합니다.
  4. history API : window.history.pushState({}, 'new-route') 를 사용하여 브라우저의 URL 표시줄에 표시되는 경로를 변경합니다. 그렇지 않으면 이전 페이지를 떠나지 않은 것 같습니다!

명확성을 위해 다음은 간단한 찾기 및 바꾸기를 사용하여 단일 페이지 앱 개념을 시각적으로 보여줍니다( 출처 기사 ).

단계별 클라이언트 측 라우팅 프로세스: 1. 미디엄 레어 햄버거 반환, 2. fetch API를 사용하여 잘 만든 버거 요청, 3. 응답 마사지, 4. 'patty' 요소를 뽑아 적용 현재 페이지로 이동합니다.
단계별 클라이언트 측 라우팅 프로세스: 1. 미디엄 레어 햄버거 반환, 2. fetch API를 사용하여 잘 만든 버거 요청, 3. 응답 마사지, 4. 'patty' 요소를 뽑아 적용 현재 페이지로 이동합니다. (큰 미리보기)

참고 : 내 개인 사이트에서 소스 코드를 방문할 수도 있습니다.

물론, React et al과 선택한 애니메이션 라이브러리의 일부 페어링이 이 작업을 수행할 수 있습니다. 그러나 페이드 전환과 같은 단순한 사용 사례의 경우 웹 API는 그 자체로 매우 강력합니다. 그리고 Pug 또는 일반 HTML과 같은 정적 템플릿에서 보다 강력한 페이지 전환을 원할 경우 Swup과 같은 라이브러리가 도움이 될 것입니다.

11ty가 테이블에 가져온 것

이 시점에서 나는 내 작은 SSG에 대해 꽤 기분이 좋았습니다. 물론 빌드 시 CMS 데이터를 가져올 수 없었고 페이지 또는 디렉토리별로 다른 레이아웃을 지원하지 않았으며 내 이미지를 최적화하지 않았으며 증분 빌드가 없었습니다.

알겠습니다. 도움이 필요할 수 있습니다.

v1에서 배운 모든 것을 감안할 때 "제3자 빌드 파이프라인 금지" 규칙을 철회하고 기존 도구에 접근할 수 있는 권리를 얻었다고 생각했습니다. 11ty에는 내가 필요로 하는 기능이 많이 있습니다!

  • .11ydata.js 파일을 사용하여 빌드 시 데이터 가져오기
  • _data 폴더의 모든 템플릿에서 사용할 수 있는 전역 데이터.
  • 브라우저 동기화를 사용하여 개발 중 핫 리로딩
  • 멋진 HTML 변환 지원
  • … 그리고 셀 수 없이 많은 다른 것들.

Jekyll이나 Hugo와 같은 기본 SSG를 사용해 본 적이 있다면 11ty가 어떻게 작동하는지 꽤 잘 알고 있을 것입니다. 차이점만? 11ty는 JavaScript를 사용합니다.

11ty는 기본적으로 모든 템플릿 라이브러리를 지원하므로 모든 Pug 페이지를 .html 경로로 렌더링할 수 있어 기뻤습니다. 내 가짜 단일 페이지 앱 설정에도 도움이 된 레이아웃 체인 옵션입니다. 모든 경로에 대한 단일 script 와 해당 스크립트를 가져오기 위한 "전역" 레이아웃이 필요했습니다.

 // _includes/base-layout.html <html> <body> <!--load every page's content between some body tags--> {{ content }} <!--and apply the script tag just below this--> <script src="main.js"></script> </body> </html> // random-blog-post.pug --- layout: base-layout --- article h2 Welcome to my blog p Have you heard the story of Darth Plagueis the Wise?

main.js 가 우리가 탐색한 모든 링크 가로채기를 수행하는 한 페이지 전환이 있습니다!

아 그리고 데이터 캐스케이드

그래서 11ty는 v1에서 내 모든 스파게티 코드를 정리하는 데 도움이 되었습니다. 그러나 그것은 또 다른 중요한 부분을 가져왔습니다: 내 레이아웃에 데이터를 로드하기 위한 깨끗한 API입니다. 이것이 Jamstack 접근 방식의 핵심입니다. JavaScript + DOM 조작으로 브라우저에서 데이터를 가져오는 대신 다음을 수행할 수 있습니다.

  1. Node.js를 사용하여 빌드 시 데이터를 가져옵니다.
    이것은 일부 외부 API, 로컬 JSON 또는 YAML 가져오기 또는 사이트의 다른 경로 콘텐츠에 대한 호출일 수 있습니다(새 경로가 추가될 때마다 목차 업데이트를 상상해 보세요).
  2. 해당 데이터를 경로에 넣습니다. 이전에 작성한 .render 함수를 기억하십시오.
 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] })

...하지만 매번 데이터로 pug.render 를 호출하는 대신 11ty가 이 작업을 배후에서 수행하도록 합니다.

물론, 내 개인 사이트에 대한 데이터가 많지 않았습니다. 하지만 모든 개인 프로젝트를 위해 .yaml 파일을 만드는 것은 기분이 좋았습니다.

 # _data/works.yaml - title: Bits of Good Homepage hash: bog-homepage links: - href: https://bitsofgood.org text: Explore the live site - href: https://github.com/GTBitsOfGood/bog-web text: Scour the Svelt-ified codebase timeframe: May 2019 - present tags: - JAMstack - SvelteJS - title: Dolphin Audio Visualizer ...

모든 템플릿에서 해당 데이터에 액세스합니다.

 // home.pug .project-carousel each work in works h3 #{title} p #{timeframe} each tag in tags ...

create-react-app을 사용한 "클라이언트 측 렌더링"의 세계에서 나온 이것은 꽤 큰 폭로였습니다. 더 이상 API 키나 큰 JSON blob을 브라우저로 보낼 필요가 없습니다.

또한 내 사이트의 버전 1에 JavaScript 가져오기 및 애니메이션 개선을 위한 몇 가지 유용한 기능을 추가했습니다. 궁금하시다면 여기 내 README가 이 시점에 서 있었던 위치가 있습니다.

나는 이 시점에서 행복했지만 뭔가가 빠졌다

나는 JS 기반 구성 요소를 포기하고 템플릿(부팅에 대한 애니메이션 페이지 전환 포함)을 수용함으로써 놀라울 정도로 멀리 나아갔습니다. 그러나 이것이 내 요구를 영원히 충족시키지 못할 것이라는 것을 압니다. 내가 우리를 시작했던 그 큰 분열을 기억하십니까? 글쎄, 내 빌드 설정(캠프 #1에 단단히 고정되어 있음)과 JS화 상호 작용의 천국(Next, SvelteKit 및 기타 캠프 #2) 사이에는 분명히 여전히 계곡이 있습니다. 추가하고 싶다고 말하세요:

  • 열기/닫기 토글이 있는 팝업 모달,
  • Material UI와 같은 구성 요소 기반 디자인 시스템, 범위 지정 스타일 완성,
  • 상태 머신에 의해 구동되는 복잡한 다단계 형식.

당신이 평범한 JS 순수주의자라면 아마도 이러한 모든 사용 사례에 대해 프레임워크가 없는 답변을 가지고 있을 것입니다. 그러나 JQuery가 더 이상 표준이 아닌 이유가 있습니다! HTML, 범위 스타일 및 JavaScript "상태" 변수의 개별적이고 읽기 쉬운 구성 요소를 만드는 데는 매력적인 것이 있습니다. React, Vue, Svelte 등은 디버깅 및 테스트를 위한 너무 많은 기능을 제공하므로 직접적인 DOM 조작이 완전히 일치할 수 없습니다.

여기 내 백만 달러짜리 질문이 있습니다.

스트레이트 HTML 템플릿을 사용하여 시작하고 점진적으로 원하는 곳에 React/Vue/Svelte 구성 요소를 추가할 수 있습니까?

대답은 입니다. 해 보자.

11ty + Vite: A Match Made In Heaven ️

여기 내가 꿈꾸는 꿈이 있습니다. 인터랙티브한 것을 삽입하고 싶은 곳마다 "여기에 X React 구성 요소를 넣습니다"라는 작은 플래그를 템플릿에 남겨두고 싶습니다. 이것은 11ty가 지원하는 단축 코드 구문일 수 있습니다.

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react './components/FancyLiveDemo.jsx' %}

그러나 원피스 11ty는 (의도적으로) 모든 JavaScript를 번들로 묶는 방법을 피합니다. 번들링의 OG 길드에서 온 당신의 두뇌는 아마도 여기에서 Webpack, Rollup 또는 Babel 프로세스를 구축하는 데 뛰어들 것입니다. 큰 ole 진입점 파일을 만들고 최적화된 아름다운 코드를 출력하지 않습니까?

네, 하지만 이것은 꽤 관련될 수 있습니다. 예를 들어 React 구성 요소를 사용하는 경우 JSX용 로더, 모든 것을 변환하는 멋진 Babel 프로세스, SASS 및 CSS 모듈 가져오기용 인터프리터, 라이브 다시 로드에 도움이 되는 등이 필요할 것입니다.

.jsx 파일을 보고 정확히 무엇을 해야 하는지 알 수 있는 도구가 있다면.

입력: 비테

Vite는 최근까지 마을의 화두였습니다. JavaScript에서 거의 모든 것을 구축하기 위한 올인원 도구입니다. 다음은 집에서 시도해 볼 수 있는 예입니다. 머신 어딘가에 빈 디렉토리를 만들고 몇 가지 종속성을 설치해 보겠습니다.

 npm init -y # Make a new package.json with defaults set npm i vite react react-dom # Grab Vite + some dependencies to use React

이제 앱의 "진입점"으로 사용할 index.html 파일을 만들 수 있습니다. 매우 간단하게 유지하겠습니다.

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> </body> </html>

유일한 흥미로운 부분은 div id="root" 가 중간에 있다는 것입니다. 이것은 곧 우리 React 컴포넌트의 루트가 될 것입니다!

원하는 경우 Vite 서버를 실행하여 브라우저에서 일반 HTML 파일을 볼 수 있습니다. vite (또는 터미널에서 명령이 구성되지 않은 경우 npx vite )를 실행하면 다음과 같은 유용한 출력이 표시됩니다.

 vite vX.XX dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in Xms.

Browsersync 또는 다른 인기 있는 개발 서버와 마찬가지로 각 .html 파일의 이름은 우리 서버의 경로에 해당합니다. 따라서 index.htmlabout.html 로 이름을 바꾸면 http://localhost:3000/about/ 을 방문합니다(예, 뒤에 슬래시가 필요합니다!)

이제 흥미로운 것을 해보자. index.html 파일과 함께 일종의 기본 React 구성 요소를 추가합니다. 여기에서 React의 useState 를 사용하여 상호작용성을 보여줍니다.

 // TimesWeMispronouncedVite.jsx import React from 'react' export default function TimesWeMispronouncedVite() { const [count, setCount] = React.useState(0) return ( <div> <p>I've said Vite wrong {count} times today</p> <button onClick={() => setCount(count + 1)}>Add one</button> </div> ) }

이제 해당 구성 요소를 페이지에 로드해 보겠습니다. 이것이 index.html 에 추가해야 하는 전부입니다.

 <!DOCTYPE html> ... <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> <!--Don't forget type="module"! This lets us use ES import syntax in the browser--> <script type="module"> // path to our component. Note we still use .jsx here! import Component from './TimesWeMispronouncedVite.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('root'); ReactDOM.render(React.createElement(Component), componentRoot); </script> </body> </html>

네, 바로 그것입니다. .jsx 파일을 브라우저에서 사용할 수 있는 .js 파일로 직접 변환할 필요가 없습니다! Vite는 .jsx 가져오기를 볼 때마다 해당 파일을 브라우저가 이해할 수 있는 것으로 자동 변환합니다. 개발 작업 dist 또는 build 폴더도 없습니다. Vite는 모든 것을 즉석에서 처리합니다. 변경 사항을 저장할 때마다 핫 모듈 재로딩이 완료됩니다.

자, 우리는 믿을 수 없을 정도로 유능한 빌드 도구를 가지고 있습니다. 이것을 11ty 템플릿에 어떻게 가져올 수 있습니까?

11ty와 함께 Vite 실행

좋은 내용으로 넘어가기 전에 11ty와 Vite를 나란히 실행하는 것에 대해 논의해 보겠습니다. 계속해서 마지막 섹션의 동일한 프로젝트 디렉토리에 dev 종속성으로 11ty를 설치하십시오.

 npm i -D @11ty/eleventy # yes, it really is 11ty twice

이제 11ty가 작동하는지 확인하기 위해 약간의 비행 전 점검을 해 보겠습니다. 혼란을 피하기 위해 다음을 제안합니다.

  1. 이전의 index.html 파일을 삭제하십시오.
  2. TimesWeMispronouncedVite.jsx 를 새 디렉토리로 이동하십시오. 말하자면, components/ ;
  3. 우리 웹사이트가 src 폴더를 만드세요.
  4. 11ty가 처리할 수 있도록 해당 src 디렉토리에 템플릿을 추가합니다.

예를 들어 다음 콘텐츠가 포함된 blog-post.md 파일:

 # Hello world! It's markdown here

프로젝트 구조는 다음과 같아야 합니다.

 src/ blog-post.md components/ TimesWeMispronouncedVite.jsx

이제 다음과 같이 터미널에서 11ty를 실행합니다.

 npx eleventy --input=src

모든 것이 잘 진행되면 다음과 같은 빌드 출력이 표시되어야 합니다.

 _site/ blog-post/ index.html

여기서 _site 는 기본 출력 디렉토리이고 blog-post/index.html 은 브라우징을 위해 아름답게 변환된 마크다운 파일입니다.

일반적으로 npx eleventy --serve 를 실행하여 개발 서버를 가동하고 해당 /blog-post 페이지를 방문합니다. 하지만 지금은 개발자 서버에 Vite를 사용하고 있습니다! 목표는 다음과 같습니다.

  1. 110명이 _site 디렉토리에 마크다운, Pug, _site 등을 빌드하도록 합니다.
  2. 동일한 _site 디렉토리에 Vite를 지정하여 React 구성 요소, 멋진 스타일 가져오기 및 11ty가 선택하지 못한 기타 사항을 처리할 수 있습니다.

따라서 11ty가 Vite를 전달하는 2단계 빌드 프로세스입니다. 다음은 "감시" 모드에서 11ty와 Vite를 동시에 시작하는 데 필요한 CLI 명령입니다.

 (npx eleventy --input=src --watch) & npx vite _site

더 쉬운 디버깅을 위해 두 개의 개별 터미널에서 이러한 명령을 실행할 수도 있습니다.

운이 좋다면 http://localhost:3000/blog-post/ 를 방문하여 처리된 Markdown 파일을 볼 수 있습니다.

단축 코드로 부분 수분 공급

숏코드에 대해 간단히 알아보겠습니다. 이전 구문을 다시 살펴볼 시간입니다.

 {% react '/components/TimesWeMispronouncedVite.jsx' %}

단축 코드에 익숙하지 않은 사람들을 위해: 단축 코드는 함수 호출과 거의 동일합니다. 여기서 함수는 페이지에 슬라이드할 HTML 문자열을 반환합니다. 단축 코드의 "해부학"은 다음과 같습니다.

  • {% … %}
    단축 코드의 시작과 끝을 나타내는 래퍼.
  • react
    잠시 후 구성할 단축 코드 함수의 이름입니다.
  • '/components/TimesWeMispronouncedVite.jsx'
    단축 코드 함수에 대한 첫 번째(그리고 유일한) 인수입니다. 원하는 만큼 많은 인수를 가질 수 있습니다.

첫 번째 단축 코드를 연결해 봅시다! .eleventy.js 파일을 프로젝트 베이스에 추가하고 react 단축 코드에 대해 다음 구성 항목을 추가합니다.

 // .eleventy.js, at the base of the project module.exports = function(eleventyConfig) { eleventyConfig.addShortcode('react', function(componentPath) { // return any valid HTML to insert return `<div>This is where we'll import ${componentPath}</div>` }) return { dir: { // so we don't have to write `--input=src` in our terminal every time! input: 'src', } } }

이제 새로운 단축 코드로 blog-post.md 를 꾸며봅시다. 이 콘텐츠를 마크다운 파일에 붙여넣습니다.

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react '/components/TimesWeMispronouncedVite.jsx' %}

그리고 빠른 npx eleventy 를 실행하면 _site 아래의 /blog-post/index.html 디렉토리에서 이 출력을 볼 수 있습니다.

 <h1>Super interesting programming tutorial</h1> <p>Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example!</p> <div>This is where we'll import /components/TimesWeMispronouncedVite.jsx</div>

구성 요소 단축 코드 작성

이제 해당 단축 코드로 유용한 작업을 수행해 보겠습니다. Vite를 사용하면서 작성한 script 태그를 기억하십니까? 글쎄, 우리는 우리의 단축 코드에서 같은 일을 할 수 있습니다! 이번에는 componentPath 인수를 사용하여 가져오기를 생성하지만 나머지는 거의 동일하게 유지합니다.

 // .eleventy.js module.exports = function(eleventyConfig) { let idCounter = 0; // copy all our /components to the output directory // so Vite can find them. Very important step! eleventyConfig.addPassthroughCopy('components') eleventyConfig.addShortcode('react', function (componentPath) { // we'll use idCounter to generate unique IDs for each "root" div // this lets us use multiple components / shortcodes on the same page idCounter += 1; const componentRootId = `component-root-${idCounter}` return ` <div></div> <script type="module"> // use JSON.stringify to // 1) wrap our componentPath in quotes // 2) strip any invalid characters. Probably a non-issue, but good to be cautious! import Component from ${JSON.stringify(componentPath)}; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('${componentRootId}'); ReactDOM.render(React.createElement(Component), componentRoot); </script> ` }) eleventyConfig.on('beforeBuild', function () { // reset the counter for each new build // otherwise, it'll count up higher and higher on every live reload idCounter = 0; }) return { dir: { input: 'src', } } }

이제 단축 코드(예: {% react '/components/TimesWeMispronouncedVite.jsx' %} )를 호출하면 다음과 같이 출력되어야 합니다.

 <div></div> <script type="module"> import Component from './components/FancyLiveDemo.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('component-root-1'); ReactDOM.render(React.createElement(Component), componentRoot); </script>

(npx eleventy --watch) & vite _site 를 사용하여 개발 서버를 방문하면 클릭 가능한 카운터 요소가 아름답게 표시되어야 합니다.

유행어 경고 — 부분 수화 및 섬 구조

우리는 가장 단순한 형태로 "섬 건축"을 시연했습니다. 이것은 대화형 구성 요소 트리가 전체 웹 사이트를 사용할 필요가 없다는 아이디어입니다. 대신, 우리는 상호 작용이 실제로 필요한 위치에 따라 앱 전체에 미니 트리 또는 "섬"을 만들 수 있습니다. 관리할 상태가 없는 링크의 기본 방문 페이지가 있습니까? 엄청난! 대화형 구성 요소가 필요하지 않습니다. 그러나 X React 라이브러리의 이점을 얻을 수 있는 다단계 양식이 있습니까? 문제 없어요. react 단축 코드와 같은 기술을 사용하여 Form.jsx 섬을 회전시킵니다.

이것은 "부분적 수화"라는 아이디어와 관련이 있습니다. NextJS 또는 Gatsby와 같은 구성 요소 SSG로 작업하는 경우 "수화"라는 용어를 들었을 것입니다. 간단히 말해서 다음과 같은 방법입니다.

  1. 먼저 구성 요소를 정적 HTML로 렌더링하십시오.
    이것은 사용자가 웹사이트를 처음 방문할 때 볼 수 있는 것을 제공합니다.
  2. 상호 작용으로 이 HTML을 "수화"하십시오.
    여기에서 상태 후크와 렌더러를 연결하여 버튼 클릭이 실제로 무언가를 트리거하도록 합니다.

이 1-2 펀치는 JS 기반 프레임워크를 정적 사이트에서 실행 가능하게 만듭니다. JavaScript가 구문 분석을 완료하기 전에 사용자가 볼 것이 있는 한 해당 등대 지표에서 괜찮은 점수를 얻을 수 있습니다.

글쎄, 당신이하지 않을 때까지. 모든 마지막 DOM 요소 를 처리할 준비가 된 JavaScript 번들이 필요하기 때문에 전체 웹사이트를 "수화"하는 것은 비용이 많이 들 수 있습니다. 그러나 우리의 지저분한 단축 코드 기술은 전체 페이지를 다루지 않습니다 ! 그 대신, 필요한 곳에만 구성 요소를 삽입하여 존재하는 콘텐츠를 "부분적으로" 수화합니다.

걱정하지 마세요. 이 모든 것을 위한 플러그인이 있습니다: Slinkity

여기에서 발견한 내용을 요약해 보겠습니다.

  1. Vite는 추가 구성 없이 대부분의 파일 유형(예: jsx , vuesvelte )을 처리할 수 있는 믿을 수 없을 정도로 유능한 번들러입니다.
  2. 단축 코드는 HTML 청크를 구성 요소 스타일의 템플릿에 삽입하는 쉬운 방법입니다.
  3. 부분 수화를 사용하여 원하는 곳 어디에서나 단축 코드를 사용하여 동적 대화형 JS 번들을 렌더링할 수 있습니다.

그렇다면 최적화된 프로덕션 빌드는 어떻습니까? 범위가 지정된 스타일을 올바르게 로드하고 있습니까? 도대체, .jsx 를 사용하여 전체 페이지를 만드시겠습니까? 글쎄, 나는 이 모든 것(그리고 훨씬 더 많은 것!)을 Slinkity라는 프로젝트에 묶었습니다. 프로젝트에 대한 커뮤니티의 따뜻한 환영을 보게 되어 기쁩니다. 독자 여러분, 직접 사용해 보시기 바랍니다!

빠른 시작 가이드 사용해 보기

아스트로의 꽤 위대하다

최첨단 기술에 눈을 뜬 독자라면 아마 한 번쯤은 아스트로를 떠올렸을 것입니다. 그리고 난 당신을 비난할 수 없습니다! 이는 매우 유사한 목표를 염두에 두고 구축되었습니다. 일반 HTML로 시작하여 필요할 때마다 상태 저장 구성 요소를 삽입하는 것입니다. 젠장, Vue 내부에 React 구성 요소를 작성하거나 HTML 템플릿 파일 내부에 Svelte 구성 요소를 작성할 수도 있습니다! MDX 익스트림 에디션과 비슷합니다.

하지만 그들의 접근 방식에는 한 가지 큰 비용이 듭니다 . 앱을 처음부터 다시 작성해야 합니다. 이것은 JSX를 기반으로 하는 새로운 템플릿 형식(편하지 않을 수 있음), 현재 몇 가지 멋진 기능이 누락된 완전히 새로운 데이터 파이프라인 및 꼬임을 해결할 때 일반적인 버그를 의미합니다.

그러나 Slinkity와 같은 도구를 사용하여 11ty + Vite 칵테일을 만들 수 있습니까? 음, 이미 11ty 사이트가 있는 경우 Vite는 재작성 없이 제자리에 고정되어야 하며 단축 코드는 .astro 파일과 동일한 많은 사용 사례를 다루어야 합니다. 나는 그것이 지금 완벽과는 거리가 멀다 는 것을 인정할 것이다. 하지만 지금까지는 유용했고 사이트 전체에서 다시 작성하는 것을 피하고 싶다면 꽤 강력한 대안이라고 생각합니다!

마무리

이 Slinkity 실험은 지금까지 내 요구 사항을 잘 충족했습니다(그리고 여러분 중 일부도 마찬가지입니다!). JAM에 적합한 스택을 자유롭게 사용하십시오. 저는 제 1년 동안의 빌드 도구 방탕한 결과를 공유하게 되어 매우 기쁩니다. 그리고 우리가 Jamstack의 큰 격차를 해소할 수 있는 방법을 알게 되어 너무 기쁩니다.

추가 읽기

부분 수화, ESM 또는 SSG에 대해 더 자세히 알고 싶으십니까? 다음 사항을 확인하십시오.

  • 섬 건축
    Jason Format의 이 블로그 게시물은 웹 개발의 "섬"과 "부분적 수화"에 대한 논의를 시작했습니다. 유용한 다이어그램과 아이디어 뒤에 숨겨진 철학으로 가득 차 있습니다.
  • 맞춤형 정적 사이트 생성기로 정적 단순화
    노드 기반 웹 사이트 빌더를 처음부터 만드는 과정을 안내하는 또 다른 SmashingMag 기사. 저에게 큰 영감을 주었습니다!
  • ES 모듈이 웹 개발을 재정의한 방법
    ES 모듈이 웹 개발 게임을 어떻게 변화시켰는지에 대한 개인 게시물입니다. 이것은 웹에서 가져오기 구문의 "그때와 지금"에 대해 조금 더 자세히 설명합니다.
  • 웹 구성 요소 소개
    웹 구성 요소가 무엇인지, shadow DOM이 작동하는 방식, 웹 구성 요소가 유용한 위치에 대한 훌륭한 설명입니다. 이 가이드를 사용하여 사용자 정의 구성 요소를 내 프레임워크에 적용했습니다!