Remix Framework에 TailwindCSS 적용하기
안녕하세요?
오늘은 Remix 프레임워크에 TailwindCSS를 적용시켜 보겠습니다.
먼저, 지난 시간까지 만든 remix-tutorial 폴더에서 다음과 같이 tailwindcss와 concurrently를 설치해 보겠습니다.
npm i -D tailwindcss@latest concurrently
이제 tailwindCSS init을 실행시켜 볼까요?
npx tailwindcss init
Remix 프레임워크에서는 postcss가 필요 없어 뺐습니다.
이제 tailwind.config.js 파일을 아래와 같이 고쳐볼까요?
module.exports = {
content: ["./app/**/*.{ts,tsx,js,jsx}"],
theme: {
extend: {},
},
plugins: [],
};
tailwindCSS 3.0 버전으로 오면서 purge 항목이 content 항목으로 바뀌었습니다.
그 content 항목에 우리의 app 폴더 밑에 있는 모든 ts, tsx, js, jsx 파일을 넣어두면 됩니다.
이제 package.json 파일을 수정해 보겠습니다.
{
// ...
"scripts": {
"build": "npm run build:css && remix build",
"build:css": "tailwindcss -o ./app/tailwind.css",
"dev": "concurrently \"npm run dev:css\" \"remix dev\"",
"dev:css": "tailwindcss -o ./app/tailwind.css --watch",
"postinstall": "remix setup node",
"start": "remix-serve build"
}
// ...
}
build:css 부분과 dev:css 부분을 추가했고 build 부분과 build:css 부분도 그에 맞게 수정했습니다.
참고로 concurrently가 동시에 실행시켜 주는 패키지입니다.
tailwindcss 가 CSS 파일을 컴파일해서./app/tailwind.css 파일로 만들어 준다는 얘기입니다.
그리고 최종적으로 만들어진 tailwind.css 파일을 app 폴더의 root.tsx 파일에서 links 함수를 통해 stylesheet로 지정만 해주면 됩니다.
...
...
import type { MetaFunction, LinksFunction } from "remix";
import styles from "./tailwind.css";
export const links: LinksFunction = () => {
return [
{
rel: "stylesheet",
href: styles,
},
];
}
...
...
app 폴더가 루트 폴더가 되기 때문에 styles를 import 할 때./tailwind.css라고 했습니다. 참고 바랍니다.
npm run dev를 실행시켜 보면 맨 처음에는 tailwind.css 파일이 없다고 나오는데 그런데 그다음에 리믹스(Remix)가 빌드될 때 tailwind.css 파일을 생성시켜서 에러 없이 작동되게 됩니다.
그럼 app/routes/index.tsx파일에 TailwindCSS를 적용시켜 볼까요?
/app/routes/index.tsx
export default function Index() {
return (
<div className="w-full flex flex-col items-center justify-center leading-6 space-y-6">
<h1 className="text-blue-500 text-2xl">Welcome to Remix</h1>
</div>
);
}
TailwindCSS가 잘 적용되었네요.
TailwindCSS Custom Components 사용하기
두 번째로 알아볼 거는 바로 TailwindCSS의 Custom Components 적용방법입니다.
Custom Components는 자주 사용하는 CSS 스타일을 이름 지어 놓는 겁니다.
예를 들어 button의 스타일을 btn이라고 지어 놓으면 다음부터는 className="btn"이라고 간단하게만 적어도 btn에 지정된 스타일이 적용되게 됩니다.
일종의 단축어라고 보시면 됩니다.
그러면 Remix 프레임워크에서는 어떻게 TailwindCSS Custom Components를 적용시킬까요?
먼저, package.json 파일을 다음과 같이 수정시킵시다.
"scripts": {
"build": "cross-env NODE_ENV=production npm run build:css && remix build",
"build:css": "tailwindcss -i ./styles/tailwind.css -o ./app/tailwind.css --minify",
"dev": "cross-env NODE_ENV=development concurrently \"npm run dev:css\" \"remix dev\"",
"dev:css": "tailwindcss -i ./styles/tailwind.css -o ./app/tailwind.css --watch",
"postinstall": "remix setup node",
"start": "cross-env NODE_ENV=production remix-serve build"
},
package.json을 잘 보시면 tailwindcss -i라고 되어 있습니다.
-i는 input 옵션인데요.
input 된 파일을 기준으로 -o output 파일을 만들라는 얘기입니다.
그래서 -i 옵션으로 준 게 바로./styles/tailwind.css 파일입니다.
이 파일의 위치는 styles 폴더 밑에 있는데요.
styles 폴더는 app 폴더 밑이 아니라 app 폴더와 같은 동등한 위치입니다.
일단 프로젝트 최상단에 app 폴더와 동등한 위치에 styles 폴더를 만들어 놓고 그 밑에 tailwind.css 파일을 아래와 같이 만듭시다.
/styles/tailwind.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn-primary {
@apply text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800;
}
}
이 파일을 보시면 익숙한 @tailwind 같은 디렉티브가 보입니다.
그리고 그 밑에 @layer components 가 있는데요.
먼저, 테스트 겸 .btn-primary 클래스를 만들었습니다.
위와 같이 하면 앞으로 .btn-primary CSS 클래스는 위의 @apply 뒤에 있는 스타일이 적용되게 됩니다.
이제 /app/routes/index.tsx 파일에 btn-primary 클래스를 적용시켜 볼까요?
export default function Index() {
return (
<div className="w-full flex flex-col items-center justify-center leading-6 space-y-6">
<h1 className="text-blue-500 text-2xl">Welcome to Remix</h1>
<button
className="btn-primary"
onClick={() => console.log("button in index.tsx")}
>
button
</button>
</div>
);
}
당연히 package.json 파일을 수정했으니까 npm run dev 했던 개발 서버를 Ctrl+C로 중지하고 다시 실행시켜야 합니다.
실행 결과 아주 잘 적용되고 있네요.
root.tsx 파일에 Document 컴포넌트 만들기
지난 시간에 안 다뤘던 Document 컴포넌트에 대해 알아보겠습니다.
NextJS에는 _Document.tsx 파일이 있는데요.
Remix Framework에는 그냥 root.tsx 파일 안에다가 만들면 됩니다.
아래 코드처럼 Document 컴포넌트를 만들고 App 컴포넌트에서는 단순히 Document 컴포넌트 안에 Outlet 컴포넌트만 넣으면 됩니다.
function Document({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
export default function App() {
return (
<Document>
<Outlet />
</Document>
);
}
그럼 여기서 Layout 컴포넌트도 여기서 지정할 수 있는데요.
Layout 컴포넌트는 NextJS와는 다른 방법으로 적용되기 때문에 다음에 그 방법을 알아보겠습니다.
오늘은 여기까지 하겠습니다.