리액트나 앵귤러 같은 웹 프레임워크가 편하기는 하지만 비교적 소규모 프로젝트를 빠르게 개발하고자 할 때 Tailwind와 Alpine.js를 사용함으로써 얻는 장점을 무시할 수 없다고 합니다. (물론 같이 쓸 수도 있습니다) 현재 회사에서 새 프로젝트 시작과 함께 도입되었습니다.
Tailwind CSS
Tailwind CSS는 기존 .css 파일에 스타일을 세팅하는 방식이 아닌, html 태그 안 클래스 이름에 스타일을 입력하는 웹 프레임워크입니다. 자주 쓰는 스타일에 대한 정형화된 클래스 키워드를 제공해주는 게 마치 매크로 느낌이랄까요...
장점은
1. 클래스 이름을 짓느라 시간을 쓸 필요가 없다.
2. 제공된 클래스를 이용하면 스타일을 빠르게 적용할 수 있다.
3. css 파일을 따로 만들지 않으니 코드 길이가 줄어든다.
단점은
1. 제공되는 스타일 키워드들에 대한 학습이 필요하다. (공식 문서에 있음)
2. html 클래스 이름이 길어져서 가독성이 떨어진다.
3. input.css를 output.css로 바꾸는 빌드 과정이 필요하다.
npm 명령어 또는 CDN을 통해 적용할 수 있는데 방법은 아래 Tailwind 공식 홈페이지에 설명이 나와 있습니다.(쉬움)
설명에도 나와있지만, Tailwind를 적용하려면 npx tailwindcss -i (이하생략) 명령어를 통한 빌드 과정이 반드시 필요합니다.
적용 예시:
<!-- index.html -->
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="./output.css" rel="stylesheet">
</head>
<body>
<h1 class="text-red-400 font-bold underline">
Hello world!
</h1>
</body>
</html>
tailwind.config.js 에 값을 추가하여 기본적인 키워드로 제공되지 않는 스타일(색상 값 등)을 커스텀 키워드로 등록할 수도 있고, 제공되는 키워드의 값을 사용자가 바꿀 수도 있습니다. 이 또한 공식 문서에 설명이 되어있습니다.
// tailwind.config.js
module.exports = {
content: ["./src/**/*.{html,js}"],
theme: {
colors: {
"blue": "#1fb6ff",
"purple": "#7e5bef",
},
extend: {
fontSize: {"10": "10px", "12": "12px"}
},
},
plugins: [],
}
<button class="bg-blue text-12">
Doringri
</button>
Alpine.js
자바스크립트 프레임워크 Alpine.js (이하 알파인) 입니다.
Tailwind와 같이 쓰면 html 태그 안에서 스타일과 더불어 간단한 js 작업까지 할 수 있어 같이 쓰는 경우가 많다고 합니다.
알파인도 공식 홈페이지에 적용 방법이 나와있습니다.
CDN을 script 태그 안에 넣으면 끝입니다.
<!-- index.html -->
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="./output.css" rel="stylesheet">
</head>
<body>
<script defer type="module" src="/src/index.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js"></script>
</body>
</html>
그리고 html 파일 script 태그에 해당 js파일을 모듈로 등록해줍니다.
CDN 링크를 module 링크보다 위에 두면 defer 속성 때문에 알파인이 적용되지 않기 때문에 꼭 순서를 지켜야 합니다.
클릭하면 글자색이 붉게 변하고 다시 누르면 원래대로 돌아오는 토글 버튼을 만들어 보겠습니다.
// index.js
document.addEventListener("alpine:init", () => {
Alpine.data("test", () => ({
isRed: false,
turnRed() {
this.isRed = !this.isRed;
}
}));
});
index.js라는 파일을 만들어서 Alpine이 초기화되면 실행되는 EventListener를 등록하고, 그 안에서 test라는 Alpine.data를 정의합니다.
그 data 안에 isRed라는 변수와 turnRed()라는 함수를 정의합니다.
<div x-data="test">
<button :class="{'text-red-400': isRed}" class="bg-[#0000FF]" @click="turnRed()">
Turn Red
</button>
</div>
그리고 body 태그 안에 위와 같은 내용을 입력했습니다. (Tailwind와 같이 적용되어 있음)
x-data에는 div라는 태그 안에서 쓸 모든 data들을 정의합니다.
이 코드에서는 test라는 Alpine.data 객체에 있는 모든 요소를 가져왔지만, 이 코드처럼 변수 하나만 필요할 때는 아래 코드와 같이 html 파일 하나만으로 동작이 가능합니다.
그래서 아래 코드와 동일하게 동작합니다.
<div x-data="{ isRed: false }">
<button :class="{'text-red-400': isRed}" class="bg-[#0000FF]" @click="isRed = ! isRed">
Turn Red
</button>
</div>
:class는 클래스 이름을 유동적으로 변경해주는 기능을 합니다. (x-bind의 shorthand 버전)
isRed가 참이 되면 text-red-400라는 클래스명이 "bg-[#0000FF]" 라는 클래스명 뒤에 붙게 되고, 그럼 Tailwind에 의해 글자색이 붉게 변합니다.
그리고 @click에는 해당 요소를 클릭했을 때 실행될 함수를 입력합니다. (x-on의 shorthand 버전)
코드 실행하기
두 번째 방법처럼 html 파일에서 모든 작업을 수행한다면 상관없지만 .js 파일을 가지고 오려면 웹 서버를 돌려야 합니다. html 같은 정적 코드는 브라우저에서 바로 테스트가 가능하지만, js를 돌리려고 한다면
CORS 보안 에러가 발생합니다.
로컬에서 돌렸을 땐 html과 js 파일의 출처(Origin)이 달라지기 때문입니다.
SOP(Same-Origin Policy)에 따르면 프로토콜, 호스트, 포트 중 하나라도 Origin과 다를 때 저 에러가 발생합니다.
http://localhost:8080?name=doringri 라는 URL에서
http:// - 프로토콜
localhost - 호스트
8080 - 포트
name=doringri - 리소스 입니다.
반면 웹 서버에 html과 js를 함께 올려서 돌려주면 둘의 Origin이 같아지게 되고 결국 보안 에러는 없어지겠죠.
리액트나 앵귤러는 자체 웹 서버를 돌려줘서 상관 없지만 지금 같은 경우엔 웹 서버가 필요합니다.
물론 인텔리제이처럼 IDE에서 직접 돌려주는 경우도 있고 VSCode도 플러그인을 설치하면 되지만 npm으로 직접 깔아보겠습니다.
테스트를 위해 live-server를 설치하고 돌려줍니다. (http-server를 설치해도 됩니다.)
npm install -D live-server
npx live-server
잘 실행되는 걸 볼 수 있습니다.
'IT > 기타' 카테고리의 다른 글
[IT] SSR과 CSR의 차이점 (0) | 2024.03.16 |
---|---|
[Alpine.js] Alpine.store 객체를 통한 전역 데이터 관리 (0) | 2024.01.27 |
[SonarQube] New Code, Overall Code란? (0) | 2023.09.01 |
[SonarQube] 정적 분석 결과 해석하기 (0) | 2023.09.01 |
[SonarQube] Java, Kotlin, JavaScript(TypeScript) 정적 분석, 커버리지 분석 (0) | 2023.09.01 |