๐Ÿ”ฅ Trouble Shooting - Next.js ํ™˜๊ฒฝ๋ณ€์ˆ˜์™€ ์ด๋ฏธ์ง€ ์„ค์ • ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

์Š˜ยท2025๋…„ 3์›” 11์ผ

๐Ÿ”ฅ Trouble Shooting

๋ชฉ๋ก ๋ณด๊ธฐ
11/23

๐Ÿ’ป Next.js ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉ๋ฒ•

์˜ค๋Š˜ Next.js ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉ ๋ฐฉ์‹์— ๋Œ€ํ•ด ๋‹ค์‹œ ํ•œ๋ฒˆ ํ™•์ธํ–ˆ๋‹ค. Vite๋‚˜ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” import.meta.env๋กœ ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜์ง€๋งŒ, Next.js์—์„œ๋Š” process.env๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

// โŒ ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ• (Vite ์Šคํƒ€์ผ)
const apiUrl = import.meta.env.VITE_API_URL;

// โœ… Next.js์—์„œ์˜ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•
const apiUrl = process.env.NEXT_PUBLIC_API_URL;

๋˜ํ•œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ NEXT_PUBLIC_ ์ ‘๋‘์‚ฌ๋ฅผ ๋ถ™์—ฌ์•ผ ํ•œ๋‹ค. ์ด ์ ‘๋‘์‚ฌ๊ฐ€ ์—†๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค.

๐Ÿšจ ๋ฌธ์ œ์ƒํ™ฉ : next/image ์ปดํฌ๋„ŒํŠธ ์˜ค๋ฅ˜: "๊ตฌ์„ฑ๋˜์ง€ ์•Š์€ ํ˜ธ์ŠคํŠธ"

์˜ค๋Š˜ ๋ฐœ์ƒํ•œ ์ฃผ์š” ์ด์Šˆ๋Š” next/image ์ปดํฌ๋„ŒํŠธ ๊ด€๋ จ ์˜ค๋ฅ˜์˜€๋‹ค. League of Legends API์—์„œ ์ฑ”ํ”ผ์–ธ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค:

Error: Invalid src prop (https://ddragon.leagueoflegends.com/cdn/15.5.1/img/champion/Aatrox.png) on `next/image`, hostname "ddragon.leagueoflegends.com" is not configured under images in your `next.config.js`

Next.js์—์„œ๋Š” ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋Š” ์™ธ๋ถ€ ๋„๋ฉ”์ธ์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์–ด๋–ค ์™ธ๋ถ€ ๋„๋ฉ”์ธ์˜ ์ด๋ฏธ์ง€๋„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

โœ… ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: next.config.js ์„ค์ •ํ•˜๊ธฐ

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด next.config.js ํŒŒ์ผ์— images.remotePatterns ์„ค์ •์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค:

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "ddragon.leagueoflegends.com",
        port: "",
        pathname: "/cdn/**",
        search: "",
      },
    ],
  },
};

export default nextConfig;

์ด ์„ค์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์„ ํฌํ•จํ•œ๋‹ค:

  • protocol: ์ด๋ฏธ์ง€ URL์˜ ํ”„๋กœํ† ์ฝœ (http ๋˜๋Š” https)
  • hostname: ์ด๋ฏธ์ง€ ์„œ๋ฒ„์˜ ํ˜ธ์ŠคํŠธ๋ช…
  • port: ์‚ฌ์šฉํ•  ํฌํŠธ (๋น„์›Œ๋‘๋ฉด ๊ธฐ๋ณธ ํฌํŠธ)
  • pathname: ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ ํŒจํ„ด (**๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™€์ผ๋“œ์นด๋“œ ์ง€์ • ๊ฐ€๋Šฅ)
  • search: ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ (๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋น„์›Œ๋‘ )

์„ค์ • ํ›„์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด next/image ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค:

import Image from 'next/image';

function ChampionCard({ championName }) {
  return (
    <div>
      <Image
        src={`https://ddragon.leagueoflegends.com/cdn/15.5.1/img/champion/${championName}.png`}
        alt={championName}
        width={120}
        height={120}
      />
      <h3>{championName}</h3>
    </div>
  );
}

๐Ÿ“ ๋ฐฐ์šด ์ 

  1. Next.js์—์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” process.env๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•˜๋ฉฐ, ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉํ•˜๋ ค๋ฉด NEXT_PUBLIC_ ์ ‘๋‘์‚ฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  2. next/image ์ปดํฌ๋„ŒํŠธ๋Š” ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ๊ธฐ๋ณธ์ ์œผ๋กœ ์™ธ๋ถ€ ์ด๋ฏธ์ง€๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

  3. ์™ธ๋ถ€ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด next.config.js์— images.remotePatterns ์„ค์ •์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

  4. ์ด๋Ÿฌํ•œ ๋ณด์•ˆ ์„ค์ •์€ ๊ท€์ฐฎ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ์‚ฌ์ดํŠธ์˜ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•˜๊ณ  ์•…์˜์ ์ธ ์ด๋ฏธ์ง€ ์‚ฝ์ž…์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.

์•ž์œผ๋กœ Next.js ํ”„๋กœ์ ํŠธ์—์„œ ์™ธ๋ถ€ API์˜ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•ญ์ƒ next.config.js์— ํ•ด๋‹น ๋„๋ฉ”์ธ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋ง์•„์•ผ๊ฒ ๋‹ค.

๐Ÿ’ก ์ถ”๊ฐ€ TIP

NextJs ๊ณต์‹๋ฌธ์„œ - next-image-unconfigured-host

profile
์ฃผ๋‹ˆ์–ด ํ”„๋ก ํŠธ์—”๋“œ ์„ฑ์žฅ๊ธฐ ๊ธฐ๋ก๊ธฐ๋ก

0๊ฐœ์˜ ๋Œ“๊ธ€