본문 바로가기

개발 공부/Angular

앵귤러 메타데이터 관리 (1)

메타데이터가 왜 중요한가?

SPA(싱글 페이지 앱)라고 해도 결국 브라우저 탭 제목, 검색엔진, SNS(카톡/슬랙/트위터 카드)에서 보이는 정보는 HTML <head>의 메타데이터에 의존합니다.

 

대표적인 것들

  • <title> — 브라우저 탭 제목, SEO 기본
  • <meta name="description"> — 검색 결과 요약 문구
  • <meta property="og:title">, <meta property="og:description">, <meta property="og:image"> — SNS 링크 미리보기 (Open Graph)

Next.js App Router의 generateMetadata()처럼 페이지별로 일관되게 메타데이터를 관리하고 싶다면, Angular에서는 다음 3가지를 조합해서 쓰게 됩니다.

  1. Title 서비스 (@angular/platform-browser)
  2. Meta 서비스 (@angular/platform-browser)
  3. Angular Router의 Route.title + TitleStrategy + ResolveFn

 


 

 

Angular에서 메타데이터를 다루는 기본 도구

Title 서비스

import { Title } from '@angular/platform-browser';

const title = inject(Title);
title.setTitle('홈 | MyApp');
  • 브라우저 탭에 보이는 <title>을 제어합니다.
  • 단순 문자열만 다룹니다.

Meta 서비스

import { Meta } from '@angular/platform-browser';

const meta = inject(Meta);

meta.updateTag({ name: 'description', content: '메타 설명입니다.' });
meta.updateTag({ property: 'og:title', content: 'OG 타이틀' });
meta.updateTag({ property: 'og:image', content: 'https://.../image.png' });
  • <meta> 태그를 추가/수정/삭제할 수 있습니다.
  • name / property 중 하나를 사용합니다.

이 두 가지를 매번 컴포넌트에서 직접 호출해도 되지만, 규모가 커지면 중복과 누락이 생기기 쉽습니다. 그래서 아래처럼 레이어를 나눠서 관리하는 게 좋습니다.


 

컴포넌트에서 바로 inject()로 제어

먼저, 기본 사용법부터 짚고 넘어가겠습니다.

Standalone 컴포넌트에서 메타데이터 설정

// home-page.component.ts
import { Component, OnInit, inject } from '@angular/core';
import { Title, Meta } from '@angular/platform-browser';

@Component({
  standalone: true,
  selector: 'app-home-page',
  template: `<h1>홈</h1>`,
})
export class HomePageComponent implements OnInit {
  private readonly title = inject(Title);
  private readonly meta = inject(Meta);

  ngOnInit(): void {
    this.title.setTitle('홈 | MyApp');

    this.meta.updateTag({
      name: 'description',
      content: 'MyApp 홈 화면입니다. 오늘의 추천 콘텐츠를 확인해 보세요.',
    });

    this.meta.updateTag({
      property: 'og:title',
      content: '홈 | MyApp',
    });

    this.meta.updateTag({
      property: 'og:description',
      content: 'MyApp 홈 화면입니다. 오늘의 추천 콘텐츠를 확인해 보세요.',
    });
  }
}

 

  • 작은 앱이나 정적인 페이지 몇 개만 있는 경우에는 이 정도만 해도 충분합니다.

하지만

  • 페이지가 많아질수록 ngOnInit 안이 메타 코드로 더러워지고,
  • 타이틀 접미사(| MyApp)를 바꾸고 싶을 때 전부 찾아서 수정해야 하고,
  • i18n(다국어)이 섞이면 더 복잡해집니다.

그래서 라우터 레벨에서 전역 전략 + 라우트 설정으로 제어하는 패턴으로 올라가 봅니다.


Route.title + TitleStrategy

Angular 14+부터 라우트에 title 속성을 정의하면, 네비게이션 후 자동으로 <title>을 업데이트해 주는 기능이 들어가 있습니다.

 

라우트에서 정적 타이틀 설정

// app.routes.ts
import { Routes } from '@angular/router';
import { HomePageComponent } from './pages/home-page.component';
import { PostListPageComponent } from './pages/post-list-page.component';

export const routes: Routes = [
  {
    path: '',
    component: HomePageComponent,
    title: '홈',
  },
  {
    path: 'posts',
    component: PostListPageComponent,
    title: '게시글 목록',
  },
];
  • 그리고 app.config.ts에서 라우터를 제공하면, 기본 TitleStrategy가 이 title을 사용해 <title>을 설정합니다.
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    // ... 다른 provider들
  ],
};
  • 이렇게만 해도 각 페이지마다 다른 <title>이 자동으로 적용됩니다.
  • 하지만 여기서도 아쉬운 점이 있죠.
    • 모든 라우트의 타이틀에 | MyApp 접미사를 붙이고 싶다거나
    • 라우트마다 기본 prefix/suffix 규칙을 통일하고 싶을 때

이때 쓰는 게 커스텀 TitleStrategy입니다.

커스텀 TitleStrategy

// app-title.strategy.ts
import { Injectable, inject } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { RouterStateSnapshot, TitleStrategy } from '@angular/router';

@Injectable({ providedIn: 'root' })
export class AppTitleStrategy extends TitleStrategy {
  private readonly title = inject(Title);
  private readonly APP_NAME = 'MyApp';

  override updateTitle(routerState: RouterStateSnapshot): void {
    // 라우트 설정의 title(문자열 또는 Resolver 결과)을 조합해서 title 문자열 생성
    const resolvedTitle = this.buildTitle(routerState);

    const fullTitle = resolvedTitle
      ? `${resolvedTitle} | ${this.APP_NAME}`
      : this.APP_NAME;

    this.title.setTitle(fullTitle);
  }
}
  • 그리고 app.config.ts에 전략을 등록합니다.
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter, TitleStrategy } from '@angular/router';
import { routes } from './app.routes';
import { AppTitleStrategy } from './app-title.strategy';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    { provide: TitleStrategy, useClass: AppTitleStrategy },
  ],
};

이제부터는 라우트에 순수한 페이지 타이틀만 적어주면:

// app.routes.ts
export const routes: Routes = [
  {
    path: '',
    component: HomePageComponent,
    title: '홈',
  },
  {
    path: 'posts',
    component: PostListPageComponent,
    title: '게시글 목록',
  },
];

실제 <title>은:

  • / → 홈 | MyApp
  • /posts → 게시글 목록 | MyApp

처럼 자동으로 만들어집니다.

'개발 공부 > Angular' 카테고리의 다른 글

Angular validationForm  (0) 2025.12.14
앵귤러 메타데이터 관리 (2)  (0) 2025.12.02
Angular inject()  (0) 2025.09.01
Signals vs RxJS  (0) 2025.08.23
Angular에서 signal을 써야 하는 이유  (1) 2025.08.15