프론트엔드를 개발할 때 디자인 라이브러리를 사용할 지 말지에 대한 고민에 빠지곤 한다. 어느정도 규모가 있는 기업이라면 내부에서 디자인 라이브러리를 직접 개발하겠지만 그렇지 않다면 늘 고민이 되는 부분이다.
예전에는 직접 모든 디자인을 Less활용해서 컴포넌트화 해서 사용해본 적이 있었는데, css에서 정말 정말 많은 공수가 들어간다.
이번에는 대세라고 하는 Antd 한 번 써보기로 결정했다. 과거에 회사 사이드 프로젝트에서 Antd 사용해본 적이 있었는데, 경험이 나쁘지 않았다.
Antd를 사용하고 배포 후 처음으로 맞이하게 된 문제는 바로 FOUC였다. 프레임워크는 SSR 적용된 Next를 사용했다. 따로 설정을 하지 않고 Antd를 js에서 사용하니 FOUC가 심하게 발생했다. 해결하기 위해서 이런 저런 정보를 찾아보았지만 결국 해답은 공홈에서 얻을 수 있었다.
다음의 디펜던시가 필요했다.
npm install ts-node tslib --save-dev
{
"compilerOptions": {
"strictNullChecks": true,
"module": "NodeNext",
"jsx": "react",
"esModuleInterop": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}
기존에 CNA하면 tsconfig.json은 들어있는데, prebuild
와 predev
에서 사용하기 위해 위와 같은 타입스크립트 설정파일을 따로 하나 더 만들어준다.
Antd의 ConfigProvider
를 노드에 래핑해주는 함수를 하나 만들어준다. 이 함수는 테마를 커스터마이징 하기 위해서 사용된다.
import React from "react";
import { ConfigProvider } from "antd";
const backgroundColor = "#f8e0f1";
const borderColor = "#FFE5CA";
const secondaryBorderColor = "#FFE5CA";
const pointColor = "#E74646";
const withTheme = (node: JSX.Element) => (
<>
<ConfigProvider
theme={{
token: {
colorPrimary: pointColor,
colorBgBase: "white",
fontFamily: "Noto Sans KR",
},
}}
>
<ConfigProvider
theme={{
token: {
colorBorderSecondary: secondaryBorderColor,
colorBorder: borderColor,
},
}}
>
{node}
</ConfigProvider>
</ConfigProvider>
</>
);
export default withTheme;
export { backgroundColor, pointColor, borderColor, secondaryBorderColor };
실행하면 output경로에 Antd css파일을 생성해주는 스크립트를 작성해준다. 위에서 작성한 withTheme을 같이 활용해서 추후에 테마를 커스터마이징하는데 도움될 수 있도록 해준다.
// scripts/genAntdCss.tsx
import { extractStyle } from "@ant-design/static-style-extract";
import withTheme from "../theme";
import fs from "fs";
const outputPath = "./public/antd.min.css";
const css = extractStyle(withTheme);
fs.writeFileSync(outputPath, css);
다음으로는 패키지.json에 predev
와 prebuild
스크립트를 아래와 같이 작성해, build
dev
스크립트 실행 시 antd css파일을 경로에 생성해줄 수 있도록 작성해준다.
// package.json
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"predev": "ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx",
"prebuild": "ts-node --project ./tsconfig.node.json ./scripts/genAntdCss.tsx"
}
}
_app.tsx
파일에도 컴포넌트를 withTheme
함수로 래핑해준다.
export default function App({ Component, pageProps }: AppProps) {
return withTheme(
<MainLayout>
<Component {...pageProps} />
</MainLayout>
);
}
document 에서 Head 내부에 빌드타임에 생성될 /antd.min.css
파일을 임포트 해준다.
export default function MyDocument() {
return (
<Html lang="en">
<Head>
<link href="/antd.min.css" rel="stylesheet" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
위와 같이 작성하면 Head에서 antd CSS를 불러오기 때문에 FOUC가 많이 개선된다.
그럼에도 불구하고 특정한 환경에 따라서 완전한 FOUC의 개선은 어려워보인다. 완전한 사용자 경험의 개선을 위해서 다른 방법을 찾아보아야겠다.