컨텐츠로 이동

라우팅

Astro는 파일 기반 라우팅을 사용하여 프로젝트 src/pages/ 디렉터리의 파일 레이아웃을 기반으로 빌드 URL을 생성합니다.

Astro는 표준 HTML <a> 요소를 사용하여 경로를 탐색합니다. 프레임워크별 <Link> 컴포넌트는 제공되지 않습니다.

src/pages/index.astro
<p>Read more <a href="/about/">about</a> Astro!</p>

.astro 페이지 컴포넌트src/pages/ 디렉터리의 Markdown 및 MDX 파일 (.md, .mdx)은 자동으로 웹사이트의 페이지가 됩니다. 각 페이지의 경로는 src/pages/ 디렉터리의 경로와 파일 이름에 해당합니다.

# Example: Static routes
src/pages/index.astro -> mysite.com/
src/pages/about.astro -> mysite.com/about
src/pages/about/index.astro -> mysite.com/about
src/pages/about/me.astro -> mysite.com/about/me
src/pages/posts/1.md -> mysite.com/posts/1

Astro 페이지 파일은 파일 이름에 동적 경로 매개변수를 지정하여 일치하는 여러 페이지를 생성할 수 있습니다. 예를 들어 src/pages/authors/[author].astro 파일은 블로그의 모든 작성자에 대한 약력 페이지를 생성합니다. author는 페이지 내부에서 액세스할 수 있는 매개변수 가 됩니다.

Astro의 기본 정적 출력 모드에서 이러한 페이지는 빌드 시 생성되므로, 해당 파일을 가져오는 author 목록을 미리 결정해야 합니다. SSR 모드에서는 일치하는 경로에 대한 요청이 있을 때 페이지가 생성됩니다.

모든 경로는 빌드 시 결정되어야 하기 때문에 동적 경로는 params 속성이 있는 객체 배열을 반환하는 getStaticPaths()를 내보내야 합니다. 이러한 각 객체는 해당 경로를 생성합니다.

[dog].astro 파일은 파일 이름에 동적 dog 매개변수를 정의하므로 getStaticPaths()에 의해 반환된 객체는 paramsdog을 포함해야 합니다. 그러면 페이지는 Astro.params를 사용하여 이 매개변수에 액세스할 수 있습니다.

src/pages/dogs/[dog].astro
---
export function getStaticPaths() {
return [
{params: {dog: 'clifford'}},
{params: {dog: 'rover'}},
{params: {dog: 'spot'}},
];
}
const { dog } = Astro.params;
---
<div>Good dog, {dog}!</div>

이렇게 하면 /dogs/clifford, /dogs/rover, /dogs/spot의 세 페이지가 생성되며 각각에 해당되는 개 이름을 표시합니다.

파일 이름에는 여러 매개변수가 포함될 수 있으며, 이 매개변수는 getStaticPaths()params 객체에 모두 포함되어야 합니다.

src/pages/[lang]-[version]/info.astro
---
export function getStaticPaths () {
return [
{params: {lang: 'en', version: 'v1'}},
{params: {lang: 'fr', version: 'v2'}},
];
}
const { lang, version } = Astro.params;
---
...

그러면 /en-v1/info/fr-v2/info가 생성됩니다.

매개변수는 경로의 개별 부분에 포함될 수 있습니다. 예를 들어, 위와 동일한 getStaticPaths()가 있는 src/pages/[lang]/[version]/info.astro 파일은 /en/v1/info/fr/v2/info 경로를 생성합니다.

getStaticPaths()에 대해 자세히 알아보세요.
관련 레시피: Add i18n features (EN)

URL 라우팅에 더 많은 유연성이 필요한 경우 나머지 매개변수 ([...path])를 .astro 파일 이름에 추가하여 모든 깊이의 파일 경로와 일치시킵니다.

src/pages/sequences/[...path].astro
---
export function getStaticPaths() {
return [
{params: {path: 'one/two/three'}},
{params: {path: 'four'}},
{params: {path: undefined }}
]
}
const { path } = Astro.params;
---
...

그러면 /sequences/one/two/three, /sequences/four, /sequences가 생성됩니다. (나머지 매개변수를 undefined로 설정하면 최상위 페이지와 일치하게 됩니다.)

나머지 매개변수는 다른 명명된 매개변수와 함께 사용할 수 있습니다. 예를 들어 GitHub의 파일 뷰어는 다음 동적 경로로 표시될 수 있습니다.

/[org]/[repo]/tree/[branch]/[...file]

이 예시에서 /withastro/astro/tree/main/docs/public/favicon.svg에 대한 요청은 다음과 같은 명명된 매개변수로 분할됩니다.

