Skip to content

라우트 매칭 문법

대부분의 애플리케이션은 동적 라우트 매칭에서 본 것처럼 /about 같은 정적 라우트와 /users/:userId 같은 동적 라우트를 사용하겠지만, Vue Router는 그보다 훨씬 더 많은 기능을 제공합니다!

TIP

단순화를 위해 모든 라우트 레코드는 path 값에 집중할 수 있도록 component 속성을 생략합니다.

params 안의 사용자 정의 regex

:userId 같은 param을 정의할 때 내부적으로는 URL에서 params를 추출하기 위해 ([^/]+)라는 regex(/가 아닌 문자가 최소 한 개)를 사용합니다. 이는 param 내용에 따라 두 라우트를 구분해야 하는 경우가 아니라면 잘 동작합니다. /:orderId/:productName 두 라우트를 생각해 보면 둘 다 정확히 같은 URL에 매치되므로, 이를 구분할 방법이 필요합니다. 가장 쉬운 방법은 이를 구분해 주는 정적 섹션을 경로에 추가하는 것입니다:

js
const routes = [
  // /o/3549에 매치됩니다
  { path: '/o/:orderId' },
  // /p/books에 매치됩니다
  { path: '/p/:productName' },
]

하지만 어떤 시나리오에서는 /o/p 같은 정적 섹션을 추가하고 싶지 않을 수 있습니다. 대신 orderId는 항상 숫자이고 productName은 무엇이든 될 수 있으므로, 괄호 안에 param용 사용자 정의 regex를 지정할 수 있습니다:

js
const routes = [
  // /:orderId -> 숫자에만 매치됩니다
  { path: '/:orderId(\\d+)' },
  // /:productName -> 그 외 모든 것에 매치됩니다
  { path: '/:productName' },
]

이제 /25로 이동하면 /:orderId에 매치되고, 다른 어떤 값으로 이동하면 /:productName에 매치됩니다. 심지어 routes 배열의 순서도 중요하지 않습니다!

TIP

JavaScript 문자열 안에서 실제 백슬래시 문자를 전달하려면 \d\\d로 쓴 것처럼 백슬래시(\)를 이스케이프 해야 한다는 점에 유의하세요.

닫는 괄호 )는 사용자 정의 regex의 끝을 나타내는 데 사용되므로, regex 내부에서(예: 중첩 그룹) 이를 이스케이프해야 합니다:

js
const routes = [
  // regexp 안에 있는 그룹의 닫는 괄호가 이스케이프된 점에 주목하세요
  { path: '/:custom(something-(nested|other\\))' },
]

반복 가능한 params

/first/second/third처럼 여러 섹션이 있는 라우트를 매치해야 한다면, param을 *(0개 이상) 또는 +(1개 이상)로 표시해 반복 가능하게 만들어야 합니다:

js
const routes = [
  // /:chapters -> /one, /one/two, /one/two/three 등에 매치됩니다
  { path: '/:chapters+' },
  // /:chapters -> /, /one, /one/two, /one/two/three 등에 매치됩니다
  { path: '/:chapters*' },
]

이렇게 하면 문자열 대신 params 배열을 얻게 되며, 이름 있는 라우트를 사용할 때도 배열을 전달해야 합니다:

js
// given { path: '/:chapters*', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// /를 생성합니다
router.resolve({ name: 'chapters', params: { chapters: ['a', 'b'] } }).href
// /a/b를 생성합니다

// given { path: '/:chapters+', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// `chapters`가 비어 있으므로 Error를 throw합니다

이들은 닫는 괄호 뒤에 추가하여 사용자 정의 regex와 결합할 수도 있습니다:

js
const routes = [
  // 숫자에만 매치됩니다
  // /1, /1/2 등에 매치됩니다
  { path: '/:chapters(\\d+)+' },
  // /, /1, /1/2 등에 매치됩니다
  { path: '/:chapters(\\d+)*' },
]

sensitive 및 strict 라우트 옵션

기본적으로 모든 라우트는 대소문자를 구분하지 않으며, 끝 슬래시가 있든 없든 매치됩니다. 예를 들어 /users 라우트는 /users, /users/, 심지어 /Users/에도 매치됩니다. 이 동작은 strictsensitive 옵션으로 구성할 수 있으며, 라우터 수준과 라우트 수준 모두에서 설정할 수 있습니다:

js
const router = createRouter({
  history: createWebHistory(),
  routes: [
    // /users/posva에는 매치되지만 다음에는 매치되지 않습니다:
    // - strict: true 때문에 /users/posva/
    // - sensitive: true 때문에 /Users/posva
    { path: '/users/:id', sensitive: true },
    // /users, /Users, /users/42에는 매치되지만 /users/ 또는 /users/42/에는 매치되지 않습니다
    { path: '/users/:id?' },
  ],
  strict: true, // 모든 라우트에 적용됩니다
})

선택적 매개변수

? 수정자(0개 또는 1개)를 사용해 매개변수를 선택적으로 표시할 수도 있습니다:

js
const routes = [
  // /users와 /users/posva에 매치됩니다
  { path: '/users/:userId?' },
  // /users와 /users/42에 매치됩니다
  { path: '/users/:userId(\\d+)?' },
]

엄밀히 말하면 *도 매개변수를 선택적으로 표시하지만, ? 매개변수는 반복될 수 없습니다.

라우트 세그먼트에 선택적 매개변수 외에 다른 내용이 더 들어 있으면, 끝 슬래시가 없는 경로에는 매치되지 않습니다. 예:

  • /users/:uid?-:name? won't match /users, only /users/- or even /users/-/
  • /users/:uid(\\d+)?:name? won't match /users, only /users/, /users/2, /users/2/, etc

playground에서 매칭 문법을 직접 시험해 볼 수 있습니다

디버깅

왜 어떤 라우트가 매치되지 않는지 이해하거나 버그를 보고하기 위해, 라우트가 regex로 어떻게 변환되는지 깊이 살펴봐야 한다면 path ranker 도구를 사용할 수 있습니다. URL을 통해 라우트를 공유하는 것도 지원합니다.

느린 regex 피하기

사용자 정의 regex를 사용할 때는 느린 regex 패턴을 피해야 합니다. 예를 들어 .*는 어떤 문자와도 매치되며, 반복 수정자 * 또는 +와 결합되고 그 뒤에 다른 내용이 이어지면 심각한 성능 문제를 일으킬 수 있습니다:

ts
const routes = [
  // 탐욕적인 `.*` 뒤에 `*`와 정적 문자열이 이어지므로 매우 느린 regex가 만들어집니다
  { path: '/:pathMatch(.*)*/something-at-the-end' },
]

실제로는 이런 모든 것과 매치되는 params를 URL의 맨 끝에서만 사용하세요. 경로 중간에서 필요하다면 반복 가능하게 만들지 마세요:

ts
const routes = [
  // `.*`가 끝에 있으므로 괜찮습니다
  { path: '/:pathMatch(.*)/something-at-the-end' },
]

이 방식은 같은 라우트에 매치되지만 params 배열을 만들지 않으며 훨씬 빠릅니다.

모두를 위한 문서 한글화