Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.5.2
Comment on lines +17 to +20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/ci.yml | head -70

Repository: umsungjun/react-head-safe

Length of output: 1968


🌐 Web query:

pnpm latest version January 2026 release

💡 Result:

Latest pnpm (as of Jan 14, 2026) is v10.28.0 — released Jan 12, 2026. [1][2]

Sources:

  • pnpm release notes (10.28). [1]
  • Chocolatey package listing (shows v10.28.0 uploaded Jan 12, 2026). [2]

Update pnpm to a current version.

The workflow pins pnpm to version 10.5.2, but the latest stable release as of January 2026 is 10.28.0. Update to a recent version to ensure bug fixes and security patches are included.

This applies to both the test job (lines 17-20) and build job (lines 54-57).

🤖 Prompt for AI Agents
In @.github/workflows/ci.yml around lines 17 - 20, Update the pinned pnpm
version in both "Setup pnpm" steps to a current stable release: replace the
version value (currently 10.5.2) with 10.28.0 in the pnpm/action-setup@v4 step
used in the test job and the build job so both occurrences use the updated pnpm
version.


- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run tests
run: pnpm test

- name: Run tests with coverage
run: pnpm test:coverage

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/coverage-final.json
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

build:
runs-on: ubuntu-latest
needs: test

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.5.2

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build package
run: pnpm build

- name: Check for build artifacts
run: |
if [ ! -d "dist" ]; then
echo "Build failed: dist directory not found"
exit 1
fi
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ dist
.DS_Store
.env
.env.local

# Test coverage
coverage
.vitest
144 changes: 144 additions & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# react-head-safe

[English](README.md) | [한국어](README.ko.md)

중복 메타 태그를 방지하고 document head 요소를 안전하게 관리하는 CSR 전용 React head 매니저입니다.

## 왜 react-head-safe인가요?

React에서 document head 요소를 관리하기 위한 가볍고 CSR에 최적화된 대안입니다. 다음과 같은 요구사항이 있는 간단한 클라이언트 사이드 렌더링 애플리케이션에 완벽합니다:

- **명시적 중복 방지** - 새로운 태그를 추가하기 전에 항상 기존 메타 태그를 제거합니다
- **간단함** - 복잡한 설정 없이 props만 전달하는 단일 컴포넌트
- **성능** - 페인트 전 동기적 DOM 업데이트를 위해 `useLayoutEffect` 사용
- **타입 안전성** - TypeScript로 작성되어 완전한 타입 정의 제공

## 주요 기능

- ✅ **중복 태그 없음** - 새 태그를 만들기 전에 기존 메타 태그 제거
- ✅ **TypeScript 지원** - TypeScript로 완전한 타입 안전성 제공
- ✅ **경량** - React 외에 의존성 제로
- ✅ **CSR 최적화** - 동기적 DOM 업데이트를 위해 `useLayoutEffect` 사용
- ✅ **Open Graph 지원** - 소셜 미디어 메타 태그 기본 지원
- ✅ **간단한 API** - props만 전달하면 되는 복잡하지 않은 설정

## 설치