{
org: 'withastro',
repo: 'astro',
branch: 'main',
file: 'docs/public/favicon.svg'
}

예: 여러 수준의 동적 페이지

섹션 제목: 예: 여러 수준의 동적 페이지

다음 예시에서 나머지 매개변수 ([...slug])와 getStaticPaths()props 기능은 다양한 깊이의 슬러그에 대한 페이지를 생성합니다.

src/pages/[...slug].astro
---
export async function getStaticPaths() {
const pages = [
{
slug: undefined,
title: "Astro Store",
text: "Welcome to the Astro store!",
},
{
slug: "products",
title: "Astro products",
text: "We have lots of products for you",
},
{
slug: "products/astro-handbook",
title: "The ultimate Astro handbook",
text: "If you want to learn Astro, you must read this book.",
},
];
return pages.map(({ slug, title, text }) => {
return {
params: { slug },
props: { title, text },
};
});
}
const { title, text } = Astro.props;
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>

SSR 모드에서 동적 경로는 동일한 방식으로 정의됩니다. 임의의 문자열이나 경로와 일치하도록 파일 이름에 [param] 또는 [...path] 대괄호를 포함합니다. 그러나 경로가 더 이상 미리 빌드되지 않기 때문에 페이지는 일치하는 모든 경로에 제공됩니다. 이는 “정적” 경로가 아니므로 getStaticPaths를 사용하면 안 됩니다.

src/pages/resources/[resource]/[id].astro
---
const { resource, id } = Astro.params;
---
<h1>{resource}: {id}</h1>

이 페이지는 resourceid 값 (resources/users/1, resources/colors/blue 등)에 대해 제공됩니다.

SSR에 대한 [...slug] 예시 수정

섹션 제목: SSR에 대한 [...slug] 예시 수정

SSR 페이지는 getStaticPaths()를 사용할 수 없기 때문에 props를 받을 수 없습니다. 이전 예시는 객체에서 slug 매개변수 값을 조회하여 SSR 모드에 맞게 조정할 수 있습니다. 경로가 루트 (”/“)에 있으면 슬러그 매개변수는 undefined가 됩니다. 객체에 값이 없으면 404 페이지로 리디렉션됩니다.

src/pages/[...slug].astro
---
const pages = [
{
slug: undefined,
title: 'Astro Store',
text: 'Welcome to the Astro store!',
},
{
slug: 'products',
title: 'Astro products',
text: 'We have lots of products for you',
},
{
slug: 'products/astro-handbook',
title: 'The ultimate Astro handbook',
text: 'If you want to learn Astro, you must read this book.',
}
];
const { slug } = Astro.params;
const page = pages.find((page) => page.slug === slug);
if (!page) return Astro.redirect("/404");
const { title, text } = page;
---
<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{text}</p>
</body>
</html>

사이트 구조가 영구적으로 변경되었거나 인증된 경로에 로그인하는 등의 작업에 대한 응답으로 사용자를 새 페이지로 리디렉션해야 하는 경우가 있습니다.

Astro 구성에서 영구적으로 이동된 페이지로 사용자를 리디렉션하는 규칙을 정의할 수 있습니다. 또는 사용자가 여러분의 사이트를 사용할 때 사용자를 동적으로 리디렉션할 수도 있습니다.

Added in: astro@2.9.0

redirects 값을 사용하여 Astro 구성에서 영구 리디렉션 매핑을 지정할 수 있습니다. 대부분의 리디렉션에서 이는 이전 경로를 새 경로로 매핑합니다.

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/old-page': '/new-page'
}
});

이러한 리디렉션은 파일 기반 경로와 동일한 규칙을 따릅니다. 새 경로와 이전 경로 모두에 동일한 매개변수가 포함되어 있는 한 동적 경로가 허용됩니다. 예를 들면 다음과 같습니다.

{
"/blog/[...slug]": "/articles/[...slug]"
}

SSR 또는 정적 어댑터를 사용하면 객체를 값으로 제공하여 새로운 destination 외에 status 코드를 지정할 수도 있습니다.

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
redirects: {
'/old-page': {
status: 302,
destination: '/new-page'
}
}
});

astro build를 실행하면 Astro는 기본적으로 meta refresh 태그가 포함된 HTML 파일을 출력합니다. 지원되는 어댑터는 대신 리디렉션을 사용하여 호스트의 구성 파일을 작성합니다.

상태 코드는 기본적으로 301입니다. HTML 파일로 빌드하는 경우 서버에서는 상태 코드를 사용하지 않습니다.

