개발 환경 구성하기
이번 글에서는 본격적으로 개발에 들어가기 전에 코드 품질 도구 설정, 스타일링 인프라 구축, 다국어 환경 구성 등 개발 환경을 준비하는 과정을 다뤄보겠습니다.
코드 스타일과 품질을 위한 도구
서로 다른 환경에서도 일관된 코드 스타일을 유지할 수 있도록 .editorconfig
과 eslint
를 사용하는 것을 추천합니다. 물론 이 섹션을 생략하고 넘어가도 블로그를 개발하는 것에 지장은 없지만, Nuxt.js v2에서의 eslint 모듈에 질려버린 분이라면 그때와는 달리 이제는 개발을 방해하지 않는 수준으로 동작하기 때문에 사용하는 것을 권장합니다.
.editorconfig
.editorconfig
는 들여쓰기 스타일(스페이스 vs. 탭), 들여쓰기 크기, 파일 끝 공백 제거 여부 등 IDE 설정을 통일하는 데 유용합니다. 프로젝트 최상위 디렉토리에 파일을 생성하여 다음과 같이 설정할 수 있습니다.
root = true
[*]
indent_size = 2
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
Eslint
원래는 코드 품질을 보장하는 린터(Linter)와 스타일을 보장하는 포메터(Formatter)의 역할을 수행하는 라이브러리 였으나, 유지 관리 비용 문제로 인해서 포메터는 Stylistic이라는 별도의 프로젝트로 분리하고 린터의 역할만 수행합니다. 이로 인해 Eslint와 코드 포메터를 연동할 때 더 이상 복잡하지 않게 되었습니다.
Eslint를 직접 설치하면 린팅 룰까지 전부 직접 구성해줘야하기 때문에, 이를 자동화 할 수 있는 Nuxt Eslint 모듈 모듈을 설치하겠습니다. 모듈을 설치하고 나면 flat config 형태로 설정을 할 수 있는 eslint.config.js
파일이 자동으로 생성되며, 여기에 원하는 설정을 구현하시면 됩니다. 전 기본 설정을 사용하도록 하겠습니다.
ESLint는 코드 품질을 보장하는 린터(Linter) 역할을 합니다. 이전에는 코드 스타일을 포맷팅하는 기능도 제공했으나, 유지 관리 비용 문제로 이 기능은 Stylistic 프로젝트로 분리되었습니다. 이로 인해 현재 ESLint는 린팅에만 집중하며, 포매터는 별도로 설정하는 것이 권장됩니다.
코드 린팅 설정을 간단히 하기 위해 Nuxt Eslint 모듈을 사용하겠습니다. 이 모듈을 설치하면, eslint.config.js
파일이 자동으로 생성되며, 여기서 flat config 형식으로 린팅 규칙을 설정할 수 있습니다. 기본 설정만으로도 충분히 활용할 수 있습니다.
nuxt module add eslint
저는 과거에 코드 포매터로 Prettier를 사용했지만, Why I don't use Prettier라는 글을 읽고 나서 Stylistic을 대신 사용하고 있습니다. Nuxt ESLint 모듈 덕분에 간단한 설정만 추가하면 Stylistic을 함께 사용할 수 있습니다.
export default defineNuxtConfig({
modules: [
'@nuxt/eslint',
],
devtools: { enabled: true },
compatibilityDate: '2024-11-01',
eslint: {
config: {
stylistic: true,
},
},
})
스타일링 인프라 구축
스타일링 인프라는 CSS를 효율적으로 관리하고, 일관된 디자인 시스템을 구축하기 위한 기본 설정 작업을 의미합니다. 이번 프로젝트에서는 스타일링 인프라 구축 작업으로 Tailwind CSS, 다크 모드와 같은 테마 환경 설정, 그리고 프로젝트 전체에 적용될 글로벌 CSS 규칙을 정의해 보겠습니다.
Tailwind CSS
CSS를 직접 다루는 작업은 복잡하고 번거로울 수 있으며, SCSS나 LESS 같은 CSS 프리프로세서를 사용하면 네이밍 작업에 많은 시간을 소모하거나, 셀렉터 중첩으로 인해 스타일 충돌이 발생할 가능성이 있습니다. 그래서 저는 이 문제로부터 자유로운 아토믹 CSS 방식을 선호하며, 그중에서도 오랜 기간 검증된 도구인 Tailwind CSS를 선택하곘습니다. 직접 설치하면서 설정할 필요 없이 Nuxt Tailwind CSS 모듈을 설치해 보겠습니다.
nuxt module add tailwindcss
모듈을 설치 후 Tailwind CSS 설정 파일을 생성하지 않아도 nuxt.config.ts
에 관련 설정이 가능합니다. 그러나 이번 프로젝트는 Tailwind CSS 설정이 많기 때문에, 별도의 설정 파일을 생성하도록 하겠습니다. 저는 TS 형식으로 생성하겠습니다.
bunx tailwindcss init --ts
프로젝트에서 기본 색상은 정체성을 나타내기도 하기 때문에 쉽게 바뀔 일이 없지만, 아직 개발 단계일 경우에는 자주 바뀌기도 합니다. 저는 이런 경우를 대비해, primary color 속성을 만들어 기본 색상을 언제든지 쉽게 바꿀 수 있도록 설정합니다. 특히 외주 작업을 할 시에 클라이언트 요청에 따라 바꾸기 용이합니다.
import type { Config } from 'tailwindcss'
import colors from 'tailwindcss/colors'
export default {
content: [],
theme: {
extend: {
colors: {
primary: colors.sky,
},
},
},
plugins: [],
} satisfies Config
tailwind-merge
Tailwind CSS는 사용하기 편리하지만, 상태에 따라 스타일을 동적으로 바꾸기가 어렵다는 단점이 있습니다. 이를 해결하기 위해 tailwind-merge라는 라이브러리를 사용합니다. 이 라이브러리는 Tailwind CSS 클래스의 우선순위 문제를 해결해줍니다.
bun i tailwind-merge
색상 테마
밝은 테마와 어두운 테마 간의 전환 기능은 Nuxt Color Mode 모듈을 사용해서 간단히 구현할 수 있습니다.
nuxt module add color-mode
지금은 환경만 구성하고 실제 구현은 다음 글에서 진행하도록 하겠습니다.
전역 CSS
이제 프로젝트 전체에 걸쳐 사용될 전역 CSS를 작성해 보겠습니다. SCSS나 LESS가 필요할 정도의 작업을 하지 않기 떄문에 Post CSS로 작성하도록 하겠습니다.
body {
@apply antialiased text-slate-600 dark:text-slate-300 bg-white dark:bg-slate-900;
}
.dark-mode {
color-scheme: dark
}
::-moz-selection {
@apply bg-primary-500/40
}
::selection {
@apply bg-primary-500/40
}
- 1-3행 : 폰트에 안티얼라이싱을 적용하고, 밝은 테마와 어두운 테마에서의 기본 폰트 색상과 배경 색을 지정합니다.
- 5-7행 : 어두운 테마 활성화 시 색상표를 변경해 브라우저 스크롤바 색상도 어두운 테마에 맞게 설정합니다.
- 9-15행 : 사용자에 의해 하이라이트된, 텍스트 부분에 대한 스타일을 지정합니다.
작성한 CSS 파일은 Nuxt의 nuxt.config.ts
에 등록해 전역으로 적용합니다.
export default defineNuxtConfig({
modules: [
'@nuxt/eslint',
'@nuxtjs/i18n',
'@nuxtjs/tailwindcss',
'@nuxtjs/color-mode',
],
devtools: { enabled: true },
css: ['assets/css/main.pcss'],
compatibilityDate: '2024-11-01',
eslint: {
config: {
stylistic: true,
},
},
})
아이콘
헤더나 푸터처럼 제한된 공간에서는 아이콘을 활용하면 버튼의 역할을 쉽게 이해할 수 있고, 디자인의 일관성도 유지할 수 있습니다. 이를 위해 Nuxt Icon 모듈을 설치하여 다양한 아이콘을 편리하게 사용할 수 있는 환경을 구축해보겠습니다.
nuxt module add icon
저는 20x20 크기의 아이콘을 자주 사용해서 기본 크기로 20을 지정하도록 하겠습니다.
export default defineNuxtConfig({
modules: [
'@nuxt/eslint',
'@nuxtjs/i18n',
'@nuxtjs/tailwindcss',
'@nuxtjs/color-mode',
'@nuxt/icon',
],
devtools: { enabled: true },
css: ['assets/css/main.pcss'],
compatibilityDate: '2024-11-01',
eslint: {
config: {
stylistic: true,
},
},
icon: {
size: '20',
},
})
원하시는 아이콘 패키지를 설치해주시면 되는데, 저는 Phosphor 아이콘 세트가 범용성이 가장 좋다고 생각해 사용하겠습니다.
bun i -D @iconify-json/ph
다국어 환경 구축
다국어로 블로그 콘텐츠를 제공하기 위해서는 라우팅 설정, 메시지 파일 관리, SEO 설정 등 다양한 작업이 필요합니다. 이번 섹션에서는 i18n 모듈을 활용해 다국어 환경을 손쉽게 구성하고, 방문자의 브라우저 언어를 기반으로 자동 리다이렉트를 설정하는 방법 등을 살펴보겠습니다.
i18n 모듈
Nuxt i18n 모듈을 사용하면 간편하게 다국어 환경을 구성할 수 있으며, 브라우저 감지를 통해 사용자가 선호하는 언어로 페이지를 자동 전환할 수도 있습니다.
nuxt module add i18n
모듈 설치 후에 nuxt.config.ts
에 다음과 같이 설정을 합니다.
export default defineNuxtConfig({
modules: [
'@nuxt/eslint',
'@nuxtjs/i18n',
'@nuxtjs/tailwindcss',
'@nuxtjs/color-mode',
],
devtools: { enabled: true },
css: ['assets/css/main.pcss'],
compatibilityDate: '2024-11-01',
eslint: {
config: {
stylistic: true,
},
},
icon: {
size: '20',
},
i18n: {
baseUrl: 'YOUR SITE',
locales: [
{ code: 'ko', name: '한국어', file: 'ko.yaml', language: 'ko-KR' },
{ code: 'en', name: 'English', file: 'en.yaml', language: 'en-US' },
],
strategy: 'prefix_except_default',
defaultLocale: 'en',
detectBrowserLanguage: {
alwaysRedirect: true,
fallbackLocale: 'en',
},
vueI18n: './i18n/i18n.config.ts',
},
})
설정 주요 항목
- baseUrl : 사이트의 기본 URL을 설정합니다. SEO 최적화를 위해 필수 항목입니다.
- locales : 제공할 언어와 관련된 정보를 정의합니다.
language
속성은 표준 형식(ko-KR
,en-US
)을 따라야 합니다. - defaultLocale : 기본 언어를 지정하며, 설정되지 않은 언어로 접근 시 사용할 언어를 지정합니다.
- strategy : 로케일에 따른 URL 생성 전략을 정의합니다.
prefix except default
전략의 경우, URL에 로케일이 접두사로 붙고 기본 언어에는 접두사가 붙지 않습니다.- 기본 언어(영어): https://besfir-blog.pages.dev/
- 한국어: https://besfir-blog.pages.dev/ko/
- detectBrowserLanguage : 브라우저 언어를 감지하여 적절한 언어 페이지로 리다이렉트합니다. 최상위 페이지에서 작동하도록 기본 설정되어 있습니다.
- vueI18n : Vue i18n 설정 파일 경로를 지정합니다. Nuxt i18n은 내부적으로 Vue i18n을 사용하기 때문에, 옵션을 똑같이 사용할 수 있습니다.
더 자세한 정보는 i18n 모듈의 옵션 문서에서 확인할 수 있습니다.
날짜 국제화
개발 분야 특성상 정보의 신선도가 중요하기 때문에 작성일자나 수정일자는 반드시 표기합니다. Vue i18n에서는 날짜/시간 포멧팅을 위한 헬퍼 함수인 $d
함수와 datetimeFormats
옵션을 통해서 로케일별 형식으로 날짜를 출력할 수 있습니다. 전역적으로 이 옵션을 적용하려면 defineI18nConfig
컴포저블을 이용해서 Vue i18n에 전달되는 구성을 정의할 수 있습니다.
export default defineI18nConfig(() => ({
datetimeFormats: {
ko: {
short: {
year: 'numeric', month: 'short', day: 'numeric',
},
long: {
year: 'numeric',
month: 'short',
day: 'numeric',
weekday: 'short',
hour: 'numeric',
minute: 'numeric',
hour12: true,
},
},
en: {
short: {
year: 'numeric', month: 'short', day: 'numeric',
},
long: {
year: 'numeric',
month: 'short',
day: 'numeric',
weekday: 'short',
hour: 'numeric',
minute: 'numeric',
},
},
},
}))
locale 파일 생성
nuxt.config.ts
의 i18n
> locales
속성에 설정한 로케일 파일이 존재하지 않으면 오류가 발생합니다. 이를 방지하기 위해 더미 데이터를 포함한 파일을 생성해 보겠습니다.
hello: 안녕하세요.
SEO 기초 작업
다국어 콘텐츠를 제공할 때는 각 언어에 맞춘 SEO 최적화 작업이 필수적입니다. i18n 모듈에서 제공하는 SEO 가이드를 참고하여 설정을 추가합니다. 저는 layout 컴포넌트를 사용하지 않고 app.vue
에 직접 설정을 적용했습니다.
<script setup lang="ts">
const head = useLocaleHead()
</script>
<template>
<Html
:lang="head.htmlAttrs?.lang"
:dir="head.htmlAttrs?.dir"
>
<Head>
<template
v-for="link in head.link"
:key="link.id"
>
<Link
:id="link.id"
:rel="link.rel"
:href="link.href"
:hreflang="link.hreflang"
/>
</template>
<template
v-for="meta in head.meta"
:key="meta.id"
>
<Meta
:id="meta.id"
:property="meta.property"
:content="meta.content"
/>
</template>
</Head>
<Body>
<nuxt-page />
</Body>
</Html>
</template>
위 코드는 전역 설정을 위한 기본 작업이며, 각 페이지에 대한 SEO는 해당 페이지 컴포넌트마다 추가로 설정할 예정입니다.