Antd FOUC

복세편살·2023년 4월 10일

Antd FOUC

프론트엔드를 개발할 때 디자인 라이브러리를 사용할 지 말지에 대한 고민에 빠지곤 한다. 어느정도 규모가 있는 기업이라면 내부에서 디자인 라이브러리를 직접 개발하겠지만 그렇지 않다면 늘 고민이 되는 부분이다.

예전에는 직접 모든 디자인을 Less활용해서 컴포넌트화 해서 사용해본 적이 있었는데, css에서 정말 정말 많은 공수가 들어간다.

이번에는 대세라고 하는 Antd 한 번 써보기로 결정했다. 과거에 회사 사이드 프로젝트에서 Antd 사용해본 적이 있었는데, 경험이 나쁘지 않았다.

Antd를 사용하고 배포 후 처음으로 맞이하게 된 문제는 바로 FOUC였다. 프레임워크는 SSR 적용된 Next를 사용했다. 따로 설정을 하지 않고 Antd를 js에서 사용하니 FOUC가 심하게 발생했다. 해결하기 위해서 이런 저런 정보를 찾아보았지만 결국 해답은 공홈에서 얻을 수 있었다.

디펜던시 설치

다음의 디펜던시가 필요했다.

npm install ts-node tslib --save-dev

tsconfig.node.json

{
  "compilerOptions": {
    "strictNullChecks": true,
    "module": "NodeNext",
    "jsx": "react",
    "esModuleInterop": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}

기존에 CNA하면 tsconfig.json은 들어있는데, prebuildpredev 에서 사용하기 위해 위와 같은 타입스크립트 설정파일을 따로 하나 더 만들어준다.

theme/index.tsx

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 };

scripts/genAntdCss.tsx

실행하면 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);

package.json

다음으로는 패키지.json에 predevprebuild 스크립트를 아래와 같이 작성해, 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

_app.tsx 파일에도 컴포넌트를 withTheme 함수로 래핑해준다.

export default function App({ Component, pageProps }: AppProps) {
	return withTheme(
		<MainLayout>
			<Component {...pageProps} />
		</MainLayout>
	);
}

_document.tsx

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의 개선은 어려워보인다. 완전한 사용자 경험의 개선을 위해서 다른 방법을 찾아보아야겠다.

0개의 댓글