Astro 전역에서 Astro.redirect 메소드를 사용하면 다른 페이지로 동적으로 리디렉션할 수 있습니다. 쿠키에서 세션을 가져와 사용자가 로그인했는지 확인한 후 이 작업을 수행할 수 있습니다.

src/pages/account.astro
---
import { isLoggedIn } from '../utils';
const cookie = Astro.request.headers.get('cookie');
// 사용자가 로그인되어 있지 않은 경우 로그인 페이지로 리디렉션
if (!isLoggedIn(cookie)) {
return Astro.redirect('/login');
}
---
<html>
<!-- 페이지... -->
</html>

정의된 여러 경로가 동일한 URL 경로를 빌드하려고 시도할 수 있습니다. 예를 들어, 다음 경로는 모두 /posts/create를 빌드할 수 있습니다.

  • 디렉터리src/pages/
    • […slug].astro
    • 디렉터리posts/
      • create.astro
      • [page].astro
      • [pid].ts
      • […slug].astro

Astro는 페이지를 빌드하는 데 어떤 경로를 사용해야 하는지 알아야 합니다. 이를 위해 다음 규칙에 따라 순서대로 정렬합니다.

  • 더 많은 경로 세그먼트를 가진 경로가 덜 구체적인 경로보다 우선합니다. 위 예시에서 /posts/ 아래의 모든 경로는 루트의 /[...slug].astro보다 우선합니다.
  • 경로 매개변수가 없는 정적 경로는 동적 경로보다 우선합니다. 예: /posts/create.astro는 예시의 다른 모든 경로보다 우선합니다.
  • 명명된 매개변수를 사용하는 동적 경로는 나머지 매개변수보다 우선합니다. 예: /posts/[page].astro/posts/[...slug].astro보다 우선합니다.
  • 사전 렌더링된 동적 경로는 서버 동적 경로보다 우선합니다.
  • 엔드포인트가 페이지보다 우선합니다.
  • 위 규칙 중 어느 것도 순서를 결정하지 않으면 노드 설치의 기본 로케일을 기준으로 경로가 알파벳순으로 정렬됩니다.

위 예시에서 규칙이 요청된 URL을 HTML 작성에 사용된 경로와 일치시키는 방법에 대한 몇 가지 예시는 다음과 같습니다.

  • pages/posts/create.astro - /posts/create만 빌드합니다.
  • pages/posts/[pid].ts - /posts/abc, /posts/xyz 등을 빌드하지만 /posts/create는 빌드하지 않습니다.
  • pages/posts/[page].astro - /posts/1, /posts/2 등을 빌드하지만 /posts/create, /posts/abc, /posts/xyz는 빌드하지 않습니다.
  • pages/posts/[...slug].astro - /posts/1/2, /posts/a/b/c 등을 빌드하지만 /posts/create, /posts/1, /posts/abc 등은 빌드하지 않습니다.
  • pages/[...slug].astro - /abc, /xyz, /abc/xyz 등을 빌드하지만 /posts/create, /posts/1, /posts/abc 등은 빌드하지 않습니다.

Astro는 여러 페이지로 분할해야 하는 대규모 데이터 컬렉션에 대해 내장된 페이지네이션을 지원합니다. Astro는 이전/다음 페이지 URL, 총 페이지 수 등을 포함한 일반적인 페이지네이션 속성을 생성합니다.

페이지가 매겨진 경로 이름은 표준 동적 경로와 동일한 [대괄호] 구문을 사용해야 합니다. 예를 들어 파일 이름 /astronauts/[page].astro/astronauts/1, /astronauts/2 등에 대한 경로를 생성합니다. 여기서 [page]는 생성된 페이지 번호입니다.

paginate() 함수를 사용하여 다음과 같은 값 배열에 대한 이러한 페이지를 생성할 수 있습니다.

src/pages/astronauts/[page].astro
---
export async function getStaticPaths({ paginate }) {
const astronautPages = [{
astronaut: 'Neil Armstrong',
}, {
astronaut: 'Buzz Aldrin',
}, {
astronaut: 'Sally Ride',
}, {
astronaut: 'John Glenn',
}];
// astronauts 배열에서 한 페이지에 2개의 페이지를 생성합니다.
return paginate(astronautPages, { pageSize: 2 });
}
// 페이지가 매겨진 모든 데이터는 "page" prop으로 전달됩니다.
const { page } = Astro.props;
---
<!--현재 페이지 번호를 표시합니다. Astro.params.page도 사용할 수 있습니다!-->
<h1>Page {page.currentPage}</h1>
<ul>
<!--astronauts 정보 배열 나열-->
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>

