기본

MM·2024년 4월 25일

AstroDeepDive

목록 보기
1/7
post-thumbnail

시작하기

설치

npm create astro@latest -- --template <example-name>



핵심 개념

왜 Astro인가?

Next.js나 RemixAstro
성능 문제를 해결해야 하는 곳에서만 부분적으로 SSR을 사용필요한 경우에만 부분적으로 CSR 사용
SPA로 페이지 로드 후에야 콘텐츠 동적 생성-> TTI(Time To Interaction)에 악영향MPA 지원
첫 로딩 성능이 중요한 콘텐츠 중심 웹사이트에는 좋지 않음SSR를 적극적으로 활용하여 콘텐츠가 많은 동적 웹사이트를 고성능으로 제작 가능

🤔 근데 Next.js도 필요한 곳에서만 use client쓰지 않나?


Astro 아일랜드

부분 수화

일반적으로 CSR은 초기 페이지 로드 후 전체 컴포넌트 트리를 로드하고 렌더링한다.
-> 단순하고 강력함.
-> 클라이언트 측 JS사용이 많아 페이지 로드 성능 문제 존재.


그러나 부분 수화는 필요한 부분만 로드 및 렌더링한다!
-> 선택적이고 전략적인 수화.
-> 이것을 이용한 패턴이 컴포넌트 아일랜드 패턴.


아일랜드

클라이언트와 상호작용하는 대화형 ui 컴포넌트.

  • Astro는 UI 컴포넌트의 모든 클라이언트 측 JavaScript를 제거하고 HTML 및 CSS로 렌더링
    • 그러므로 아일랜드별로 다른 프레임워크를 선택할 수 있다!😳😳
    • JS는 필요한 개별 컴포넌트에 대해서만 로드된다.
  • 아일랜드별 우선순위 작용
    • 클라이언트 지시어를 사용하여 렌더링 시점을 정확히 부여 가능!
  • 병렬 로딩

-> 이것이 astro가 웹 사이트를 빠르게 유지하는 비결!

아일랜드 생성

<MyReactComponent1 />             //SSR 아일랜드
<MyReactComponent2 client:지시어 /> //CSR 아일랜드



기본

프로젝트 구조

src

Astro에 의해 자동으로 빌드되고 처리되는 디렉터리

  • 컴포넌트
    • 코드 그대로 브라우저 전송X
    • 정적 HTML로 렌더링후 전송O
  • CSS
    • 최적화 및 번들링된 후 브라우저 전송

content

콘텐츠 컬렉션 및 선택적 컬렉션 구성 파일 저장
-> 그 외에 다른 파일이 허용되지 않음!

pages

필수 하위 디렉터리
-> 이 디렉터리가 존재하지 않으면 사이트의 페이지나 경로 또한 존재하지 않는다!


public

빌드 프로세스 중 처리할 필요가 없는 정적 파일들로, 그대로 빌드 폴더에 복사됨



Astro 컴포넌트

Astro 프로젝트의 기본 구성 요소.

  • HTML전용 템플릿 컴포넌트
  • 클라이언트에서 렌더링되지 않음
    • 즉, 클라이언트 측 런타임이 없다

컴포넌트 스크립트

코드 펜스 (----)

astro는 코드 펜스를 이용하여 컴포넌트 스크립트를 식별한다.
-> 코드 펜스로 감싸진 부분은 클라이언트 측에서 실행되지 않는, 즉 사용자 브라우저로 전송되지 않는 부분.
-> 따라서 해당 부분에 비공개 데이터베이스 호출이나 비용이 많이 드는 코드를 작성할 수 있다.

컴포넌트 템플릿

코드 펜스 아래에 있는 부분. 컴포넌트의 html 출력을 결정한다

---
// 컴포넌트 스크립트
import SomeAstroComponent from '../components/SomeAstroComponent.astro';
import SomeReactComponent from '../components/SomeReactComponent.jsx';
import someData from '../data/pokemon.json';

// `<X title="안녕하세요!" />`
const { title } = Astro.props;
const data = await fetch('SOME_SECRET_API_URL/users').then((r) => r.json());
---

//컴포넌트 템플릿
<Banner />
<h1>안녕하세요!</h1>
<p>{title}</p>
<ReactPokemonComponent client:visible />