[![npm version](https://badge.fury.io/js/react-head-safe.svg)](https://www.npmjs.com/package/react-head-safe)

```bash
npm install react-head-safe
# 또는
yarn add react-head-safe
# 또는
pnpm add react-head-safe
```

## 사용법

```tsx
import { ReactHeadSafe } from 'react-head-safe';

function MyPage() {
return (
<>
<ReactHeadSafe
title="내 페이지 제목"
description="SEO를 위한 페이지 설명입니다."
keywords="react,seo,meta tags"
ogTitle="소셜 미디어용 페이지 제목"
ogDescription="소셜 미디어용 설명입니다."
ogImage="https://example.com/image.jpg"
/>
<div>페이지 콘텐츠...</div>
</>
);
}
```

## API

### ReactHeadSafeProps

| Prop | Type | Description |
| --------------- | -------- | -------------------------------------------------------- |
| `title` | `string` | `document.title`에 설정될 페이지 제목 |
| `description` | `string` | SEO를 위한 메타 설명 태그 콘텐츠 |
| `keywords` | `string` | SEO를 위한 메타 키워드 태그 콘텐츠 |
| `ogTitle` | `string` | 소셜 미디어 공유를 위한 Open Graph 제목 (og:title) |
| `ogDescription` | `string` | 소셜 미디어 공유를 위한 Open Graph 설명 (og:description) |
| `ogImage` | `string` | 소셜 미디어 공유를 위한 Open Graph 이미지 URL (og:image) |

## 언제 사용해야 하나요?

**다음과 같은 경우 react-head-safe를 사용하세요:**

- CSR 전용 애플리케이션을 구축하는 경우 (Create React App, Vite 등)
- 최소한의 설정으로 간단하고 가벼운 솔루션을 원하는 경우
- 중복 메타 태그 방지에 대한 명시적 제어가 필요한 경우
- 동기적 DOM 업데이트를 위해 `useLayoutEffect`를 선호하는 경우

**다음과 같은 경우 대안을 사용하세요:**

- SSR/SSG 지원이 필요한 경우 → `react-helmet-async`, Next.js `<Head>`, Remix `<Meta>` 사용
- 중첩 컴포넌트나 중복 제거 로직 같은 고급 기능이 필요한 경우
- head 관리 기능이 내장된 프레임워크를 이미 사용 중인 경우

## 왜 CSR 전용인가요?

이 라이브러리는 **클라이언트 사이드 렌더링(CSR)** 애플리케이션을 위해 특별히 설계되었습니다. 서버 사이드 렌더링(SSR) 지원이 필요하다면 다음을 고려하세요:

- SSR용 `react-helmet-async`
- Next.js 내장 `<Head>` 컴포넌트
- Remix `<Meta>` 컴포넌트

## 로컬 개발

예제 애플리케이션으로 로컬 변경사항을 테스트하려면:

```bash
pnpm run example
```

이 명령은 라이브러리의 로컬 버전을 사용하여 예제 프로젝트를 실행하므로, 게시하기 전에 수정한 내용을 테스트할 수 있습니다.

## 테스트

[![codecov](https://codecov.io/gh/umsungjun/react-head-safe/branch/main/graph/badge.svg)](https://codecov.io/gh/umsungjun/react-head-safe)

이 프로젝트는 단위 테스트를 위해 **Vitest**와 **React Testing Library**를 사용합니다.

### 테스트 실행

```bash
# 테스트 한 번 실행
pnpm test

# watch 모드로 테스트 실행
pnpm test:watch

# 커버리지와 함께 테스트 실행
pnpm test:coverage

# UI 모드로 테스트 실행
pnpm test:ui
```

### CI/CD

이 프로젝트는 지속적 통합을 위해 GitHub Actions를 사용합니다:

- ✅ **자동화된 테스트** - 모든 PR과 main 브랜치 push 시 테스트 실행
- ✅ **Node.js 20.x** - Node.js 20.x (LTS) 버전으로 테스트
- ✅ **빌드 검증** - 패키지가 올바르게 빌드되는지 확인
- ✅ **브랜치 보호** - main 브랜치에 머지하기 전에 테스트 통과 필수

PR이 main 브랜치에 머지되기 전에 모든 테스트를 통과해야 합니다.

## 라이선스

[MIT](LICENSE)

## 기여하기

기여를 환영합니다! Pull Request를 자유롭게 제출해주세요.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# react-head-safe

[English](README.md) | [한국어](README.ko.md)

A CSR-only React head manager that prevents duplicate meta tags and safely manages document head elements.

## Why react-head-safe?
Expand Down Expand Up @@ -98,6 +100,39 @@ To test your local changes with the example application:
pnpm run example
```

## Testing

[![codecov](https://codecov.io/gh/umsungjun/react-head-safe/branch/main/graph/badge.svg)](https://codecov.io/gh/umsungjun/react-head-safe)

This project uses **Vitest** and **React Testing Library** for unit testing.

### Running Tests

```bash
# Run tests once
pnpm test

# Run tests in watch mode
pnpm test:watch

# Run tests with coverage
pnpm test:coverage

# Run tests with UI
pnpm test:ui
```

### CI/CD

The project uses GitHub Actions for continuous integration:

- ✅ **Automated Testing** - Tests run on every PR and push to main
- ✅ **Node.js 20.x** - Tests against Node.js 20.x (LTS)
- ✅ **Build Verification** - Ensures the package builds correctly
- ✅ **Branch Protection** - Tests must pass before merging to main

All tests must pass before a PR can be merged to the main branch.

This command will run the example project using your local version of the library, allowing you to test any modifications you've made before publishing.
Comment on lines +134 to 136
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Documentation flow issue.

Line 136 ("This command will run the example project...") appears to be a continuation of the "Local Development" section (lines 95-101) but is now separated by the new Testing section. This creates confusion as the reader loses context about which command it refers to.

📝 Suggested fix

Move line 136 to directly follow line 101, before the Testing section:

 ```bash
 pnpm run example

+This command will run the example project using your local version of the library, allowing you to test any modifications you've made before publishing.
+

Testing

codecov
...
All tests must pass before a PR can be merged to the main branch.

-This command will run the example project using your local version of the library, allowing you to test any modifications you've made before publishing.

License

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

In @README.md around lines 134 - 136, The sentence "This command will run the
example project using your local version of the library, allowing you to test
any modifications you've made before publishing." is misplaced in the Testing
section and should be moved to the end of the Local Development section; cut
that sentence from its current location and insert it immediately after the
Local Development example command block (the pnpm run example snippet) so it
directly follows the code block and precedes the Testing header, ensuring the
explanatory line stays with the related command.


</details>

<!-- fingerprinting:phantom:poseidon:ocelot -->

<!-- This is an auto-generated comment by CodeRabbit -->


## License
Expand Down
15 changes: 13 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,29 @@
"build": "vite build",
"prepublishOnly": "pnpm run build",
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
"example": "cd examples/basic && pnpm install && pnpm dev"
"example": "cd examples/basic && pnpm install && pnpm dev",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"test:ui": "vitest --ui"
},
"peerDependencies": {
"react": ">=17"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1",
"@types/node": "^22.10.5",
"@types/react": "^19.2.7",
"@vitejs/plugin-react": "^5.1.2",
"@vitest/coverage-v8": "^4.0.17",
"happy-dom": "^20.1.0",
"jsdom": "^27.4.0",
"prettier": "^3.7.4",
"typescript": "^5.9.3",
"vite": "^6.0.7",
"vite-plugin-dts": "^4.4.2"
"vite-plugin-dts": "^4.4.2",
"vitest": "^4.0.17"
},
"packageManager": "pnpm@10.5.2",
"keywords": [
Expand Down
Loading