그러면 한 페이지에 2개의 항목이 포함된 다음 페이지가 생성됩니다.

  • /astronauts/1 - 페이지 1: “Neil Armstrong” 및 “Buzz Aldrin” 표시
  • /astronauts/2 - 페이지 2: “Sally Ride” 및 “John Glenn” 표시

paginate() 함수를 사용하면 각 페이지는 page prop을 통해 데이터가 전달됩니다. page prop에는 유용한 속성이 많이 있지만 주요 내용은 다음과 같습니다.

  • page.data - paginate() 함수에 전달한 페이지의 데이터 조각을 포함하는 배열
  • page.url.next - 세트의 다음 페이지에 대한 링크
  • page.url.prev - 세트의 이전 페이지에 대한 링크
src/pages/astronauts/[page].astro
---
// 이전 예시와 동일한 { astronaut } 객체 목록에 페이지를 매깁니다.
export async function getStaticPaths({ paginate }) { /* ... */ }
const { page } = Astro.props;
---
<h1>Page {page.currentPage}</h1>
<ul>
{page.data.map(({ astronaut }) => <li>{astronaut}</li>)}
</ul>
{page.url.prev ? <a href={page.url.prev}>Previous</a> : null}
{page.url.next ? <a href={page.url.next}>Next</a> : null}
interface Page<T = any> {
/** result */
data: T[];
/** 메타데이터 */
/** 0부터 시작하는 페이지의 첫 번째 항목 수 */
start: number;
/** 0부터 시작하는 페이지의 마지막 항목 수 */
end: number;
/** 총 결과 수 */
total: number;
/** 1부터 시작하는 현재 페이지 번호 */
currentPage: number;
/** 페이지당 항목 수(기본값: 25) */
size: number;
/** 마지막 페이지 수 */
lastPage: number;
url: {
/** 현재 페이지의 URL */
current: string;
/** 이전 페이지의 URL (존재하는 경우) */
prev: string | undefined;
/** 다음 페이지의 URL (존재하는 경우) */
next: string | undefined;
};
}

페이지네이션의 고급 사용 사례는 중첩 페이지네이션입니다. 이는 페이지네이션이 다른 동적 경로 매개변수와 결합되는 경우입니다. 중첩된 페이지네이션을 사용하여 페이지가 매겨진 컬렉션을 일부 속성이나 태그별로 그룹화할 수 있습니다.

예를 들어, 페이지가 매겨진 Markdown 게시물을 일부 태그로 그룹화하려면 다음 URL과 일치하는 /src/pages/[tag]/[page].astro 페이지를 생성하여 중첩된 페이지네이션을 사용합니다.

  • /red/1 (태그=red)
  • /red/2 (태그=red)
  • /blue/1 (태그=blue)
  • /green/1 (태그=green)

중첩된 페이지네이션은 getStaticPaths()에서 paginate() 결과 배열을 각 그룹마다 하나씩 반환하여 작동합니다.

다음 예시에서는 위에 나열된 URL을 작성하기 위해 중첩된 페이지네이션을 구현합니다.

src/pages/[tag]/[page].astro
---
export async function getStaticPaths({ paginate }) {
const allTags = ['red', 'blue', 'green'];
const allPosts = await Astro.glob('../../posts/*.md');
// 모든 태그에 대해 paginate() 결과를 반환합니다.
// `{params: {tag}}`를 `paginate()`에 전달했는지 확인합니다.
// Astro가 결과가 어떤 태그 그룹에 대한 것인지 알 수 있도록 합니다.
return allTags.flatMap((tag) => {
const filteredPosts = allPosts.filter((post) => post.frontmatter.tag === tag);
return paginate(filteredPosts, {
params: { tag },
pageSize: 10
});
});
}
const { page } = Astro.props;
const params = Astro.params;

페이지나 디렉터리 이름 앞에 밑줄 (_)을 붙여서 빌드되지 않도록 제외할 수 있습니다. _ 접두사가 붙은 파일은 라우터에서 인식되지 않으며 dist/ 디렉터리에 배치되지 않습니다.

이를 사용하여 페이지를 일시적으로 비활성화하고 테스트, 유틸리티 및 컴포넌트를 관련 페이지와 동일한 폴더에 넣을 수도 있습니다.

이 예시에서는 src/pages/index.astrosrc/pages/posts/post1.md 파일만 페이지 경로 및 HTML 파일로 빌드됩니다.

  • 디렉터리src/pages/
    • 디렉터리_hidden-directory/
      • page1.md
      • page2.md
    • _hidden-page.astro
    • index.astro
    • 디렉터리posts/
      • _SomeComponent.astro
      • _utils.js
      • post1.md