1. MOCKING TOOL๋ก ์์ฐ์ฑ ์ฑ๊ธฐ๊ธฐ
๋ชจํน(Mocking)์ด๋ ๋จ์ ํ ์คํธ ์์ฑํ ๋, ํด๋น ์ฝ๋๊ฐ ์์กดํ๋ ๋ถ๋ถ์ ๊ฐ์ง(mock)๋ก ๋์ฒดํ๋ ๊ธฐ๋ฒ์ ๋๋ค.
๊ฐ๋ฐ์ ์งํํ ๋ ๋ฐฑ์๋์์ API๊ฐ ์์ฑ๋์ง ์์ ๋์ฒํ๋ ์ ์ด ์์์ ๊ฒ์ ๋๋ค.
ํน์ ์ํฉ์ ๊ฐ๋ฐ๋์ง ์์ ๋ถ๋ถ์ ์์กดํ์ฌ ๊ฐ๋ฐ์ ์งํํ๊ฒ ๋๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๋ฅผ ์ผ๊ธฐํ ์ ์์ต๋๋ค.
- ๊ฐ๋ฐ๋์ง ์์ ๋ชจ๋์ ์์กดํ๋ฉด ํ ์คํ ์ด ์ด๋ ค์
- ๋ค๋ฅธ ๋ชจ๋์ ์ํด ํ ์คํธ ๊ฒฐ๊ณผ๊ฐ ๋ฐ๋์์๊ณ , ํ ์คํธ ์คํ ์๋๊ฐ ๋จ์ด์ง
- ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์ปค์ ธ์ ํ ์คํธ ์ผ์ดํฌ๊ฐ ๋ง์์ง ๊ฒฝ์ฐ ํฐ ์ด์๊ฐ ์ผ๊ธฐ๋ ์ ์์
์ด๋ฌํ ์ํฉ์์ ์ค์ ๋ชจ๋์ ๋ชจ๋ฐฉํ ๊ฐ์ง ๋ชจ๋์ ์์ฑํ๋ mocking ์ด ํ์ํ๊ฒ ๋๋ฉฐ, ์ค์ ๋ก ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์๋ mocking ํ๋ ํ์๊ฐ ๋น ๋ฅธ ๊ฐ๋ฐ๊ณผ ์์ ์ฑ์ ๋์์ ์ค ์ ์์ต๋๋ค.
ํ๋ก ํธ์๋์์ ๋ฐฑ์๋ ๋ชจํน์ด ํ์ํ ์ํฉ์ ๋ค์ํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๋ฐฑ์๋ API๊ฐ ์์ง ๊ฐ๋ฐ ์ค์ด๊ฑฐ๋, ์ํ๋ ํํ์ ๋ฐ์ดํฐ๋ ์๋ต์ ํ ์คํธํด์ผ ํ ๋, ๋๋ ์๋ฒ ์๋ฌ ์ํฉ์ ํ ์คํธํ๊ณ ์ถ์ ๋ ๋ฑ์ด ์์ต๋๋ค.
์ด ์ํฉ์์์ ์๋ฃจ์ ์ ๋ํ์ ์ผ๋ก ์ธ๊ฐ์ง๋ก ๋๋ ๋ณผ ์ ์๋๋ฐ,
- ๋ฐฑ์๋ ์์ ์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ๋ด๋ถ ๋ก์ง์ ์ง์ Mocking ํ๋ค. (์ฐธ๊ณ : publicย folder์ย .jsonย ํ์ผ ๋ฑ์ ์ด์ฉํ์ฌ mocking )
- ํ์ดํฌ API๋ฅผ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค.
ํ์ค์ ์ผ๋ก ์๊ฐ์ด ๋ง๋ค๋ฉด 1๋ฒ์ ์งํฅํ๊ฒ ์ง๋ง, ์๊ฐ์ด ๋ถ์กฑํ๊ฑฐ๋ ๋ฆฌ์์ค๊ฐ ๋ถ์กฑํ ๊ฒฝ์ฐ์๋ 3๋ฒ์ ์ ํํ๊ฒ ๋ฉ๋๋ค.
์ค์ ๋ก ์ฉ์ฉ๋ฐ์ฌ ํ๋ก์ ํธ์์๋ Google API ํ ๋น๋ ๋ถ์กฑ์ผ๋ก ์ธํด ๊ฐ๋ฐ ํ๊ฒฝ ํ ์คํธ๋ฅผ ์ํด 3๋ฒ ๋ฐฉ๋ฒ์ ์ฑํํ์ต๋๋ค.
๋ฐ๋ผ์ ์ด์ ๊ด๋ จํ์ฌ ์ฃผ๋ก ์ฌ์ฉ๋๋ ํด๋ค์ ์๊ฐํฉ๋๋ค.
Json Placeholder
JSONPlaceholder - Free Fake REST API
Json Placeholder๋ ํ๋กํ ํ์ ๋๋ ๊ฐ๋ฐ ํ ์คํธ๋ฅผ ์ํ ํ์ดํฌ JSON API๋ฅผ ์ ๊ณตํฉ๋๋ค.
6๊ฐ ์ ํ์ ๋ฆฌ์์ค๋ฅผ ์ ๊ณตํ๋ฉฐ, CRUD ํ ์คํธ๋ฅผ ์ํ ๋ชจ๋ HTTP ๋ฉ์๋๋ฅผ ์ง์ํฉ๋๋ค.
GET, POST, PUT, PATCH, DELETE ๋ฉ์๋๋ฅผ ๋ชจ๋ ํ ์คํธ ํ ์ ์์ผ๋ฉฐ ๊ฒ์๋ฌผ, ์ฌ์ง ๋ฑ๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๋ค๋ ๋ค๋ฃฐ์ ์๊ฒ ๋์ด์์ต๋๋ค.
๊ฐ๋ตํ ์ฌ์ฉ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
// ์์ฒญ ์์
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => console.log(json));
Json Placeholder๋ฅผ ์ด์ฉํ๋ฉด ๋น ๋ฅธ ์๋๋ก ํ ์คํธํ ์ ์์ง๋ง, ์๋ต๊ฐ์ ์ปค์คํ ํ๋ ๊ฒ์ด ์ด๋ ค์ด ๋จ์ ์ด ์์ต๋๋ค.
MSW(Mock Service Worker)
MSW(Mock Service Worker)๋ Service Worker๋ฅผ ์ด์ฉํด ์๋ฒ๋ฅผ ํฅํ ์ค์ ๋คํธ์ํฌ ์์ฒญ์ ๊ฐ๋ก์ฑ์(intercept) ๋ชจ์ ์๋ต(Mocked response)๋ฅผ ๋ณด๋ด์ฃผ๋ API Mocking ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ์ค์ API๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ์ ์ฌํ๊ฒ ๋คํธ์ํฌ ์์ค์์ Mockingํ ์ ์์ต๋๋ค.
์ฌ์ฉ ์์๋ก POST ๋ฉ์๋์ /login ์์ฒญ์ ๋ง๋ค์ด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด API๋ฅผ ์ง์ ์ ์ํ ์ ์์ต๋๋ค.
/ src/mocks.js
import { setupWorker, rest } from 'msw'
const worker = setupWorker(
rest.post('/login', (req, res, ctx) => {
const isAuthenticated = sessionStorage.getItem('username')
if (!isAuthenticated) {
return res(
ctx.status(403),
ctx.json({
errorMessage: 'Not authenticated',
}),
)
}
return res(
ctx.json({firstName: 'John'}),
)
}),
)
// Register the Service Worker and enable the mocking
worker.start()
์ด๋ฐ์์ผ๋ก ์ํ ์ฝ๋์ ์๋ฌ ๋ฉ์์ง, ๋ฐํ ๊ฐ๋ค์ ์ปค์คํ ํ ์ ์์ผ๋ฉฐ ์ฌ๋ฌ ์ต์ ๋ค์ ์ธ๋ถ์ ์ผ๋ก ์ ์ฉํ ์ ์๋ค. (์ค์ API ์ฒ๋ผ ์ ๋ง ๋ค์ํ๊ฒ ์ปค์คํ ํ ์ ์๋ค)
ํ์ง๋ง ์ค์ ๋น์ฉ์ด ๋น๊ต์ ๋ง์ด ๋ค๊ณ , ๊ฐ๋จํ ์๋ต ํ ์คํธ๋ฅผ ์ํด์๋ ๋ค์ ๋ฒ๊ฑฐ๋ก์ธ ์ ์์ต๋๋ค.
conclusion
- FE ํ๊ฒฝ์ ๋น ๋ฅธ ๊ฐ๋ฐ์ ์ํ๋ค๋ฉด ๋ฐฑ์๋ ๋ชจํน์ด ํ์ํ๋ค.
- Json Placeholder๋ ๊ฐ๋จํ ์๋ต ํ ์คํธ์ ์ ํฉํ๋ฉฐ, MSW๋ ๋์ฑ ๋ณต์กํ ์ํฉ์์ ์ปค์คํฐ๋ง์ด์ง์ด ๊ฐ๋ฅํ๋ค.
reference
https://tech.kakao.com/2021/09/29/mocking-fe/
https://developer.mozilla.org/ko/docs/Web/API/Service_Worker_API
https://www.daleseo.com/mock-service-worker/#google_vignette
--
2. ๋ก๋ฉ ์๊ฐ์ ๋ฐ๋ฅธ ๋ค๋ฅธ ์ฌ์ฉ์ ๊ฒฝํ ์ฒ๋ฆฌ
ํ๋ก๊ทธ๋์ค ๋ฐ๋ ๋ก๋ฉ ์คํผ๋์ ๊ฐ์ UI ์์๋ ์ฌ์ฉ์๊ฐ ํ์ฌ ์์ ์ํ๋ฅผ ํ์ ํ๊ณ ๋ถํ์ค์ฑ์ ์ค์ฌ์ฃผ์ด ํ๋ก์ธ์ค๋ฅผ ๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋๋ก ๋์์ค๋๋ค. ์ด๋ก์จ ์ฌ์ฉ์๋ ๋์ฑ ๋ง์กฑ์ค๋ฌ์ด ๊ฒฝํ์ ํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ ํฌ ์๋น์ค์์๋ ๋ฐ์ดํฐ Fetching ์ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด Suspense๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ํ์ง๋ง ์ด๋ฌํ ๋ฐฉ๋ฒ์ด ์ค์ ๋ก ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๊ณ ์๋์ง ์๋ฌธ์ ๋๋ค.
##Progress Indicator ์ ๊ดํ ๋ฆฌ์์น
์ธ๊ณ์ ์ธ UX ์ฐ๊ตฌ์ ๋์จ ๋๋จผ์ ์ง์นจ์ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- 1์ด ์ด์ ๊ฑธ๋ฆฌ๋ ์์ ์๋ Progress Indicator๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์์ ์ด 1์ด ๋ฏธ๋ง์ ์๋ฃ๋๋ ๊ฒฝ์ฐ ๋ฐ๋ณต๋๋ ์ ๋๋ฉ์ด์ ์ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค.
- ๋ก๋ฉ ์คํผ๋์ ๊ฐ์ ์์๋ 2~9์ด์ ์ง์ฐ ์์๋ง ์ฌ์ฉํฉ๋๋ค.
- ์๋ฃ์จ ์ ๋๋ฉ์ด์ ์ 10์ด ์ด์ ์์๋๋ ์์ ์ ์ฌ์ฉํฉ๋๋ค.
- ๋น ๋ฅธ ์๋ต์ด ๊ฐ์ฅ ์ด์์ ์ด์ง๋ง, ์๋ฒ ์ ๊ทธ๋ ์ด๋๋ก ์ธํด ์์คํ ์๋๊ฐ ๋๋ ค์ง ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ์์ ์ด 10์ด ์ด์ ์์๋ ๊ฒฝ์ฐ ์ฌ์ฉ์์๊ฒ ์๋ฃ ์์ ์๊ฐ์ ํ์ํด์ผ ํฉ๋๋ค.
- ์ ์ ์ธ ์งํ๋ฅ ํ์๋ ํผํ๋ ๊ฒ์ด ์ข์ต๋๋ค. (์: ํ๋ฉด์ ๋จ์ํ "...๋ก๋ ์ค" ํ ์คํธ๋ง ํ์)
์ด๋ฌํ ์ง์นจ์ ๊ณ ๋ คํ๋ฉด ๋ก๋ฉ ์๊ฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ๋ก๋ฉ ๊ฒฝํ์ ์ ๊ณตํ๋ ๊ฒ์ด ๋ฐ๋์งํฉ๋๋ค.
๋ํ, ๋ชจ๋ ๊ฒฝ์ฐ๊ฐ ์๋ 1์ด ์ด์ ์ง์ฐ๋ ๊ฒฝ์ฐ์๋ง ๋ก๋ฉ ์คํผ๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
##React Suspense ๋ฅผ ์ด์ฉํ์ฌ ๋ก๋ฉ ๊ฒฝํ ๊ฐ์
ํ์ฌ ์ ํฌ๋ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ Suspense๋ฅผ ์ด์ฉํ์ฌ child component๋ฅผ ๊ฐ์ธ ๋ก๋ฉ ์คํผ๋๋ฅผ ๋ณด์ฌ์ฃผ๊ณ ์์ต๋๋ค.
// example
<div className={styles.page__depart}>
<React.Suspense fallback={<LoadingSpinner />}>
<DeptListbox />
</React.Suspense>
</div>
์ด๋ฅผ ๋ก๋ฉ ์๊ฐ์ ๋ฐ๋ผ ๋ค๋ฅธ UX๋ฅผ ์ ๊ณตํ ์ ์๋๋ก ์ ํธ์ฑ ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํด ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, 1์ด๊น์ง๋ ์๋ฌด๋ฐ UX๋ฅผ ์ ๊ณตํ์ง ์๋ค๊ฐ 1์ด ์ด์ ๋ก๋ฉ์ด ์ง์ฐ๋๋ค๋ฉด ๊ทธ๋ ๋ก๋ฉ ์คํผ๋๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์๋๋ ์นด์นด์ค์์ ์ ์ํ ์ ํธ ์ปดํฌ๋ํธ ์ค๊ณ์ ๋๋ค.
const DeferredComponent = ({ children }: PropsWithChildren<{}>) => {
const [isDeferred, setIsDeferred] = useState(false);
useEffect(() => {
// 200ms ์ง๋ ํ children Render
const timeoutId = setTimeout(() => {
setIsDeferred(true);
}, 200);
return () => clearTimeout(timeoutId);
}, []);
if (!isDeferred) {
return null;
}
return <>{children}</>;
};
**DeferredComponent**๋ children์ Props๋ก ๋ฐ๊ณ , 200ms ์ด์ ์๋ children์ ๋ ๋๋งํ์ง ์์ต๋๋ค.
๋ฐ๋ผ์ ๊ธฐ์กด์ ๋ก๋ฉ ์คํผ๋์ ์ด **DeferredComponent**๋ฅผ ์ ์ฉํ๋ฉด ํน์ ์์ ๋ถํฐ ๋ก๋ฉ ์คํผ๋๊ฐ ๋ณด์ฌ์ง๊ฒ ๋ฉ๋๋ค.
<div className={styles.page__depart}>
<React.Suspense
fallback={
<DeferredComponent>
<LoadingSpinner />
</DeferredComponent>
}
>
<DeptListbox />
</React.Suspense>
</div>
์ฐ๋ฆฌ๋ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๊ธฐ ์ํด ํญ์ Progress Indicator(=Skeleton)์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋น ๋ฅธ ์ธํฐ๋ท ํ๊ฒฝ์์๋ ์คํ๋ ค ์ ํ์ ์ผ๋ก Progress Indicator๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ๋ ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
resource
- https://tech.kakaopay.com/post/skeleton-ui-idea/
- https://www.nngroup.com/articles/progress-indicators/
--
3. Web vital ์ต์ ํ๋ฅผ ์ํ tip
์น ์ฑ๋ฅ ์ต์ ํ๋ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ์ฃผ์ ์์๋ก, ์๋น์ค ๊ด์ ์์๋ ์ค์ํ ์ญํ ์ ํฉ๋๋ค. ๋ก๋ฉ ์๋๊ฐ ๋๋ฆด์๋ก ์ฌ์ฉ์๋ ์น์ฌ์ดํธ๋ฅผ ๋ ๋ ๊ฐ๋ฅ์ฑ์ด ๋์์ง๋๋ฐ, 0.1์ด์ ์ฑ๋ฅ ๊ฐ์ ๋ conversion rate๋ฅผ ๋์ผ ์ ์์ต๋๋ค.
์ฃผ๋ก LCP, FID, INP์ ๊ฐ์ web vitals๋ก ์ธก์ ๋๋ฉฐ, ์ด๋ฌํ ์งํ๋ ์ฌ์ฉ์์ ์ฒซ ๋ฐ์์ ๊ธฐ์ค์ผ๋ก ํฉ๋๋ค. (์ต๊ทผ์๋ ์ด๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด INP๊ฐ ๋์ ๋์๋๋ฐ, ์ด๋ ๋ชจ๋ ์ ๋ ฅ ์ง์ฐ ์๊ฐ์ ํ๊ท ์ ์ธก์ ํ๋ ๋ฑ ๋ ๋์ ์ธก์ ์ด ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.)
์ด๋ฌํ web vitals ๋ฅผ ์ด๋ป๊ฒ ๊ฐ์ ํ ์ ์๋์ง, ์ฌ๋ฌ๊ฐ์ง ํ๋ค์ ์ ๋ฆฌํด๋ดค์ต๋๋ค.
LCP ์ต์ ํ
- LCP ์์์ด HTML ๋ด์์ ๋นจ๋ฆฌ ์ฐพ์์ ธ์ผ ํฉ๋๋ค.
- LCP ์์์ด ์ฐ์ ์๋์ด ๋ค์ด๋ก๋๋ ์ ์๋๋ก ํด์ผ ํฉ๋๋ค.
- CDN์ ์ฌ์ฉํ์ฌ ๋์ ํฌ์ํฉ๋๋ค.
- ์ฌ์ฉ์๊ฐ ๊ฐ์ฅ ๊ฐ๊น์ด ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌ๋ฐ์ ์ ์๋๋ก ํฉ๋๋ค.
- ๋ฌผ๋ฆฌ์ ์ผ๋ก ์ต๋ํ ๊ฐ๊น์ด ์๋ฒ๋ฅผ ํ์ฉํฉ๋๋ค.
์ค์ ์ฌ๋ก:
- ์ด๋ฏธ์ง๋
<img>์๋ฆฌ๋จผํธ์ ๋ฃ๊ณsrc๋srcset์์ฑ์ ์ด์ฉํ์ฌ ์ฒซ ๋ฒ์งธ ๋ ๋๋ง ์ ํ์ํ ์ด๋ฏธ์ง๋ฅผ ์๋ ค์ค๋๋ค. - SSR์ ์ฌ์ฉํฉ๋๋ค.
- ๋ด๋ถ์์ ํธ์คํ
ํ์ง ์๋ ์ด๋ฏธ์ง์๋
<link rel="preload">ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ธ๋ผ์ฐ์ ์๊ฒ ๋นจ๋ฆฌ ๋ก๋ํด์ผ ํ๋ ์์ค์์ ์๋ ค์ค๋๋ค. <img>ํ๊ทธ์fetchpriority="high"์์ฑ์ ์ถ๊ฐํ์ฌ LCP ์ด๋ฏธ์ง๋ฅผ ์ฐ์ ์ ์ผ๋ก ๋ธ๋ผ์ฐ์ ๊ฐ ๋ค์ด๋ก๋ํ๊ฒ ํฉ๋๋ค.<img>์๋ฆฌ๋จผํธ์loading="lazy"์์ฑ์ ์ถ๊ฐํ์ฌ LCP ๊ฐ ์๋ ์ด๋ฏธ์ง๋ฅผ ๋์ค์ ๋ก๋ฉํ ์ ์๋๋ก ํฉ๋๋ค.
CLS ์ต์ ํ
- ์ปจํ ์ธ ์ ๋ช ํํ ์ฌ์ด์ฆ๋ฅผ ์ค์ ํฉ๋๋ค.
- ํ๋ค๋ฆฌ๋ CSS ์ ๋๋ฉ์ด์ ๋ฐ ์ ํ ํจ๊ณผ๋ฅผ ์ง์ํฉ๋๋ค.
- bfcache๋ฅผ ์ฌ์ฉํ์ฌ ์บ์ฑ์ ์ต์ ํํฉ๋๋ค.
- ๋ชจ๋ ์งํ๋ฅผ ํฅ์์ํฌ ์ ์๋ ๋๊ตฌ์ ๋๋ค.
- ์ด๋ฅผ ์ํด ์บ์ฑ์ ๋ง์๋์ง ์์๋์ง ํ์ธํฉ๋๋ค.
์ค์ ์ฌ๋ก:
width์height๋ฅผ ๋ช ์์ ์ผ๋ก ์ง์ ํฉ๋๋ค.aspect-ratio๋ฅผ ์ฌ์ฉํ์ฌwidth๋ง ์ง์ ํ๊ณheight๋ฅผ ์ ๋์ ์ผ๋ก ์ค์ ํฉ๋๋ค.min-height๋ฅผ ์ง์ ํ์ฌ ์์๊ฐ ๋ ๋ฐ๋ฆฌ๋๋ก ๋ฐฉ์งํฉ๋๋ค.
FID ์ต์ ํ
- ๊ธด ์์ ์ ์๊ฒ ๋ถํ ํฉ๋๋ค.
- ๋ถํ์ํ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์ต์ํํฉ๋๋ค.
- ํฐ ๋ ๋๋ง ์
๋ฐ์ดํธ๋ฅผ ํผํฉ๋๋ค.
- ๋ถ๋ถ์ ์ผ๋ก๋ง ์ ๋ฐ์ดํธํฉ๋๋ค.
์ค์ ์ฌ๋ก:
- ๊ธด ์์
์ ์๊ฒ ๋ถํ ํฉ๋๋ค.
- webpack๊ณผ ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ chunking์ด ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
- ๋ฉ์ธ ์ฐ๋ ๋์์ ์ ์ ์์์ ์๋ณดํฉ๋๋ค.
- coverage ๋๊ตฌ๋ฅผ ํ์ฉํฉ๋๋ค.
- ์ฝ๋๋ฅผ ๋ถํ ํฉ๋๋ค.
- ๋ถํ์ํ ํธ๋ํน ํ๊ทธ๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
requestAnimationFrame()์ฌ์ฉ์ ์ง์ํ๊ณ DOM ํฌ๊ธฐ๋ฅผ ์ต์ํํฉ๋๋ค.
reference
https://web.dev/articles/vitals
23๋ 6์ Tech ์ธ๋ฏธ๋ - ์น ํ๋ก ํธ์๋ ์ฑ๋ฅ ์ต์ ํ ๋ฐฉ๋ฒ ๋ฐ ์ ์ฉ ์ฌ๋ก
--
4. ์ฌ๋ฏธ์ ์ด์ต์ ์ํ ์๋ฐ์คํฌ๋ฆฝํธ ์ ๋ฌธํ
https://velog.io/@surim014/optimizing-javascript-for-fun-and-for-profit#9-์ ๋ฌธํspecialization-์ฌ์ฉํ๊ธฐ ์ด ๊ธ์ JavaScript ์ต์ ํ ๋ฐฉ๋ฒ์ ๋ํ ๋ด์ฉ์ ์๊ฐํฉ๋๋ค.
์ด์ค์์ 9๋ฒ ์ฑํฐ์ธ ์ ๋ฌธํ(specialization) ์ ๊ด๋ จํด ํฅ๋ฏธ๋กญ๊ฒ ๋๋ ๋ถ๋ถ์ ์ค์ฌ์ผ๋ก ์ค๋ช ํ๊ฒ ์ต๋๋ค. ์ด์ธ์ ๋ด์ฉ์ด ๊ถ๊ธํ์ ๋ถ๋ค์ ์ ๊ธ์ ๋๋จธ์ง ์ฑํฐ๋ค์ ์ฝ์ด๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
์ ๋ฌธํ
์ ๋ฌธํ๋ ํน์ ์ฌ์ฉ ์ฌ๋ก์ ์ ์ฝ ์กฐ๊ฑด์ ๋ก์ง์ ๋ง์ถ๋ ๊ฒ์ ๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ํ ์กฐ๊ฑด์ด ๋ค๋ฅธ ์กฐ๊ฑด๋ณด๋ค ๋ ์์ฃผ ๋ฐ์ํ๋ค๊ณ ํ๋จ๋ ๋, ์ด๋ฅผ ํ์ ํ๊ณ ํด๋น ์กฐ๊ฑด์ ๋ง๊ฒ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ์ด๋ค ์ ํ ๋ชฉ๋ก์ ํ๊ทธ๋ฅผ ์ถ๊ฐํด์ผ ํ๋ ์ํฉ์์, ํ๊ทธ๊ฐ ๋๋ถ๋ถ ๋น์ด์๋ค๋ ๊ฒ์ ์๊ฒ ๋์๋ค๊ณ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค.
๋ฐ๋ผ์ ์ด ์ํฉ์ ๋ง์ถ์ด ์ ๋ฌธํ๋ฅผ ์ ์ฉํ๊ณ ์ด์ ๋ํด ์ค๋ช ํ๊ฒ ์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์์ ๋ฌผํ๊ณผ ํ๊ทธ๋ฅผ ์ ์ํฉ๋๋ค.
const descriptions = ["apples", "oranges", "bananas", "seven"];
const someTags = {
apples: "::promotion::",
};
const noTags = {};
๊ทธ๋ฐ ๋ค์, ์ ๋ฌธํ๋ฅผ ์ ์ฉํ์ง ์์ ๋ฌธ์์ด ๋ณํ ํจ์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
// ํด๋น๋๋ ๊ฒฝ์ฐ ํ๊ทธ์ ํจ๊ป ์ ํ์ ๋ฌธ์์ด๋ก ์ ํํฉ๋๋ค.
function productsToString(description, tags) {
let result = "";
description.forEach((product) => {
result += product;
if (tags[product]) result += tags[product];
result += ", ";
});
return result;
}
์ด์ ๋ค๋ฅด๊ฒ ๋นํ๊ทธ๋ฅผ ๋จผ์ ๊ฑธ๋ฌ์ฃผ๋ ์ ๋ฌธํ๊ฐ ์ ์ฉ๋ ๋์ผํ ๊ธฐ๋ฅ ํจ์๋ฅผ ๋ง๋ค์ด์ค๋๋ค.
function productsToStringSpecialized(description, tags) {
// ์ฐ๋ฆฌ๋ `tags`๊ฐ ๋น์ด ์์ ๊ฐ๋ฅ์ฑ์ด ์๋ค๋ ๊ฒ์ ์๊ณ ์์ผ๋ฏ๋ก ๋ฏธ๋ฆฌ ํ ๋ฒ ํ์ธํ ๋ค์ ๋ด๋ถ ๋ฃจํ์์ `if` ๊ฒ์ฌ๋ฅผ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
if (isEmpty(tags)) {
let result = "";
description.forEach((product) => {
result += product + ", ";
});
return result;
} else {
// ๋ฌธ์์ด ์ ํ ๋ก์ง์ ๋์ผ
}
}
function isEmpty(o) {
for (let _ in o) {
return false;
}
return true;
}
์ด ๋๊ฐ์ ํจ์๋ฅผ ๊ฐ์ง๊ณ ์ค์ ๋น๊ตํ์ ๋์ ์์น ๋น๊ต๋ ๋ค์๊ณผ ๊ฐ์ด ๋ํ๋ฉ๋๋ค.
- non speciailized : 85.71 %
- specialized : 100 %
์์ ๊ฐ์ ์ํฉ์์๋ ๋ค์๊ณผ ๊ฐ์ ์๊ณ ๋ฆฌ์ฆ ์ ์ฉ์ ํตํด ์ฑ๋ฅ์ด ๋ ๋์์ง ์๋ ์์ง๋ง, ์กฐ๊ฑด์ด ๋ฌ๋ผ์ง๋ค๋ฉด ๋ค๋ฅด๊ฒ ํ๋จํด์ผ ํ ํ์๊ฐ ์์๊ฒ์ ๋๋ค.
(์ฝ๋์์์ ๋ถ๊ธฐ ์ธก๋ณ์์๋ ์ ๊ฑฐํ๋๊ฒ ๋ ํจ์จ์ ์ด๋ค ๋ผ๋ ์ด๋ฉด์ด ์๊ธฐ์.. ๋ํ ์์)
https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array
--
5. ์๊ฐ ๋จ์ถ์ ์ํ Tailwind ์ฌ์ฉ๊ธฐ
Tailwind๋ ์ต๊ทผ ์น ๋ถ์ผ์์ ์ธ๊ธฐ๋ฅผ ๋๊ณ ์๋ CSS ํ๋ ์์ํฌ์ ๋๋ค.
ํ์ง๋ง ๊ฐ๋ฐ์๋ค ์ฌ์ด์์๋ ํธ๋ถํธ๊ฐ ๋ง์ด ๊ฐ๋ฆฌ๋ ํธ์ด๋ฉฐ, ์ฌ๋ฌ ๋ ผ์์ด ์ค๊ฐ๋ ํซํฌํ ์ดํ ๋ก ์ฌ๊ฒจ์ง๋๋ค.
Tailwind๊ฐ ์ ์ฐจ์ธ๋ css ํ๋ ์์ํฌ๋ก ๋ด๋์ง ์์๋ณด๊ณ , ์ ์ ์ง๊ทนํ ์ฃผ๊ด์ ์ธ ๋ฆฌ๋ทฐ๋ ๊ฐ๋จํ ์ ์ด๋ณด๋ คํฉ๋๋ค.
Tailwind?
Tailwind๋ ๋ง์ ์ ํธ๋ฆฌํฐ(utility) ํด๋์ค๋ก ์ด๋ฃจ์ด์ง CSS ํ๋ ์์ํฌ์ ๋๋ค.
์ ํธ๋ฆฌํฐ ํด๋์ค๋ ํ๊ฐ์ง ์ผ๋ง ํ๋ ๋งค์ฐ ์ ์ ์์ css ์ฝ๋๋ฅผ ๋ด๊ณ ์๋ ํด๋์ค๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋๋ฐ, ์ค์ tailwind ๋ก ์ฝ๋๋ฅผ ์์ฑํ๊ณ ํฌ๋กฌ inspector๋ก ์ ํํด๋ณด๋ฉด, ๊ฐ ์คํ์ผ์ ํ ํด๋์ค๊ฐ ํ ๋น๋์ด ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๋ณดํต์ css ์ฝ๋๋ฅผ ์์ฑํ๋ ค๋ฉด css ํ์ผ์ ๋ถ๋ฆฌํ๊ฑฐ๋ ์ธ๋ผ์ธ ์์๋ก ์ง์ ์์ฑํ๊ฒ ๋ฉ๋๋ค.
๋ฌ๋ Tailwind๋ฅผ ์ฌ์ฉํ๋ฉด HTML ์์์ class ์์ฑ์ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ฅผ ์ถ๊ฐํ๋ ๊ฒ๋ง์ผ๋ก ์คํ์ผ๋ง์ด ๊ฐ๋ฅํฉ๋๋ค. (Tailwind์ PostCSS ํ๋ฌ๊ทธ์ธ์ผ๋ก ๋์ํ๋ค๊ณ ํฉ๋๋ค)
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด Tailwind ์ฝ๋๋ฅผ ์์ฑํ๋ค๊ณ ๊ฐ์ ํ๋ฉด,
<button class="rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-600">
Primary
</button>
๋ค์๊ณผ ๊ฐ์ css ํด๋์ค๋ค์ด ํฉ์ณ์ง๊ฒ ๋ฉ๋๋ค.
.rounded {
border-radius: 0.25rem;
}
.bg-blue-500 {
background-color: rgb(59 130 246);
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
...
๋ค๋ฅธ CSS ํ๋ ์์ํฌ์์ ๋น๊ต
๋ํ์ ์ธ Bootstrap ์ด๋ Mererial UI ๋ฑ๊ณผ๋ ๋ค๋ฅด๊ฒ Tailwind๊ฐ ๊ฐ์ง ๊ฐ์ ์ ๋ฌด์์ผ๊น์?
Bootstrap๊ฐ์ ํ๋ ์์ํฌ๋ <button class="btn btn-primary"> ํ์ค์ด๋ฉด ์์ UI ์ ๋์ผํ๊ฒ ๊ตฌํํด๋ผ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋, ์ธ๋ถ์ ์ธ CSS ์์ ์ด ๋ถ๊ฐํ๊ฑฐ๋ ๋ถํธํด์ง๋๋ค.
๋ฐ๋ผ์ Tailwind๋ ๋ ๋ง์ ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ณ ๋ฐฐ์์ผ ํ๋ค๋ ๋จ์ ์ด ์์ง๋ง, ๋ค๋ฅธ ์ธก๋ฉด์ผ๋ก ๋ณด๋ฉด ์์ฒญ๋ ์ ์ฐ์ฑ๊ณผ ํ์ฅ์ฑ์ ์ ๊ณตํ๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค.
๋ค์ํ CSS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์จ๋ณธ ์ ๋ก์๋ ์ด ๋ถ๋ถ์ด ๋ง์ด ๊ณต๊ฐ๋๋ ๋ถ๋ถ์ ๋๋ค.
Tailwind๋ฅผ ๋๋ฌ์ผ ์น์ดํ ๋ ผ์
ํธ์ํฐ๊ฐ์๊ณณ์์๋ Tailwind๋ฅผ ์ข์ํ๋ ๋ถ๋ฅ์ ์ซ์ดํ๋ ๋ถ๋ฅ๊ฐ ๋์๋ ๋ ผ์์.. ํ๋ค๊ณ ํฉ๋๋ค.
Tailwind๋ฅผ ์ข์ํ๋ ๊ฐ๋ฐ์๋ค์ ์์ฐ์ฑ ์ธก๋ฉด, ๋น ๋ฅด๊ฒ ๋์์ธ์ ๊ตฌํํ๊ฒ ๋์์ค๋ค๋ ์ ์ ๊ฐ์กฐํฉ๋๋ค. ๋ํ ๋ณ๊ฒฝ์ด๋ ์์ ์ด ์ฌ์์ ์ ์ง๋ณด์๊ฐ ์ ๋๋ค๊ณ ๋งํฉ๋๋ค. ํ ๋ฒ Tailwind๋ฅผ ์จ๋ณด๋ฉด ๋ค์๋ ๊ธฐ์กด์ผ๋ก ๋์๊ฐ์ง ๋ชปํ๋ค๋ ๊ฐ๋ ฅํ ์ฐฌ์ฑ์ ์๊ฒฌ๋ ๋ณด์์ต๋๋ค.
๋ฐ๋ฉด, Tailwind๋ฅผ ์ซ์ดํ๋ ๊ฐ๋ฐ์๋ค์ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ฅผ ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋๊ฒ์ด ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ฉฐ ์คํ๋ ค ์ ์ง ๋ณด์์ฑ์ด ๋ฎ์์ง๋ค๊ณ ์ฃผ์ฅํฉ๋๋ค. ๋ํ ๊ณผ๋ํ๊ฒ Tailwind๋ฅผ ํ์ตํ ๊ฒฝ์ฐ, css ๋ฐ๋ณด๊ฐ ๋ ๊ฑฐ๋ผ๋ ๊ฒฝ๊ณ ๋ ์กด์ฌํ์ต๋๋ค. (ํ์ง๋ง, Tailwind๋ฅผ ์ฌ์ฉํด๋ณด์ง ์์ ์ฌ๋๋ค์ด ์ด๋ฐ ๋ง์ ํ๋ค๋ ์์ค๋ ์์ต๋๋ค.)
๋์ ์ฃผ๊ด์ ์ธ ๋ฆฌ๋ทฐ
์ต๊ทผ ์งํํ ํ๋ก์ ํธ์์ Tailwind๋ฅผ ์ฒ์๋ถํฐ ๋์ ํด ์ฌ์ฉํด๋ณด์๋๋ฐ, ์ ์ ์ฃผ๊ด์ ์ธ ์ฅ๋จ์ ์ ๋ฆฌ๋ทฐํด๋ณด๊ฒ ์ต๋๋ค.
์ฅ์
- ๋งค์ฐ ๋น ๋ฅธ CSS ์์ฑ์ด ๊ฐ๋ฅํ๋ค (๊ธฐ์กด UI ์์ ์๊ฐ์ ํจ์จ์ ์ฝ 70% ์ ๋ ์ฌ๋ ธ๋ค๊ณ ์๊ฐ).
- ๋ค๋ฅธ CSS ํ๋ ์์ํฌ๋ณด๋ค ์์ ๋๊ฐ ๋๊ณ , ์์ ์ด ์ฉ์ดํ๋ค.
- ์ปดํฌ๋ํธ์ CSS ํ์ผ์ ๋ฐ๋ก ์ฐพ์ง ์์๋ ๋์ด ๊ฐํธํ๋ค.
- ๋ชจ๋ฐ์ผ ๋ฐ์ํ ์ ์ฉ์ด ํธ๋ฆฌํ๋ค (**
sm:flex**์ ๊ฐ์ด ์์ฑํ๋ฉด ์์ ํ๋ฉด์์ flex๊ฐ ์ ์ฉ๋จ).
๋จ์
- ์ ์ฉํ CSS ์์๊ฐ ๋ง์ ๊ฒฝ์ฐ, ์ธ๋ผ์ธ ์ฝ๋๊ฐ ์์ฒญ ๊ธธ์ด์ง๋ค.
- ๋ง์ ์์ HTML ์์์ CSS๋ฅผ ํ๊บผ๋ฒ์ ๋ณด๋ฉด ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ค.
- **Vendor Prefixes** ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ถ๊ฐ์ ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ install ํด์ผํ๋ค.
๋ง์น๋ฉฐ
์ฌ์ค ์ด๋ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋์ ํ ์ง ๊ฒฐ์ ํ ๋์๋ ๋ง์ ๊ณ ๋ ค์ฌํญ์ ๋ฐ์ ธ๋ด์ผ ํฉ๋๋ค. ๊ทธ๋ผ์๋ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ ์ธ๋ถ์ ์ธ ์์ธ(์ธ์ง๋, ์ปค๋ฎค๋ํฐ ์๊ฒฌ)์ ํฉ์ธ๋ฆฌ์ง ๋ง๊ณ ์์ ์ ํ๋ก์ ํธ์ ์ ํฉํ ๋๊ตฌ์ธ์ง ํ๋จํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐ์ด ๋ญ๋๋ค.
reference
https://tailwindcss.com/
https://tailwindcss.com/docs/browser-support#vendor-prefixes
https://kulkarniankita.com/newsletter/tailwind-vs-css-the-twitter-drama-
https://www.daleseo.com/tailwind/