- ์ ํ์ ๋์์ธ์ ๋ํ ๊ท์น
- ์๋น์ค UI์ ์ผ๊ด์ฑ์ ๋ถ์ฌํ๋ค.
- ์ฝ๋ ๋ฐ ๋์์ธ์ ์ ์ง๋ณด์๊ฐ ์ ๋ฆฌํด์ง๋ค.
- ๊ธฐํ์, ๋์์ด๋, ๊ฐ๋ฐ์ ๊ฐ ์ปค๋ฎค๋์ผ์ด์ ๋น์ฉ์ ์ ์ฝํ ์ ์๋ค.
- ์ ํ์ ๋์์ธ๊ณผ ๊ฐ๋ฐ์ ์๋ดํ๋ ๊ด๋ฒ์ํ ์ง์นจ, ํ์ค, ์ค์ฒ ์ฌํญ์ ๋ชจ์๋ ๊ฒ
- UI ์ปดํฌ๋ํธ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ฐ๋ฐํ๊ณ ๋ฌธ์ํํ ์ ์๋ ํ๊ฒฝ์ ์ ๊ณตํ๋ ๋๊ตฌ
- UI ์ปดํฌ๋ํธ์
story
๋ฅผ ๋ถ์ฌํ์ฌ ๋ ๋๋ง์ ํ ์คํธํ๋ค.story
: UI ์ปดํฌ๋ํธ์ ์ํ (์:disabled
,enabled
)
- ๋์์ธ ์์คํ
์ ๊ตฌ์ถํ๊ณ ์ ์งํ๋ ๋ฐ ์์ด ์ค์ํ ์ญํ ์ ํ๋ค.
- ๊ฐ๋ฐํ ์ปดํฌ๋ํธ๊ฐ ๋์์ธ ๊ฐ์ด๋์ ๋ง๋์ง ํ์ธํ ์ ์๋ค.
- ์ปดํฌ๋ํธ์ ๋ ์ด์์, ์์, ํ์ดํฌ๊ทธ๋ํผ ๋ฑ ๋ค์ํ ๋์์ธ ์์๋ฅผ ์ผ๊ด์ฑ ์๊ฒ ๊ด๋ฆฌํ ์ ์๋ค.
- ๋์์ธ ํ ํฐ, ์ปดํฌ๋ํธ, ํจํด ๋ฑ์ ๋ฌธ์ํํ์ฌ ํ ๋ด ๊ณต์ ๋ฐ ์ฌ์ฌ์ฉ์ ํธ๋ฆฌํ๊ฒ ํ๋ค.
- ์์ ์ปดํฌ๋ํธ๋ค์ ์์์ ํฐ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์์ ๋ UI๊ฐ ์ด๋ป๊ฒ ๋ณด์ผ์ง๋ฅผ ํ์ธํ ์ ์๋ค.
- ํ์๋ค ๊ฐ์ ์ปค๋ฎค๋์ผ์ด์ ์ ๊ฐํํ๋ฉฐ ๋์์ธ๊ณผ ์ฝ๋๋ฅผ ์ผ๊ด์ฑ ์๊ฒ ์ ์งํ๋๋ก ๋์์ค๋ค.
- ์ฌ์ฉ์๊ฐ ๋ด๊ฐ ๋ง๋ ์ปดํฌ๋ํธ๋ฅผ ๋ด๊ฐ ์๋ํ ๋๋ก ์ ์ฌ์ฉํ ์ ์๋์ง๋ฅผ ๋ฏธ๋ฆฌ ๋ณด๊ณ ์ ์ฉํ ์ ์๋ค.
- ํ์ฌ์์ ์๋ก์ด ํ๋ก์ ํธ๋ฅผ ๋ฐ์นญํ๋๋ผ๋ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋ ๋์์ธ ์์คํ ์ ๊ธฐ๋ฐ์ผ๋ก ์ผ๊ด๋ UI ์์คํ ํตํด Brand Identity๋ฅผ ๊ฐ์ ธ๊ฐ ์ ์๋ค.
- ์ฐ์ vite๋ก ํ๋ก์ ํธ๋ฅผ
init
ํฉ๋๋ค.
npm create vite@latest
- ์คํ ๋ฆฌ๋ถ์
init
ํ๋ค.
npx storybook@latest init
- vite์ ๊ด๋ จ๋ ์ถ๊ฐ ์ค์ ์ ์งํํ๋ค.
npm install @storybook/builder-vite --save-dev
- ์คํ ๋ฆฌ๋ถ ํด๋์
main.ts
ํ์ผ์core
์ค์ ์ ์ถ๊ฐํ๋ค.
// .storybook/main.ts
const config: StorybookConfig = {
// ...
core: {
builder: "@storybook/builder-vite",
},
};
- Tailwind๋ฅผ ์ค์นํ๋ค.
npm install -D tainwindcss postcss autoprefixer
npx tailwind init -p
tailwind.config.js
์์ ๋ฆฌ์กํธ ์ฝ๋ ์คํ์ผ์ด ๋ฐ์๋๋๋ก ์ค์ ํด์ค๋ค.
// tailwind.config.js
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
};
- tailwind๋ฅผ import ํด์ค๋ค.
/* index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
- ๋์์ธ ์์คํ ์ ๊ธฐ๋ณธ ์ค์ ์ ๋ฐ์ํ๋ค.
// tailwind.config.js
export default {
// ...
theme: {
colors: {
// ...
},
},
};
tailwind.config.js
์ ์ค์ ํ ๊ฒ๋ณด๋ค ์ธ๋ผ์ธ์ผ๋ก ์ง์ ์ค์ ํด์ฃผ๋ ๊ฒ์ด ์ฐ์ ๋๋ฏ๋ก ์คํ์ผ์ด ๊ณ ์ ๋ ์ฐ๋ ค๋ ํ์ง ์์๋ ๋๋ค.
- ๋ฐฉ๋ฌธ์์๊ฒ ์ฝํ
์ธ ๊ฐ ์ผ๋ง๋ ๋ถ์์ ํ๊ฒ ๋๊ปด์ง๋์ง๋ฅผ ์ธก์ ํ๋ ์ฌ์ฉ์ ๊ฒฝํ ์ธก์ ํญ๋ชฉ
- ํ์ด์ง์์ ๊ฐ์๊ธฐ ๋ ์ด์์์ ๋ณ๊ฒฝ์ด ๋ฐ์ํ๋ ๊ฒ์ ์ฌ์ฉ์์ ์ฃผ์๋ฅผ ์ฐ๋งํ๊ฒ ํ ์ ์๋ค.
- ์๋ชป๋ ํด๋ฆญ์ ์ ๋ํ ๊ฒฝ์ฐ ํผํด๋ฅผ ์ด๋ํ๊ฑฐ๋ ๋ถ๋ง์กฑ์ค๋ฌ์ด UX๋ฅผ ์ ๊ณตํ๊ฒ ๋๋ค.
- CLS ์ธก์ ์ ํตํด ์ฌ์ฉ์์๊ฒ ๋ฐ์ํ๋ ๋ ์ด์์ ์ด๋ ๋น๋๋ฅผ ํ์ ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
CLS ์ ์
- ์ผ์ ๊ธฐ๊ฐ ๋์ ๋ ์ด์์ ์ด๋์ด ์๋ ์ํ์์ ๋ฐ์ํ๋ ์์ํ์ง ์์ ๋ ์ด์์ ์ด๋์ ๋ํ ๋์ ๋ ์ ์
- ๋ทฐํฌํธ์์ ์ด๋ํ ์ฝํ ์ธ ์ ์๊ณผ ์ํฅ์ ๋ฐ์ ์์๊ฐ ์ด๋ํ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ์ฌ ์ฐ์ ๋๋ค.
- ์ข์ ์ฌ์ฉ์ ํ๊ฒฝ ์ ๊ณต์ ์ํด์๋ ์ฌ์ดํธ์ CLS ์ ์๊ฐ
0.1
๋ฏธ๋ง์ด์ด์ผ ํ๋ค.
-
errorMessage๋ฅผ
absolute
๋ก ๊ณ ์ ํด์ค๋ค. -
์ด๋, ์ฌ์ฌ์ฉ์ฑ์ ์ํด errorMessage ์์ฒด์
position
์ ๋ถ์ฌํ์ง ์์ผ๋ คdiv
ํ๊ทธ๋ฅผ ๊ฒ์ ์ถ๊ฐํ ๊ฒฝ์ฐ ๋ถํ์ํ ํ๊ทธ๊ฐ ํ๋ ๋ ์ถ๊ฐ๋๋ค.- ์ด๋ tree์ ๋ชจ๋ node๋ฅผ ํ๋ React์ Reconciliation ๊ณผ์ ์ ์์๋๋ ์๊ฐ์ ๋ ๊ธธ์ด์ง๊ฒ ํ๋ฏ๋ก ๋ ๋๋ง ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆด ์ ์๋ค.
-
CSS์ ์์ ์์ฑ์ ์ฌ์ฉํ์!
/*์ผ๋ฐ CSS ์คํ์ผ*/ .relative { > p { position: absolute; } } /*tailwindCSS ์คํ์ผ*/ @layer components { .relative > p { @apply absolute; } } /*ํน์ ์ปดํฌ๋ํธ์๋ง ์ ์ฉ๋๊ธธ ์ํ๋ ๊ฒฝ์ฐ*/ @layer components { .text-field > p { @apply absolute; } }
- ์ฝ๋๋ง ๋ณด๊ณ ์ปดํฌ๋ํธ์ ํํ๋ฅผ ์์ํ๊ธฐ ์ด๋ ต๋ค.
- PR์ ์์ฑํ ๋ ์ธ๋ถ ์ปดํฌ๋ํธ๋ฅผ ๋ชจ๋ ์์ธํ๊ฒ ์์ฑํ๊ธฐ ์ด๋ ต๋ค.
- ์ปดํฌ๋ํธ์ UI์ ํ ์คํธ๋ฅผ ์ง์ ์คํํ๊ธฐ ๋ฒ๊ฑฐ๋กญ๋ค.
- Chromatic์ด๋ ์คํ ๋ฆฌ๋ถ์์ ๋ง๋ ๋ฌด๋ฃ ๋ฐฐํฌ ์๋น์ค๋ก, ์คํ ๋ฆฌ๋ถ์ ๊ฐ๋จํ๊ฒ ๋ฐฐํฌํ ์ ์๊ฒ ํด์ค๋ค.
- ์ปดํฌ๋ํธ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ, ๋น๋ ๊ณผ์ ๋ฑ์ด ์คํ ๋ฆฌ๋ถ์ ์ต์ ํ๋์ด ๋ณด์ฌ์ง๋ค.
verify changes
๋ฅผ ํตํด ์ปดํฌ๋ํธ์ ๋ณ๊ฒฝ ์ฌํญ์ ํ์ธํ ์ ์๋ค.- Chromatic ํ์ด์ง์์ ๋๋ PR ์์ฒด์์ ์ปดํฌ๋ํธ์ ๋ํ ๋ฆฌ๋ทฐ๊ฐ ๊ฐ๋ฅํ๋ค.
Chromatic ์ค์นํ๊ธฐ
npm install --save-dev chromatic
Chromatic์ ์คํ ๋ฆฌ๋ถ ๋ฐฐํฌํ๊ธฐ
npx chromatic --project-token <your-project-token>
- ์ด ๊ณผ์ ์ด ์๋ค๋ฉด ์ปดํฌ๋ํธ์ UI์ ํ ์คํธ๋ฅผ ์ํด์๋ ์ฝ๋๋ฅผ Pull ๋ฐ๊ณ ์คํ ๋ฆฌ๋ถ์ ๋ก์ปฌ์์ ์คํํ์ฌ ํ์ธํด์ผ ํ๋ค.
Chromatic ํ ํฐ ์ค์ ํ๊ธฐ
- ํ ํฐ์ Chromatic์ Manage ํญ > Configure ํญ >
Setup Chromatic with this project token
์์ ํ์ธํ ์ ์๋ค.
Github Actions workflow ํ์ผ ์์ฑํ๊ธฐ
.github/workflows/chromatic.yml
์ ์๋์ ๊ฐ์ด ์์ฑํด์ฃผ์๋ค.- ํด๋๋ช ๋ง ๋์ผํ๋ค๋ฉด ํ์ผ๋ช ์ ์์๋ก ์ค์ ๊ฐ๋ฅํ๋ค.
# .github/workflows/chromatic.yml
name: "Chromatic"
# push ์ด๋ฒคํธ ๋ฐ์ ์
on: push
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
# ์ฌ์ฉํ๋ package manager์ ๋ง์ถฐ์ ์ค์ ํ๊ธฐ
run: npm ci
- name: Run Chromatic
uses: chromaui/action@latest
with:
# Github Secret์ ๋ฃ์ key ๊ฐ๊ณผ ๋์ผํด์ผ ํ๋ค.
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
- ์ ์์ ์ผ๋ก ์๋ํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
- ๋์งํธ ๋ถ์ผ์์ ์ ๋๋ฒ์ค ๋์์ธ(๋์ด๋ ๋ฅ๋ ฅ์ ์๊ด ์์ด ์ ํ์ ์ฌ์ฉํ ์ ์๋ค.)์ ๋ฉ์์ง๋ฅผ ๋ดํฌํ๋ ๊ฐ๋
- ์น์ฌ์ดํธ, ๋๊ตฌ, ๊ธฐ์ ์ ์ฅ์ ๋ฅผ ๊ฐ์ง ์ฌ์ฉ์๋ค๋ ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋๋ ๊ฒ
- ์ฌ๊ธฐ์์ ์ฅ์ ๋ ์ ์ฒด์ , ์ธ์ง์ ์ฅ์ ๋ฟ๋ง ์๋๋ผ ์น์ ์ ๊ทผํ๋ ๋ฐ ์ํฅ์ ์ฃผ๋ ์ผ์์ ์ธ ์ฅ์ ์ํ, ํ๊ฒฝ์ ์ ์ฝ์ ํฌํจํ๋ค.
The power of the Web is in its universality
- ์น ์ ๊ทผ์ฑ์ ์ค์ํ๋ ๊ฒ์ ์น์ ๊ธฐ๋ณธ ์ ์ ์ ์งํค๋ ๊ฒ์ด๋ฉฐ, ์ฅ์ ์ธ์ฐจ๋ณ๊ธ์ง๋ฒ๊ณผ ์ง๋ฅ ์ ๋ณดํ ๊ธฐ๋ณธ๋ฒ์ ์ํ ๋ฒ์ ์๋ฌด์ฌํญ์ด๊ธฐ๋ ํ๋ค.
- ์น ์ ๊ทผ์ฑ์ ์ค์ํ ๊ฒฝ์ฐ ์์ฝ, ์ฒญ๊ฐ์ฅ์ , ์ด๋์ฅ์ ๋ฑ ์ ์ฒด์ ๋ถํธํจ์ ๊ฐ์ง ์ฌ๋๋ค๋ ์น์ฌ์ดํธ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
- ํ์ด ๋ถ๋ฌ์ง๊ฑฐ๋ ์๊ฒฝ์ ์์ด๋ฒ๋ ค ์ผ์์ ๋ถํธํจ์ ๊ฒช๊ฑฐ๋ ๋ฐ์ ํ๋น์ด๋ ์๋ฆฌ๋ฅผ ๋ฃ๊ธฐ ํ๋ ์ํฉ์ ์ฒํ๋ ๋ฑ ํ๊ฒฝ์ ์ ์ฝ์ ๋ฐ๋ ์ฌ๋, ์ธ์ง์ /์ ์ฒด์ ๋ฅ๋ ฅ์ ์ ํ๋ฅผ ๊ฒช๋ ๋ ธ์ธ ๋ฑ ์ฅ์ ๋ฅผ ๊ฐ์ง ์๋ ์ฌ๋์๊ฒ๋ ๋์์ ์ค ์ ์๋ค.
๐Test Runner๋ฅผ ํ์ฉํ ์น ์ ๊ทผ์ฑ ํ ์คํธ
a11y addon ์ค์นํ๊ธฐ
npm install @storybook/addon-a11y --save-dev
.storybook/main.ts
์ addon ์ถ๊ฐํ๊ธฐ
addons: [
// Other Storybook addons
'@storybook/addon-a11y', //๐ The a11y addon goes here
],
Test Runner๋ฅผ ํ์ฉํ์ฌ ์น ์ ๊ทผ์ฑ ํ ์คํธ ์คํํ๊ธฐ
- playwright๋ฅผ ์ค์นํด์ค๋ค.
npx playwright install
- test runner addon์ ์ค์นํด์ค๋ค.
npm install @storybook/test-runner --save-dev
package.json
์ ์๋์ ๊ฐ์ดscripts
๋ฅผ ์ถ๊ฐํ๋ค.
{
"scripts": {
"test-storybook": "test-storybook"
}
}
- test-runner์ ์น ์ ๊ทผ์ฑ ํ ์คํธ๋ฅผ ์ค์ ํด์ค๋ค.
npm install axe-playwright --save-dev
import type { TestRunnerConfig } from "@storybook/test-runner";
import { injectAxe, checkA11y } from "axe-playwright";
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page) {
await checkA11y(page, "#storybook-root", {
detailedReport: true,
detailedReportOptions: {
html: true,
},
});
},
};
export default config;
- ์ ๋๋ก ์ ์ฉ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
Github Actions๋ก ์ ๊ทผ์ฑ ํ ์คํธ ์๋ํํ๊ธฐ
- ์๋์ ๊ฐ์ด workflow๋ฅผ ์ถ๊ฐํด์ค๋ค.
storybook-accessibility-test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
- name: Install dependencies
run: yarn
- name: Install Playwright
run: npx playwright install --with-deps
- name: Build Storybook
run: yarn build-storybook --quiet
- name: Serve Storybook and run tests
run: |
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
"npx http-server storybook-static --port 6006 --silent" \
"npx wait-on tcp:127.0.0.1:6006 && yarn test-storybook"
"npx wait-on tcp:127.0.0.1:6006 && yarn test-storybook"
๋ถ๋ถ์์ IP ์ฃผ์์ธ127.0.0.1
์ ๋ช ์ํด์ฃผ์ง ์์ผ๋ฉด CI ๊ณผ์ ์์ Storybook Server ๋ถ๋ถ์ด ์ ๋๋ก ๊ตฌ๋๋์ง ์๊ณ ๋ฌดํํ๊ฒ ๋ก๋ฉ๋๋ timeout ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฏ๋ก ์ฃผ์ํ์!
๐ฅ ์คํ ๋ฆฌ๋ถ์ ์ฌ์ฉํ ์ฌ์ฉ์ ์ํธ์์ฉ ํ ์คํธ
- ํ์ด์ง์ ๊ฐ์ด ๋ ๋ณต์กํ UI๋ฅผ ๊ตฌ์ถํ๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฑ UI ๋ ๋๋ง ์ด์์ ์ญํ ์ ๋งก๊ฒ ๋๋ค.
- Jest๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋ ํ ์คํธ๋ฅผ ์งํํ ์๋ ์์ง๋ง, ์คํ ๋ฆฌ๋ถ์ ์ฌ์ฉํด์๋ ์ปดํฌ๋ํธ ๋จ์์ ํ ์คํธ๊ฐ ๊ฐ๋ฅํ๋ค.
- API ํธ์ถ ๋ก์ง์ Cypress ๋ฑ์ ํ์ฉํ e2e ํ ์คํธ์์ ์งํํ๋ค๋ฉด, ์ปดํฌ๋ํธ์ ๋ํ ํ ์คํธ๋ ์คํ ๋ฆฌ๋ถ์ ์ฌ์ฉํ์ฌ ์งํํ๋ ๊ฒ๋ ํธ๋ฆฌํด ๋ณด์ธ๋ค.
Interaction Test ๊ด๋ จ addon ์ถ๊ฐํ๊ธฐ
npm install @storybook/test @storybook/addon-interactions --save-dev
.storybook/main.ts
์ addon ์ค์ ์ถ๊ฐํ๊ธฐ
addons: [
// Other Storybook addons
'@storybook/addon-interactions',
],
- ๋ค์ ํ์ผ๊ณผ ๊ฐ์ด ํ ์คํธ ๋ก์ง์ ์์ฑํด๋ณด๋ฉด ์๋์ ๊ฐ์ด ํ ์คํธ๊ฐ ์ ์์ ์ผ๋ก ์ ์ฉ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.