프론트엔드 성능 최적화
❐ 들어가기
이번 우아한 테크코스 4단계 첫 번째 미션은 주어진 웹사이트의 성능을 최적화하는 것이다.
사실 이번 미션을 처음 받았을 때 되게 감이 잡히지 않았다. 😞따흐흑!
뭔가 눈에 보이는 것을 구현하라는 미션이 아니어서 어떻게 해야지! 라는 생각이 바로 떠오르지 않아서였을까?
성능 최적화라니, 데모데이 준비하면서 휘몰아치듯 알아보긴 했지만 아직 잘.. 모르는 영역같다. 헤헿
불행(?) 중 다행인건, 성능 최적화 작업에 대해 구체적으로 요구사항을 주셔서 이 내용을 발판삼아 성능 최적화를 진행할 수 있다는 것이다.
이 사이트가 유저에게 제공하려는 인사이트를 바탕으로 요구사항을 하나씩 만족해나가려고 한다.
이번 미션을 통해 성능 최적화에 대한 감을 익히고,
나중에 성능 최적화 작업이 필요할 때 쉽게 접근할 수 있도록 기초를 다져 놓겠다. 헤헤
그럼 시작해볼까!? 꼬우꼬우~
사이트에 대해 알아보기
성능 최적화 미션을 위해 우리에게 주어진 사이트는 아래와 같다.
유저는 사이트에 접속해 요즘 유행하는 gif를 볼 수 있고, 원하는 gif를 검색할 수도 있다.
그렇다면 유저가 이 사이트에 접속해 많은 gif들을 보고, 검색하는 데 문제가 없어야 한다.
사이트에 들어왔는데 로딩이 느리다거나,
검색을 했는데 이미지를 불러오는 것이 너무 느려 제대로 이용할 수 없다면
이 사이트는 무용지물이 될 것이다.
요구사항 엿보기
우리에게 주어진 요구사항은 아래와 같다.
잘 모르는 내용이 있어도, 성능 최적화를 진행하면서 알아보도록 하겠다. 호호호
1. Lighthouse 95점 이상
2. Home 페이지에서 불러오는 Script Resource 크기 60kb 미만
3. Hero 이미지 크기 120kb 미만
4. 파리 기준 Fast 3G 환경으로 접속했을 때
- Home 첫번째 로드시 LCP 2.5초 미만
- Home 두번째 이후 로드시 LCP 1.5초 미만
❐ 성능 측정하기
성능을 개선하려면, 먼저 객관적으로 성능을 측정해야한다.
나의 사이트가 어떤 부분에서 유저에게 불편함을 일으키고 있는지 먼저 알면 개선 과정이 한결 편할 것이다.
그러면 성능은 어떻게 측정해야할까?
성능을 측정하는 방법은 굉장히 다양하다.
가장 유명한 성능 측정 도구로는 갓-구글에서 만든 Lighthouse, PageSpeed Insights가 있다.
마이크로소프트에서 만든 Webhint, Waterfaller 등의 사이트도 각기 조금씩은 다르지만 같은 기능을 제공한다.
웹페이지테스트에서는 Test를 하는 위치와 브라우저, Network 환경까지도 세세히 설정해 페이지를 분석해준다.
본인이 테스트하고자 하는 지표를 제공하는 사이트를 골라서 성능을 개선해보자.
나는 주어진 요구사항에 따라 Lighthouse와 웹페이지테스트를 기준으로 성능을 측정, 개선해보려고 한다.
그럼 가볼까요우~~?
🏗 들어가기 전에, 환경설정하기
유저는 정말 다양한 환경에서 사이트를 이용할 수 있다.
내가 좋은 컴퓨터를 사용한다고 해서 유저도 같은 컴퓨터를 사용하리란 법이 없고,
컴퓨터가 아니라 모바일 환경에서 접속할 수도 있다.
그렇다고해서 모든 환경을 다 커버해야하는 것은 아니다.
서비스의 성격에 따라 어느정도의 환경까지 커버를 할 것인지에 대해 기준을 잡고 성능을 측정하는 것이 더 합리적이다.
나는 아래와 같은 환경을 가진 유저를 기준으로 성능을 측정하기로 결정했다.
처음 사이트를 방문하는 유저에게도 좋은 사용자 경험을 주고 싶었고,
데스크탑 뿐만아니라 모바일을 주로 이용하는 유저까지도 커버하고 싶었기 때문이다.
1. Memegle 사이트 최초 방문 (브라우저에 캐시를 제공받을 수 없는 환경)
2. 모바일 환경 (제한된 네트워크)
이를 위해 Chrome 브라우저의 환경을 맞춰주었다.
브라우저 캐시 비활성화
Network → Disable cache 설정을 하면,
리소스 캐시를 비활성화해 마치 웹사이트에 처음 방문한 것과 같은 환경을 유지할 수 있다.
제한된 네트워크 설정
브라우저 캐시 설정 우측의 Throttling(느린 인터넷 환경)옵션을 선택해 원하는 속도의 환경을 만들 수 있다.
기본이 No throttling, 즉 가장 빠른 옵션이고, 아래의 3G 옵션들을 선택해 더 느리게 동작하도록 선택할 수 있다.
나는 Fast 3G 환경을 선택했다.
🔦 Lighthouse 사용하기
구글에서 2020년 5월 19일 Lighthouse v.6.0 배포 이후,
Chrome 브라우저 내부의 개발자도구에서도 쉽게 Lighthouse 이용이 가능해졌다.
그래서 따로 아무런 설정을 하지 않아도 Chrome 브라우저를 이용한다면 Lighthouse를 손쉽게 사용할 수 있다.
(Chrome Extension, CLI를 사용하는 방법도 있긴 하다.)
아래와 같이 개발자도구(cmd+option+i)를 켜면 Lighthouse 탭이 숨겨져있는 것을 확인할 수 있다.
원하는 카테고리를 지정할 수 있고, Device도 모바일/데스크탑 중 하나를 택해 리포트를 생성할 수 있다.
Lighthouse가 어떻게 성능을 계산하고 있는지 더 자세히 보고싶으신 분들은 여기를 참고하시면 된다.
아래는 로컬에서 memegle 사이트를 켜고, 직접 성능을 측정해 본 결과이다.
여기에서 알고 있어야 할 점은, 어떤 상황에서 측정하느냐에 따라 측정 결과가 매번 다르게 나온다는 점이다.
이상하다고 생각할 수 있지만, 생각해보면 크게 이상한 점은 아니다.
매번 사이트에 들어갈 때마다 기본 조건이 조금씩 달라지기 때문이다.
사이트의 A/B 테스트 혹은 광고의 문제, 인터넷 트래픽 라우팅의 변경, 어떤 장치(컴퓨터)를 사용하는가,
백신 프로그램, 사이트 캐싱 등과 같은 이유가 있다. 여기에서 다양한 이유들을 더 찾아볼 수 있다.
Chrome Secret Mode는 Chrome Extension, 쿠키 및 사이트 데이터 등을 사용하지 않기 때문에
성능을 측정할 때에 조금 더 정확하게 측정할 수 있다. 그러니까 Chrome Secret Mode를 사용하자! 😚
Lighthouse에서 측정하는 내용들 대해 잠깐 알아보겠다.
Performance는 화면에 콘텐츠가 얼마나 빨리 표시되고,
유저가 해당 콘텐츠를 얼마나 빨리 인식하는지에 대한 점수를 나타낸 것이다.
Accessibility는 서비스의 접근성을 검사한다.
<img> 태그에 alt 속성이 있는지, aria-* 태그가 role과 잘 맞는지 등에 대해 검사한다.
Best Practice에서는 웹에대한 표준 모범 사례를 잘 따르고 있는지 확인한다.
console의 오류를 확인하는 등의 작업을 수행한다.
SEO는 서비스가 검색 최적화되어있는지 확인한다. robots.txt 파일이 유효한지,
<title> 태그가 적절하게 들어갔는지 등을 확인한다.
Progressive Web App은 점수화되어 나타나지 않는다.
서비스가 HTTP를 HTTPS로 redirect 하는지, 응답 코드는 잘 나타나는지 등을 확인해 합격/실패만을 나타낸다.
친절한 Lighthouse에서는 점수와 함께 그 이유, 그리고 어떻게 이를 개선해야하는지 세세하게 알려준다.
가이드라인을 하나씩 따라하다보면 어느새 내 사이트가 성능천재(?)가 된 것을 볼 수 있을 것이다. 호호호
직접 성능을 측정해보니, Performance가 굉장히 낮게 나오는 것을 확인할 수 있었다. 저런..
빨리 개선하고 싶다는 생각이 든다. 아악!
자, 그럼 성능을 개선하러 가보자!
❐ 성능 개선하기
성능 개선하기.. 라고 하면 굉장히 추상적일 것이라고 생각하지만,
앞서 우리가 측정한 지표들을 바탕으로 하나씩 개선해나가면 감이 조금씩 잡힌다. 하나씩 살펴보자.
🌍 요청의 크기 줄이기
브라우저에서 어떤 사이트에 처음으로 들어간다고 했을 때,
브라우저는 서버에 이 사이트에 대한 내용들을 보내달라고 요청하게 된다.
만약 이 요청의 크기가 크다면, 브라우저에서 사이트를 보여주는 데 더 많은 시간이 소요될 것이고,
그렇지 않다면 사이트가 빨리 유저에게 보여질 것이다.
그렇기 때문에 일단 응답 파일의 크기를 줄이는 것이 첫 번째 Step이다.
응답 파일이란, 우리가 빌드해 서버에 올려놓은 파일이다.
작성한 코드가 많아지면 결국 빌드된 결과물 또한 커지기 마련이다.
애초부터 코드를 짧게 작성해 길이를 줄여버리는 신박한 방법(?)도 있기는 하지만,
보통은 이런 파일 크기를 줄여주는 다양한 웹팩 플러그인 설정과 웹팩의 기본 설정들을 통해 이를 해결한다.
[JS 파일 압축, 난독화] Webpack 4 버전 이상의 경우, production 모드 사용하기
Webpack 4 버전부터 mode가 추가되었는데,
production(배포) 용인지, development(개발) 용인지 설정해놓으면 알아서 코드를 최적화해준다.
만약 mode를 지정해놓지 않는다면, production으로 기본 설정이 되어있다.
나는 이번 미션에서 까먹고(앗챠챠) 모드를 정해두지 않았는데, 잘 돌아갔다. 허헛
아래 첫 번째 예시처럼 모드를 아예 박아둘 수도 있고,
두 번째 예시처럼 돌아가는 환경마다 달라지게 만들어 줄 수도 있다.
// webpack.config.js
// production
module.exports = {
mode: 'production'
}
// development, production에 맞추어 mode 정해주기
module.exports = () => {
const mode = process.env.NODE_ENV || 'development'
return {
mode,
entry: './src/index.js'
...
}
}
아래처럼 package.json에서 스크립트 실행시 mode를 정해줘도 된다.
// package.json
// 빌드를 하거나 local 서버를 돌릴 때, 명시하는 방법도 있다.
"scripts": {
"build:prod": "webpack --mode=production --node-env=production",
"serve": "webpack serve --mode=development"
}
Webpack5에서 이렇게 production 모드로 실행시키면, 다음의 플러그인들을 기본으로 적용해준다.
- FlagDependencyUsagePlugin
- FlagIncludedChunksPlugin
- ModuleConcatenationPlugin
- NoEmitOnErrorsPlugin
- OccurrenceOrderPlugin
- SideEffectsFlagPlugin
- TerserPlugin 👈👈
이 중에서, TerserPlugin은 JS 코드를 줄여주고, *압축해준다(Minify). *난독화(Uglify)도 기본적으로 진행한다.
그렇기 때문에 Webpack5 production 모드를 사용하면 따로 압축이나 난독화를 해주지 않아도 최적화 작업이 적용된다.
개이득!
*압축화 - 모든 들여쓰기와 공백이 제거되고, 전체 코드가 한 줄로 병합됨. 원본 코드에서 들여쓰기, 공백, 콤마 등이 제대로 사용되지 않았다면 압축된 코드에서 문제가 생길 수 있음
*난독화 - 자바스크립트 코드 자체를 분석하기 어렵게 만드는 과정. 변수, 함수명 등이 줄어 용량 감소. 하지만 난독화 단계가 높을수록 코드를 해석하고 실행하는 속도가 느려질 수 있음
[CSS 파일 분리] MiniCssExtractPlugin 사용하기
원래는 css-loader와 style-loader를 함께 사용해줬다.
css loader는 js밖에 읽지 못하는 webpack이 css파일을 읽을 수 있도록 해주고,
style loader는 css loader로 읽은 css 파일들을 style 태그로 만들어 head 태그 안에 넣어주는 역할을 한다.
이렇게 되면, head 태그가 커지면서 한 파일의 크기가 비교적 커지게 되는데
이런 현상을 막고 css 파일을 분리하고싶다면 mini-css-extract-plugin을 사용하면 된다.
(그러므로 style-loader랑 이 플러그인이랑 같이 사용하는 건 안된당)
// 변경 전
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
// 변경 후
rules: [
...
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
plugins: [
...
new MiniCssExtractPlugin({
filename: '[name].css' // 파일 네임을 지정해 줄 수 있다.
})
]
// dev, production 모드 별로 다르게 사용하기
const mode = process.env.NODE_ENV || 'development'
return {
...
module: {
rules: [
...
{
test: /\.css$/i,
use: [ mode === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader'],
},
plugins: [
...
new MiniCssExtractPlugin({
filename: '[name].css' // 파일 네임을 지정해 줄 수 있다
})
]
}
}
[CSS 파일 압축] CssMinimizerWebpackPlugin 사용하기
파일 분리를 했으니, CSS 파일에서도 불필요한 빈칸, 공백 등을 제거해 압축시켜주는 작업을 진행해보자.
Webpack5 이전 버전에서는 OptimizeCSSAssetsPlugin을 사용했으나,
Webpack5 이상의 버전부터는 CssMinimizerWebpackPlugin을 사용하는 것이 권장된다. (하는 일은 같다.)
아래와 같이 설정해주면 된다.
module.exports = {
...,
optimization: {
splitChunks: { chunks: 'all' },
minimizer: [new CssMinimizerPlugin(), '...'],
},
}
[이미지(png, jpg) 파일 최적화]
어떤 웹 어플리케이션 하나를 만든다고 했을 때, 이미지 파일은 정말 많이 사용된다.
우리가 위에서 아무리 JS, CSS 파일을 압축시킨다고 한들, 이미지 파일의 최적화가 되어있지 않다면 큰 의미가 없을 수도 있다. 따흑
네트워크 통신에서 이미지는 많은 요소를 차지한다.
이번 미션에서 주어진 사이트도 정말 많은 이미지들을 사용하고 있기 때문에 이미지 최적화가 필요했다.
png, gif로 뒤덮인 이미지들을 최적화시켜보자.
웹을 대표하는 이미지 파일 형식은 jpg와 gif이다.
엄청 오래된 형식이고, 지금까지도 많은 곳에서 사용되고 있다.
하지만 요즘 이런 오래된 형식들에서 나타나는 비효율성때문에 다른 파일 형식들에 대한 시도가 이어지고 있다.
최신 파일 형식으로는 Webp, AVIF 등이 있다.
그 중, 조금 생소하긴 하지만 요즘 갓-구글에서 밀고있는 Webp 형식을 사용해보기로 했다.
가로 1000px 이상의 큰 사이즈 이미지를 제외하고라면, Webp 형식을 사용하는 것이 꽤나 효율적이라고 한다. (참고)
처음에는 이미지 파일을 어떻게 최적화시키지..?
큰 이미지 파일 형식으로 올려져 있는 것들을 빌드할 때 자동으로 webp 형식으로 바꾸고,
그 파일들을 압축할 수 있는 방법이 없나..? 라고 생각했다.
여러 플러그인들을 살펴보고 시도해봤는데, (ImageminWebpWebpackPlugin , imageminWebp, imagemin)
자동화에 대해서는 아직까지 그렇다 할 만한 방법을 찾지는 못했다 ㅠㅠ 추후 알게되면 더 포스팅하겠다.
(어제는 분명 ImageminWebpWebpackPlugin을 사용해서였는지.. png 파일이 webp로 변환돼서 응답이 오는 것까지 확인했는데 왜 지금은 또 설정하니까 안되는지 모르겠다 ㅜㅜ 그런데 또 생각해보면 보통 이미지 파일들은 서버에 올라가있고 S3 → Cloudfront를 거쳐 이미 압축된 형태로 제공될텐데, 굳이 프론트에서 이렇게 압축을 해줄 필요는 없어보이기도 한다. 허헛 잘 모르겠다)
어쨌든, 용량이 큰 png 파일을 수동으로 webp 형식으로 바꿔주었다. (Convertio를 활용했다.)
또, srcset 태그를 이용해 Desktop, Tablet, Mobile마다 사이즈를 다르게 제공하게했다.
<picture>
<source
type='image/webp'
srcSet={`
${heroImageWebpMobile} 375w, // w는 pixel 수를 나타낸다.
${heroImageWebpTablet} 768w,
${heroImageWebp} 1980w,
`}
alt='hero'
className={styles.heroImage}
/>
<img className={styles.heroImage} src={heroImage} alt='hero' />
</picture>
[GIF 파일 최적화]
GIF의 경우에는 MP4 형식으로 바꾸어 최적화했다. (이 또한 Convertio를 활용했다.)
비디오 파일 형식인 MP4 포맷을 autoplay, muted, loop 속성을 넣어 마치 GIF처럼 보이게 했다.
<video
src={imageSrc}
type='video/mp4'
autoPlay
muted
loop
playsInline
/>
파일 자체의 크기를 변경한 것이기에, 따로 플러그인에서 건드린 것은 없다.
더 최적화된 방법이 있을 법도 한데, 만약 찾게되면 이것도 따로 포스팅하겠다.
[Code Splitting]
Webpack은 여러개의 파일들을 JS가 이해할 수 있도록 해주고, 또 그들을 묶어 하나의 파일로 만든다.
그런데 이렇게 하나의 파일만을 받게되면 파일의 크기가 커지고, 그렇게되면 페이지가 로드되는 데 시간이 오래 걸릴 것이다.
위에서 우리가 CSS 파일을 추출해낸 것도 이런 Code Splitting의 일환이라고 볼 수 있다.
Code Splitting에는 두가지 방법이 있다.
첫번째, 우리가 사용하는 라이브러리들에 대한 최적화
하나의 JS 파일을 여러개로 나누어서
chunks에는 async, all, initial을 지정할 수 있는데, 자세한 사항은 공식문서를 참고하면 좋다.
관련 Stackoverflow도 첨부한다.
나는 모든 모듈들을 최적화하는 'all' 옵션을 선택했다.
// webpack.config.js
optimization: {
splitChunks: { chunks: 'all' }
}
두번째, 리액트 내부의 컴포넌트들의 최적화
React.lazy와 Suspense를 사용해 최적화를 적용할 수 있다.
이렇게 React.lazy를 사용해 동적 import를 하게되면 컴포넌트가 필요한 상황에서만 import 하도록 만들 수 있다.
위의 splitChunks가 JS 파일을 분리하는 것이었다면, React.lazy는 그 안의 컴포넌트들을 split하는 것이라고 이해했다.
단, React.lazy와 Suspense는 서버사이드 렌더링이 불가능하기때문에 서버사이드 렌더링이 필요하다면
Lodable Components를 사용해야한다.
const Search = React.lazy((_) => import('./pages/Search/Search'));
const Home = React.lazy((_) => import('./pages/Home/Home'));
const App = () => {
return (
<Router>
<Switch>
<Suspense fallback={<div>loading..</div>}>
<Route exact path='/' component={Home} />
<Route exact path='/search' component={Search} />
</Suspense>
</Switch>
</Router>
);
};
[LayoutShift 최소화하기]
Cumulate Layout Shift는 누적 레이아웃 변화의 약자다.
사이트의 속도 혹은 비동기 로딩으로 인해 레이아웃이 변화해 유저 경험에 좋지 않은 영향을 끼치는 지 측정하는 수치이다.
어떤 사이트에 들어갔을 때, 처음에 어떤 뼈대만 보이다가 조금 나중에 이미지가 튀어나온다던가 하는 등의 현상을 겪어본 적이 있을 것이다.
가끔 이런 일이 발생하면 귀엽게(?) 넘어갈 수 있기는 한데,
만약 취소하는 버튼을 눌러야하는데 위에 이미지가 렌더링 되지 않고있다가 렌더링되는 시점에 화면을 클릭해
잘못해서 결제를 한다던가 하는 등의 커다란 문제가 생길 수 있음을 생각하면 큰 문제가 된다.
그렇기 때문에 늦게 로딩되는 리소스에 의해 레이아웃이 변화하는 현상을 최소화하는 것은 중요하다.
이러한 레이아웃의 변화를 야기하는 요소에는 여러가지가 있다.
- 위치, 사이즈가 지정되어있지 않은 이미지
- 위치, 사이즈가 없는 광고나 iframe
- 동적으로 변화하는 콘텐츠
- *FOUT(Flash of Unstyled Text), *FOIT(Flash Of Invisible Text) 방식으로 로딩되는 웹폰트
- DOM을 업데이트 하기 전, 네트워크 응답을 기다리는 작업
- Layout 변화를 일으키는 CSS 속성들을 사용할 때(참고)
*FOUT - 웹폰트가 로드되기 전까지 시스템의 기본 글꼴을 보여주고, 로드되면 이후 대체
*FOIT - 웹폰트가 로드되기 전까지는 텍스트 렌더링을 하지 않다가 이후 렌더링
최대한 이러한 요소들을 최소화시켜 레이아웃의 변화가 많이 일어나지 않도록 해야한다.
이번 미션에는 CSS top 속성 때문에 Layoutshift가 일어나던 문제점을 transform으로 바꾸어 Layoutshift를 없애주었다.
또, 폰트의 경우에도 preload 속성을 주어 브라우저에서 현재 페이지에서 필요한 폰트를 빠르게 가져오도록 했다.
폰트는 현재 브라우저에서 사용될 것이 확실한 리소스이기 때문에 preload 속성을 넣어주었다.
그리고 폰트를 가져오는 사이트들에는 preconnect 속성을 주어 브라우저가 미리 외부의 도메인과 연결을 할 수 있도록 했다.
브라우저가 미리 어떤 도메인과 연결해야하는지 예상할 수 있게 되기 때문에, 시간을 절약할 수 있다.
사실 폰트의 크기가 크지 않다면, 이것도 프로젝트 내부에 직접 넣어주고 연결할 수도 있다.
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="preload"
as="style"
href="https://fonts.googleapis.com/css2?family=Josefin+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
onload="this.onload=null; this.rel='stylesheet'"
crossorigin
/>
preload, preconnect 등의 속성에 대해서는 여기에서 더 알아볼 수 있다.
[etc..]
이외에도 Cloudfront를 사용하며 gzip설정을 통해 더 압축된 파일로 응답을 받는다거나,
캐시 전략을 사용해 이전과 달라진 부분만 요청을 받아 유저가 다시 사이트에 들어올 때 더 나은 환경을 제공한다던가,
내부적인 코드 자체에서 API 요청을 최소화해 매 번 같은 페이지에 들어올 때 같은 API를 여러번 호출하지 않는다던가,
memoization을 사용해 이미 불러온 부분을 다시 불러오지 않는다던가 하는 등의 최적화 방법이 있다.
❐ 미션을 마무리하며..
미션 자체가 S3 + Cloudfront로 배포를 하고 시작한 미션이었어서,
레벨 3에서 프로젝트를 진행하며 살짝쿵 발을 담가보았던 AWS에 대해 더 알아갈 수 있는 시간이어서 좋았다.
아직 AWS가 어렵긴 하지만, 그래도 배포를 위해 어떤 작업들을 해야하는지 조금이나마 더 알게되어서.. 유의미한 시간이었다.
리팩토링, 성능 개선같은 문제는 정말 파도 파도 끝이 없구나 라는 생각도 들었다.
프로젝트가 어떤 유저를 커버하고 싶은지, 어느정도까지의 성능을 제공하고 싶은지에 대해 명확한 기준을 가지고
성능을 개선해나가야 할 것 같다. 아니면 너무 방대한 성능 개선의 늪에 빠져 헤어나오지 못할 수도 있을 것 같다.. ㅋㅋㅋㅋㅋㅋㅋㅋㅋ
처음엔 되게 막막하고 어려웠는데, 차츰 개선해나가는게 재밌어져서 진짜 좋았다!
후에 어떤 프로젝트의 성능 개선에 대한 작업이 주어졌을 때, 막막하지 않게 도전해 볼 수 있는 용기가 생겼다.
아임 쏘 해피🙀
미션을 진행하면서 정리도 해서, 글을 잘 작성했는지 모르겠다.
혹시라도 보신 분들 중에 잘못된 부분이 보인다면 언제든 댓글.. ( ㅠㅠ) 달아주세요 꺄르룽
참고한 글들
- Github 레포지토리 main 브랜치에 push할 때마다, AWS에 자동으로 배포해주는 자동화작업에 도움을 받은 글
https://yung-developer.tistory.com/111
- 성능 최적화에 관해 시리즈로 연재한 멋진 글
- React App을 S3 + Cloudfront로 배포할 때 어떻게 해야하는지 알려주는 아쥬 친절한 글 (S3 + Cloudfront에 대한 개념 설명은 덤!)
https://hjuu.tistory.com/26?category=1019424
- AWS 메타데이터 편집하기
- 성능 최적화에 관한 전체적인 이야기