마지막 !! 아자아자
Next의 캐싱 전략
Next.js에서는 다양한 캐싱 전략을 제공한다.
Next 13부터 App 라우터가 도입되면서 프론트 서버에 부담이 늘어났다.
이유는 Server Component도 그 때 등장했기 때문!!
따라서 캐싱을 적당히 활용하여 프론트 서버의 부담을 줄여주자.
Request Memoization (Server)
Data Cache (Server)
Full Route Cache (Server)
Router Cache (Client)
https://nextjs.org/docs/app/building-your-application/caching#overview
Building Your Application: Caching | Next.js
An overview of caching mechanisms in Next.js.
nextjs.org
[관련 개념]
Duration: 캐시가 얼마나 오래 가는지
Revalidating: 언제 캐시를 무효화하고 새로운 캐시를 받아올 지
Opting out: 캐시 사용 안 함
Build Time
- 서비스를 만들고 배포하려면 빌드라는게 우선 되어야 한다. 그리고 빌드된 결과물을 배포하는 것!
- Build Time에 최적화를 많이 하자.
1. 페이지를 하나 접근했을 때 어떻게 캐시를 하냐
2.
Request Time
- 배포를 한 후에 실제 요청이 사용자로부터 왔을 때 어떻게 동작하는지
1. 배포 후에 사용자가 페이지를 방문했을 때 어떻게 캐시를 하냐
Request Memoization
한 페이지를 렌더링할 때 서버에 보내는 중복된 요청이 있으면 요청을 캐싱하는 전략 (Fetch API 사용 시)
위 그림처럼 여러 번의 요청에 대해 캐싱해준다.
Data Cache
프론트 서버가 백엔드 서버로부터 받은 데이터를 얼마동안 캐싱할 것인가
한 번 보낸 요청을 얼마동안 기억할 것인가
Duration: 계속 유지 (캐시 무효화 하거나 캐시를 아예 쓰지 않는다고 하지 않는 이상) -> 한번 캐싱을 하면 기본적으로 계속 유지 한다.
-> revalidate나 opt-out 을 잘 해줘야 한다.
-> 그렇지 않으면 사용자는 새로운 데이터를 평생 못 볼 수 있음;;
Revalidating
2가지 방법으로 캐시 무효화가 가능
- Time Based (시간에 따라 캐시 무효화)
- On Demand (수동으로 캐시 무효화)
- revalidateTag()
- revalidatePath()
revalidatePath(/home); // /home 페이지의 캐시를 모두 무효화 시킴.
Next 15에서는 no-store가 기본... (캐시 사용 안 함이 기본...)^^
Full Route Cache
: 페이지를 캐싱하는 것
언제 무효화 되는가?
- Data Cache가 Revalidate 될 때 무효화 된다.
- 재배포할 때
엄청 정적인 페이지가 아니라면 크게 신경쓰지 않아도 된다. (SNS나 커뮤니케이션 앱은 데이터들이 매번 변하니까..)
Next 14버전에서 2가지 배포 모드 (Static vs Dynamic)
- Static 모드: Next 서버 없이 HTML 페이지들만으로 구성된 정적인 사이트, 빌드할 때 모든 컨텐츠가 결정된다. -> Next 서버는 필요없다. 서버가 필요한 이유는 컨텐츠를 그때그때 다르게 불러오는 Dynamic 데이터를 다룰 수 있게 (ex. 트위터)
블로그나 뉴스 등에 적합 (대신, 글을 수정하려면 rebuild 해야함)
const nextConfig = {
output: 'export',
...
}
로 설정하면 static 배포 모드이다.
대신 Next 서버가 없기 때문에 지원되지 않는 기능들이 있다.
Dynamic Routes, Cookies, Rewirtes, Redirects, .. 등등 Next 공식문서 참고!!
위 중에 하나라도 쓰고 있으면 Dynamic 모드로 설정~
사이트 build 하기
1. npm run build: 작성된 코드를 production용으로 만든다. 코드에러가 있는지 검사도 해줌
2. npm start: 빌드된 파일 실행
배포하기 (과금주의!!) - 맛보기 버전임.
0. 준비물: GitHub 계정, Git 설치, AWS 계정
1. Local에 있는 프로젝트를 Github에 올린다.
- .env 파일에 민감한 내용이 들어있다면 지워야 함. (아니면 파일 자체를 .gitignore에 추가)
2. AWS EC2 생성
- 우분투 선택
- t2.small 선택 (프리티어 아님)
- 키페어 없이 진행
- 보안그룹 생성 선택
3. Next 포트를 3000 -> 80으로 바꿔준다.
4. 생성된 EC2에 접속하여 node.js를 설치한다.
- Ubuntu에 node.js 설치 검색 ㄱㄱ
5. Github에 올려둔 프로젝트를 clone 받고 해당 디렉토리로 이동
6. npm i (node_modules 설치)
7. sharp 라이브러리 설치
- Production 환경에서 Image Optimization 할 때 sharp 라이브러리 사용하면 성능이 좋아진다고 한다.
8. .env.production 파일 추가
- 기존 .env.local에 있던 내용을 복붙한다. (production 모드에 맞게 바꿔야 할 값은 바꿔준다.)
9. 빌드 진행 (npm run build)
- 참고: 프리티어용 서버에서는 메모리 부족으로 안된다더라..
- 서버 사양에 따라 시간이 좀 걸릴 수 있음
10. AWS 탄력적 IP 생성 후 EC2 서버와 연결 (탄력적 IP 유료임!!)
- EC2 서버에 고정 IP를 할당해주는 작업
- 탄력적 IP 사용 안하면 서버 껐다 킬 때마다 IP 바뀜.. 매우 귀찮아짐!!
11. npm start
2. 성공하면 탄력적 IP 주소로 페이지 접속 가능!!
테스트 해보았다면 과금 방지를 위해
- EC2 삭제 (종료)
- 탄력적 IP 연결 해제 및 삭제
이러한 과정으로 배포할 수 있고, 다른 방법도 있으니 (Nginx를 통한 배포) 배포 공부도 해보자..
요즘 프론트 개발자도 프론트엔드 정도는 배포할 수 있는 사람을 원한다..
SNS에 공유되는 이미지, 텍스트 설정하기
- generateMetadata 사용
- metadata의 openGraph 설정
설정 후 재배포 -> head 태그 내부에 name="og:~"로 시작하는 meta 태그가 생기면 성공!
웹소켓을 사용하여 실시간 채팅 구현하기 (보너스 강좌.. 오예)
준비물: socket.io
1. socket.io 4 버전 설치
웹소켓
: 서버에 따로 요청을 보내지 않아도 서버가 클라이언트에 데이터를 전송할 수 있다. (대신 맨 처음 연결 한번 해야 함)
웹소켓 활용
- 메시지 주고받기
- 실시간으로 새 게시글이 등록되었을 때 알림 받기
socker.io를 서버 컴포넌트에서 쓰면 메모리 누수가 발생할 수 있다.
메모리 누수: 아무것도 안했는데 메모리 사용량이 자꾸 증가함
=> 클라이언트 컴포넌트 내에서 사용하자.
커스텀 훅 생성: useSocket
export default function useSocket() {
const [socket, setSocket] = useState<Socket | null>(null);
const disconnect = useCallback(() => {
socket?.disconnect();
setSocket(null);
}, [socket]);
useEffect(() => {
if (socket) return; // 중복 소켓 연결 방지
const socketResult = io(서버와 웹소켓 연결하는 주소 입력, {
transports: ['websocket']
// socket.io는 웹소켓을 지원하지 않는 환경에서 polling 기법을 사용하도록 되어있다.
// 하지만 websocket만 사용하겠다고 설정하는 것
})
// 소켓 연결되었을 때
socket.on('connect', () => {
// 연결되었을 때 수행할 작업
})
// 연결 에러
socketResult.on('connect_error', (err) => {
console.error(err);
})
setSocket(socketResult);
}, [])
return [socket, disconnect];
}
사용부
"use client"; // 메모리 누수 방지를 위해 클라이언트 컴포넌트에서 사용
export default function WebSocketComponent() {
useSocket();
return null;
}
* 커스텀 훅 간의 state를 공유해야 하는 경우
let socket: Socket | null; // 바깥으로 빼주기
export default function useSocket() {
// const [socket, setSocket] = useState<Socket | null>(null);
const disconnect = useCallback(() => {
...
}, [])
return [socket, disconnect];
}
> 오 이렇게 사용하는 케이스는 처음 본다!.. 하지만 안티패턴이라고 하시니 다른 방법이 있는지 찾아봐야겠다.
> 아마 Redux, Zustand, Context API 등을 사용할 수도??...
메시지 보내기
socket?.emit('sendMessage', {
// 보낼 데이터
// ...
}); // 서버와 약속한 이벤트 이름으로 사용해야 함!!
메시지 받기
useEffect(() => {
socket?.on('receiveMessage', (data) => {}); // 서버와 약속한 이벤트 이름으로 사용해야 함!!
return () => {
socket?.off('receiveMessage'); // 리스너 정리
}
})
보너스: Vanilla Extract 적용하기
https://vanilla-extract.style/
vanilla-extract — Zero-runtime Stylesheets-in-TypeScript.
Zero-runtime Stylesheets-in-TypeScript.
vanilla-extract.style
쓱 보니까 Type-Safe한 스타일링 방법인 듯 하다! 오오..
'개발 > Next.js' 카테고리의 다른 글
Next 15가 나왔군.. (0) | 2024.12.23 |
---|---|
[Next 14] 섹션 5 (1) | 2024.12.09 |
[Next 14] 4. MSW, React-Query, react-intersection-observer (2) | 2024.11.25 |
[Next 14] 3. CSS, Next Hooks, ContextAPI, 외부 라이브러리(faker, dayjs) (2) | 2024.11.11 |
[Next 14] 2. 라우팅, 레이아웃, 페이지, CSS Module (5) | 2024.10.28 |