Nextjs-Optimizing(5) - Image caching
๐ ์์ํ๋ฉฐ
์ด์ Nextjs-Optimizing(4) ํฌ์คํ
์์ static assets์ ๋ํด ์ดํด๋ณด์๋ค.
์ฌ์ค ๊ทธ๋๋ โ๊ทธ๋ ๊ตฐ! ์ข์! ๐คโ ํ๊ณ ๋์ด๊ฐ๋๋ฐ, ๋์ค์ ์ด๊ฑธ ์ค์ ๋ก ์ฌ์ฉํ ์ผ์ด ์๊ธฐ๋ ์ฝ๊ฐ์ ์ํ์ฐฉ์ค๋ฅผ ๊ฒช๊ฒ ๋์ด, ์ด๋ฅผ ํด๊ฒฐํ๋ ๊ณผ์ ์ ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค.
๐ผ๏ธ Image Caching
๐ฅ ๋ฌธ์ ์ํฉ
๋๋ public ํด๋ ๋ด์ staticํ ์ด๋ฏธ์ง๋ฅผ ์์ฃผ ์ฌ์ฉํ๋๋ฐ, ํด๋น ์ด๋ฏธ์ง๋ ๋ฐ๋ ํ๋ฅ ์ด ๊ฑฐ์ ์๋ ์ด๋ฏธ์ง์๋ค. ๊ทธ๋ฐ๋ฐ ์ด ์ด๋ฏธ์ง๋ฅผ ๋ ๋๋งํ ๋๋ง๋ค ๋คํธ์ํฌ ์์ฒญ์ ๋ณด๋ด๋ ๊ฒ์ ๋๋ฌด ๋นํจ์จ์ ์ผ๋ก ๋๊ปด์ ธ, โ์ด๊ฑธ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ์ง?โ ๊ณ ๋ฏผํ๋ค๊ฐ, ์ด์ ํฌ์คํ ๊ณผ ํจ๊ป Next.js ๊ณต์๋ฌธ์๋ฅผ ๋ค์ ํ์ด๋ณด๋ฉฐ ์ด๋ฏธ์ง ์บ์ฑ ์ ์ฉ์ ์๋ํ๊ฒ ๋์๋ค.
๐ ์บ์๋?
๋จผ์ , ์บ์(Cache) ๊ฐ ๋ฌด์์ธ์ง ๊ฐ๋จํ ์ง๊ณ ๋์ด๊ฐ์.
์บ์๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์น์ฌ์ดํธ์ ์ด๋ฏธ์ง, ๊ธ๊ผด, HTML, CSS, JS ๋ฑ์ ์์๋ก ์ ์ฅํด๋๋ ๊ณต๊ฐ์ด๋ค.
์น์ฌ์ดํธ์ ์ฒ์ ๋ฐฉ๋ฌธํ๋ฉด ๋ธ๋ผ์ฐ์ ๋ ํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํ ๋ค์ํ ๋ฆฌ์์ค๋ฅผ ๋ค์ด๋ก๋ํ๋ค.
์ด๋ ๋ธ๋ผ์ฐ์ ๋ ๋ค์ ๋ฒ ๋ฐฉ๋ฌธ ์ ๊ฐ์ ํ์ผ์ ๋ค์ ์์ฒญํ์ง ์๊ธฐ ์ํด, ๋จผ์ ์บ์์ ํด๋น ๋ฆฌ์์ค๊ฐ ์๋์ง ํ์ธํ๋ค.
์ฆ, ์บ์์ ํด๋น ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ๋ธ๋ผ์ฐ์ ๋ ๋ค์ ๋ค์ด๋ก๋ํ์ง ์๊ณ ๋ฐ๋ก ๋ถ๋ฌ์ค๊ธฐ ๋๋ฌธ์ ๋ก๋ฉ ์๊ฐ์ด ๋จ์ถ๋๋ค.
๐ Next.js์์ Image Cache ํ๊ธฐ
Next.js ๊ณต์ ๋ฌธ์๋ฅผ ๋ณด๋ฉด, Next.js๋ immutable assets
์ ๋ํด ์๋์ ๊ฐ์ Cache-Control
ํค๋๋ฅผ ์๋์ผ๋ก ์ค์ ํ๋ค๊ณ ์ค๋ช
ํ๋ค.
์ด๊ฑธ ๋ณด๊ณ ๋ โ์ด? ๊ทธ๋ฌ๋ฉด ๋ฐ๋ก ์ค์ ์ ํด๋ ๋๋ ๊ฑฐ ์๋?โ ๋ผ๊ณ ์๊ฐํ ์ ์์ง๋ง, ์ฌ์ค์ โ์ด๋ป๊ฒ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ค๋๊ฐโ์ ๋ฐ๋ผ ์ ์ฉ ์ฌ๋ถ๊ฐ ๋ฌ๋ผ์ง๋ค.
๐ ์ฐธ๊ณ ์ฌํญ
Next.js๋ next/image
์ปดํฌ๋ํธ๋ฅผ ์ด์ฉํด static image๋ฅผ ๊ฐ์ ธ์ฌ ๊ฒฝ์ฐ, Cache-Control: public, max-age=31536000, immutable
์ ์๋ ์ค์ ํ๋ค.
์ด๋ฐ ๊ฒฝ์ฐ์๋ ํ์ผ๋ช ์ SHA ํด์๊ฐ ํฌํจ๋๊ธฐ ๋๋ฌธ์, ํ์ผ ๋ด์ฉ์ด ๋ฐ๋๋ฉด ์ด๋ฆ๋ ๋ฐ๋๊ฒ ๋๊ณ , ์ค๋ ์บ์ํด๋ ๋ฌธ์ ์์ด ์์ ์ ์ผ๋ก ์ ์งํ ์ ์๋ค.
ํ์ง๋ง /public/images/profile.svg
์ ๊ฐ์ ์ง์ ๊ฒฝ๋ก ๊ธฐ๋ฐ์ ์ ์ ์ด๋ฏธ์ง ์ ๊ทผ (<img src="/images/xxx.svg" />
)์๋ ์๋์ผ๋ก Cache-Control
์ด ์ ์ฉ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ด ๊ฒฝ์ฐ์๋ ์ง์ ํค๋๋ฅผ ์ค์ ํด์ค์ผ ํ๋ค.
๐ฅ ์์
Next.js์์๋ next.config.js
์์ headers()
์ค์ ์ ํตํด ํน์ ๊ฒฝ๋ก์ ๋ํ ์ปค์คํ
HTTP ํค๋๋ฅผ ์ง์ ์ง์ ํ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module.exports = {
async headers() {
return [
{
source: '/about',
headers: [
{
key: 'x-custom-header',
value: 'my custom header value',
},
{
key: 'x-another-custom-header',
value: 'my other custom header value',
},
],
},
];
},
};
๐ซ ๋ฌธ์ ์ํฉ
๊ทธ๋ฐ๋ฐ ์์ฒ๋ผ ์บ์๋ฅผ ์ ์ฉํ๊ณ ์ ํ์ ๋ ์๋์น ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
๋๋ /public
ํด๋ ๋ฐ๋ก ์๋์ ๋ชจ๋ static assets(image)์ ๋ณด๊ดํ๊ณ ์์๊ธฐ ๋๋ฌธ์, public ํด๋ /
์ ๋ชจ๋ ๋ด์ฉ์ ์บ์ ํค๋๋ฅผ ์ ์ฉํ๋ ค๊ณ ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
];
}
๊ทธ๋ฐ๋ฐ ์ด ์ค์ ์ ์ ์ฉํ๋โฆ ์ด๋ฏธ์ง๊ฐ ์์ ๋ก๋ฉ๋์ง ์๊ณ , ๋ก๊ทธ์ธ๋ ์๋ํ์ง ์๋ ์ฌ๊ฐํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ์๊ณ ๋ณด๋ ์ด ์ค์ ์ ๋ง ๊ทธ๋๋ก ๋ชจ๋ ๊ฒฝ๋ก/
์ ๋งค์นญ๋๊ธฐ ๋๋ฌธ์, ์ ์ ํ์ผ๋ฟ ์๋๋ผ ํ์ด์ง ๋ผ์ฐํธ๋ API๊น์ง ๋ชจ๋ ์บ์๋์ด ์๋์น ์์ ์ํฉ์ด ๋ฐ์ํ ๊ฒ์ด์๋ค.
๐ค ํด๊ฒฐ ๋ฐฉ๋ฒ
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด /public/images
ํด๋๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด ์ด๋ฏธ์ง๋ค์ ์ฎ๊ธด ๋ค source
๋ฅผ ์๋์ ๊ฐ์ด ์์ฑํด์ฃผ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
async headers() {
return [
{
source: '/images/:path*',
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
],
},
];
}
โ ๊ฒฐ๊ณผ
์ด์ /public/images/profile.svg
ํ์ผ์ network ํญ์์ ํ์ธํ์ ๋, ์์ฑํ๋ ๋ด์ฉ ๊ทธ๋๋ก ํ์๋๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
์๋ต ์ฝ๋: 200 OK
ํค๋: Cache-Control: public, max-age=31536000, immutable