Astro.js frontmatter 필터가 안 먹힐 때 — PowerShell UTF-8 BOM 문제

Astro getCollection 필터를 추가했는데 전혀 작동 안 하는 문제. 원인은 PowerShell의 UTF-8 BOM이었다. 찾는 데 1시간 걸린 것 기록.

Astro.js frontmatter 필터가 안 먹힐 때 — PowerShell UTF-8 BOM 문제

상황

Astro.js 블로그에서 특정 콘텐츠를 목록에서 숨기려고 했습니다. 방법은 간단합니다. 마크다운 frontmatter에 hidden: true를 추가하고 getCollection 필터로 걸러내면 됩니다.

// picks/index.astro
const allPicks = await getCollection('picks', ({ data }) => !data.hidden);

그리고 PowerShell로 64개 파일에 hidden: true를 일괄 추가했습니다:

$content = Get-Content $file.FullName -Raw -Encoding UTF8
$content = $content -replace "(---`r?`n)", "`$1hidden: true`n"
Set-Content $file.FullName -Value $content -Encoding UTF8 -NoNewline

빌드해봤습니다. 64개가 그대로 다 보입니다.


첫 번째 시도 — 코드가 맞나 확인

getCollection 문법 확인, Astro content config에 hidden: z.boolean().optional() 추가, 캐시 클리어 후 재빌드.

rm -rf .astro dist
npm run build

여전히 64개 다 보입니다.


두 번째 시도 — 파일 확인

파일을 열어서 frontmatter를 눈으로 확인합니다:

---
hidden: true
title: "..."

딱 봐선 문제없어 보입니다. 근데 왜 필터가 안 먹히는 거지?


원인 발견 — BOM

파일 바이트를 직접 확인했습니다:

$bytes = [System.IO.File]::ReadAllBytes("파일경로")
"First 6 bytes: $($bytes[0..5] -join ',')"
# 출력: 239,187,191,45,45,45

239,187,191 = EF BB BF = UTF-8 BOM입니다.

파일이 --- 로 시작하는 게 아니라 [BOM]--- 로 시작하고 있었습니다.

Astro의 YAML 프론트매터 파서는 파일 시작에 BOM이 있으면 ---을 인식하지 못합니다. 그래서 data.hidden이 계속 undefined였고, !undefined === true라서 모든 파일이 필터를 통과했던 겁니다.


왜 BOM이 붙었나

PowerShell 5.1(Windows 기본)에서 -Encoding UTF8BOM 있는 UTF-8을 씁니다.

# BOM 포함 (PowerShell 5.1 기본)
Set-Content file.txt -Value $content -Encoding UTF8

# BOM 없음 — 이렇게 해야 함
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllBytes("file.txt", $utf8NoBom.GetBytes($content))

PowerShell 6+ (Core)는 -Encoding utf8NoBOM이 있지만, 5.1에는 없습니다.


해결 — BOM 제거 후 재저장

$utf8NoBom = New-Object System.Text.UTF8Encoding $false
$allFiles = Get-ChildItem $dir -Filter "*.md"

foreach ($file in $allFiles) {
    $bytes = [System.IO.File]::ReadAllBytes($file.FullName)
    
    # BOM 제거
    if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
        $bytes = $bytes[3..($bytes.Length-1)]
    }
    
    $content = [System.Text.Encoding]::UTF8.GetString($bytes)
    [System.IO.File]::WriteAllBytes($file.FullName, $utf8NoBom.GetBytes($content))
}

재빌드하니 필터가 정상 작동했습니다.


정리

증상원인
getCollection 필터가 무시됨frontmatter 파일에 BOM 있음
data.hidden이 항상 undefinedYAML 파서가 BOM을 만나면 frontmatter 파싱 포기
PowerShell Set-Content -Encoding UTF8로 저장한 파일BOM 자동 추가됨

핵심: PowerShell 5.1에서 파일 저장할 때는 Set-Content -Encoding UTF8 대신 [System.IO.File]::WriteAllBytes()로 BOM 없이 저장해야 합니다.

#Astro.js#PowerShell#BOM#인코딩#정적사이트