<ul>
  {myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>
<p class:list={['add', 'dynamic', { classNames: true }]}></p>

슬롯

외부 HTML콘텐츠를 위한 공간.

map에서 슬롯 name을 동적으로 생성하는 것은 불가능!

//Wrapper.astro
---
import Header from './Header.astro';
import Footer from './Footer.astro';

const { title } = Astro.props;
---
<div id="content-wrapper">
  <Header />
  <slot name="after-header" />
  <h1>{title}</h1>
   <slot>
    <p>이것은 슬롯에 전달된 하위 요소가 없는 경우 렌더링 될 대체 콘텐츠입니다.</p>
  </slot>
  <Footer />
  <slot name="after-footer" />
</div>


//fred.astro
---
import Wrapper from '../components/Wrapper.astro';
---

<Wrapper title="Fred's Page">
  <img src="https://my.photo/fred.jpg" slot="after-header" />
  <p>My name is Fred</p>
  <p slot="after-footer">Copyright 2023</p>
</Wrapper>

드릴링을 고려할 필요가 없어졌지만, 동시에 슬롯 관리 및 정리를 잘 해야 할 듯..🤔



pages

Astro는 파일 기반 라우팅 시스템을 채택했다!

웹사이트의 모든 페이지에 대해 라우팅, 데이터 불러오기, 전체 페이지 레이아웃 처리를 수행

 <a href="/authors/sonali/"/> // https://example.com/authors/sonali

.astro

Astro 컴포넌트와 동일한 기능을 지원하는 html문서
-> DOCTYPE html, head 태그가 자동으로 포함된다

---
---
<html lang="ko">
  <head>
    <title>나의 홈페이지</title>
  </head>
  <body>
    <h1>제 웹사이트에 오신 것을 환영합니다!</h1>
  </body>
</html>

.md

마크다운을 쓸 수 있다는게 블로그에 정말 최적화된듯...😳

---
layout: '../layouts/MySiteLayout.astro'
title: '나의 Markdown 페이지'
---
# 제목

이 페이지는 **Markdown**으로 작성되었습니다.

404

404.astro나 404.md 로 만들 수 있음



부분적 페이지

부분적 페이지를 이용하여 새로고침이나 페이지 탐색 없이 동적으로 HTML 섹션을 불러올 수 있다.
-> 머 어케 쓰는거지 그냥 저대로 컴포넌트 만들면 되나

---
export const partial = true;
---

<li>부분적 페이지</li>


layout

UI 구조를 제공하는 Astro 컴포넌트

중첩 레이아웃

---
import BaseLayout from './BaseLayout.astro';
const { frontmatter } = Astro.props;
---
<BaseLayout url={frontmatter.url}>
  <h1>{frontmatter.title}</h1>
  <h2>게시물 작성자: {frontmatter.author}</h2>
  <slot />
</BaseLayout>


Astro template 구문

동적 속성

script 태그 안에서 순수js처럼 구현해야 함!

---
const handleClick = () => {
    console.log("버튼이 클릭되었습니다!");
}
---

<button onClick={handleClick}>클릭해도 아무 일도 일어나지 않습니다!</button>

<button id="button">클릭하세요</button>
<script>
  const handleClick = () => {console.log("버튼이 클릭되었습니다!");}
  document.getElementById("button").addEventListener("click", handleClick);
</script>

동적 태그

---
import MyComponent from "./MyComponent.astro";
const Element = 'div'
const Component = MyComponent;
---
<Element>안녕하세요!</Element>  // <div>안녕하세요!</div>
<Component />                 // <MyComponent /> 

Jsx와의 차이점

속성명에 kebab-case 형식 사용

<div className="box" dataValue="3" />   // X
<div class="box"     data-value="3" />  // O

주석

---
---
<!-- html 주석은 브라우저 Dom구조에 포함된다 -->
{/* JS 주석은 포함되지 않는다 */}


렌더링 모드(서버 output모드)

기본 렌더링 모드(output:'static')

빌드시 모든 페이지 경로에 대한 사전 렌더링 수행

  • 모든 방문자가 동일한 HTML문서를 보게 됨
  • SSG(정적 사이트 생성)
    • 페이지 업데이트시 전체 사이트 재빌드
  • 요청 전에 미리 페이지를 렌더링
    • 사용자에게 가벼운 브라우저 경험 제공
    • 백엔드 성능에 의지하지 않음
  • 대화형 UI 컴포넌트 포함 가능
  • 미들웨어 사용 가능

주문형 렌더링 모드

요청 시 렌더링(SSR)을 포함하는 모드.

  • 방문자에 따라 맞춤 설정 가능
    • 계정 정보 표시
    • 사용자 권한에 따른 액세스 처리
  • 전체 사이트를 다시 빌드하지 않고도 새로 업데이트된 데이터 표시 가능
  • 데이터베이스 액세스, 인증, 권한 부여와 같은 작업을 위한 API 엔드포인트 페이지 생성 가능

매우 동적인 모드(output: 'server')

대부분 또는 모든 경로가 주문형 경로로 구성된 매우 동적인 사이트를 위한 옵션

거의 정적인 모드(output: 'hybrid')

일부 주문형 경로가 포함된 거의 정적인 사이트를 위한 옵션

profile
중요한 건 꺾여도 그냥 하는 마음

0개의 댓글