๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • What would life be If we had no courage to attemp anything?
Development/Next.js

[Next.js] ์„ฑ๋Šฅ ์ตœ์ ํ™” - ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๋ฅผ ์ค„์ด๋Š” ๋ฐฐ๋Ÿด ํŒŒ์ผ ๊ด€๋ฆฌ ์ „๋žต

by DevIseo 2026. 2. 13.

ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋กœ์ ํŠธ์˜ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด ์šฐ๋ฆฌ๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ '๊น”๋”ํ•œ ์ฝ”๋“œ'๋ฅผ ๊ณ ๋ฏผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ๊ณผ์ •์—์„œ ์ˆ˜์‹ญ ๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•œ๊ณณ์— ๋ชจ์•„ ๋‚ด๋ณด๋‚ด๋Š” ๋ฐฐ๋Ÿด ํŒŒ์ผ(Barrel File) ํŒจํ„ด์„ ํ”ํžˆ ์‚ฌ์šฉํ•˜๊ณค ํ•˜์ฃ . ํ•˜์ง€๋งŒ ์ด ํŽธ๋ฆฌํ•จ ๋’ค์—๋Š” ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ์™€ ์„ฑ๋Šฅ์„ ๊ฐ‰์•„๋จน๋Š” ์น˜๋ช…์ ์ธ ํ•จ์ •์ด ์ˆจ์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ค๋Š˜์€ ๋ฐฐ๋Ÿด ํŒŒ์ผ์ด ์™œ ์„ฑ๋Šฅ์˜ ์ ์ด ๋˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ด๋ฏธ ์ปค์ ธ๋ฒ„๋ฆฐ ํ”„๋กœ์ ํŠธ์—์„œ Next.js์˜ optimizePackageImports๋ฅผ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ ์šฐ์•„ํ•˜๊ฒŒ ํƒˆ์ถœํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
 
 
 

1. ๋ฐฐ๋Ÿด ํŒŒ์ผ(Barrel File)์ด๋ž€?

๋ฐฐ๋Ÿด ํŒŒ์ผ์€ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์„ ํ•˜๋‚˜์˜ index.ts ํŒŒ์ผ๋กœ ๋ชจ์•„์„œ ๋‹ค์‹œ ๋‚ด๋ณด๋‚ด๋Š”(Re-export) ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

// components/index.ts (๋ฐฐ๋Ÿด ํŒŒ์ผ)
export { default as Button } from './Button';
export { default as Card } from './Card';
export { default as Modal } from './Modal';

 
์‚ฌ์šฉํ•˜๋Š” ์ชฝ์—์„œ๋Š” ๊ฒฝ๋กœ๊ฐ€ ์งง์•„์ ธ์„œ ๋ณด๊ธฐ ์ข‹์Šต๋‹ˆ๋‹ค.

import { Button } from '@/components'; // ๊น”๋”!

 
 

2. ์™œ ๋ฐฐ๋Ÿด ํŒŒ์ผ์„ ์ง€์–‘ํ•ด์•ผ ํ• ๊นŒ?

๋ฐฐ๋Ÿด ํŒŒ์ผ์€ index.ts์—์„œ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์„ exportํ•˜์—ฌ ๊ฒฝ๋กœ๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์ด 'ํ•„์š”ํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๊นŒ์ง€ ํ•ด์„ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š”' ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค.
 

โ‘  ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„์˜ ์—ฐ์‡„ ํญ๋ฐœ

๋‚ด๊ฐ€ Button ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ๋ฐฐ๋Ÿด ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜๋Š” ์ˆœ๊ฐ„, ๋ฒˆ๋“ค๋Ÿฌ๋Š” ํ•ด๋‹น ํŒŒ์ผ์— ์—ฐ๊ฒฐ๋œ Card, Modal์€ ๋ฌผ๋ก ์ด๊ณ , ๊ทธ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฌด๊ฑฐ์šด ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค๊นŒ์ง€ ๋ชจ๋‘ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์˜์กด์„ฑ ๊ทธ๋ž˜ํ”„๋ฅผ ๋น„์ •์ƒ์ ์œผ๋กœ ํฌ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

โ‘ก ํŠธ๋ฆฌ ์…ฐ์ดํ‚น(Tree Shaking)์˜ ํ•œ๊ณ„

React ๊ณต์‹ ๋ฌธ์„œ์™€ ๊ด€๋ จ ์ƒํƒœ๊ณ„์—์„œ๋Š” ํŠธ๋ฆฌ ์…ฐ์ดํ‚น์ด ๋ชจ๋“  ์ƒํ™ฉ์—์„œ ์™„๋ฒฝํ•˜์ง€ ์•Š์Œ์„ ์‹œ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— sideEffects: false ์„ค์ •์ด ๋ˆ„๋ฝ๋˜์–ด ์žˆ๊ฑฐ๋‚˜ ๋ณต์žกํ•œ ์ฐธ์กฐ๊ฐ€ ์–ฝํ˜€ ์žˆ๋‹ค๋ฉด, ๋ฒˆ๋“ค๋Ÿฌ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ฝ”๋“œ๊นŒ์ง€ "ํ˜น์‹œ ๋ชจ๋ฅด๋‹ˆ" ๋ฒˆ๋“ค์— ํฌํ•จํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

โ‘ข ๊ฐœ๋ฐœ ํ™˜๊ฒฝ(HMR) ๋ฐ ํ…Œ์ŠคํŠธ ์„ฑ๋Šฅ ์ €ํ•˜

ํŒŒ์ผ ํ•˜๋‚˜๋งŒ ์ˆ˜์ •ํ•ด๋„ ๋ฐฐ๋Ÿด ํŒŒ์ผ๊ณผ ์—ฐ๊ฒฐ๋œ ์ˆ˜๋ฐฑ ๊ฐœ์˜ ๋ชจ๋“ˆ ๊ด€๊ณ„๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Fast Refresh(HMR) ์†๋„๋ฅผ ๋Šฆ์ถ”๊ณ , ์œ ๋‹› ํ…Œ์ŠคํŠธ ์‹œ์—๋„ ๋ถˆํ•„์š”ํ•œ ๋ชจ๋“ˆ์„ ๋กœ๋“œํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ „์ฒด์ ์ธ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ ๋–จ์–ด๋œจ๋ฆฝ๋‹ˆ๋‹ค.
 
 
 

3. ์‹ค์ „ ํ•ด๊ฒฐ์ฑ…: Next.js์˜ optimizePackageImports

๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์ง์ ‘ ๊ฒฝ๋กœ(Direct Import)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ, ์ด๋ฏธ ์ˆ˜๋งŒ ์ค„์˜ ์ฝ”๋“œ๊ฐ€ ๋ฐฐ๋Ÿด ํŒŒ์ผ์„ ์“ฐ๊ณ  ์žˆ๋‹ค๋ฉด ์ผ์ผ์ด ์ˆ˜์ •ํ•˜๊ธฐ๋ž€ ๋ถˆ๊ฐ€๋Šฅ์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. ์ด๋•Œ Next.js 13.5+์—์„œ ๋„์ž…๋œ optimizePackageImports๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.



์ž๋™ ๊ฒฝ๋กœ ๋ณ€ํ™˜ (Automatic Mapping)

Next.js ๊ณต์‹ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด, ์ด ์˜ต์…˜์€ ๋นŒ๋“œ ์‹œ์ ์— ๋ฐฐ๋Ÿด ํŒŒ์ผ์„ ๊ฑฐ์น˜์ง€ ์•Š๋„๋ก ์ž„ํฌํŠธ ๊ตฌ๋ฌธ์„ ์ง์ ‘ ๊ฒฝ๋กœ๋กœ ์ž๋™ ์žฌ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ์ž ์ฝ”๋“œ: import { Button } from '@/components'
  • ์ปดํŒŒ์ผ ํ›„: import { Button } from '@/components/Button/Button.tsx' (์ž๋™ ๋ณ€ํ™˜)



์„ค์ • ๋ฐฉ๋ฒ• (next.config.js)

์ฃผ๋กœ ์•„์ด์ฝ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ์ž์ฒด UI ํ‚คํŠธ์ฒ˜๋Ÿผ ๋ชจ๋“ˆ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์€ ํŒจํ‚ค์ง€๋ฅผ ๋“ฑ๋กํ•  ๋•Œ ํšจ๊ณผ๊ฐ€ ๋“œ๋ผ๋งˆํ‹ฑํ•ฉ๋‹ˆ๋‹ค.

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    // ๋ฐฐ๋Ÿด ํŒŒ์ผ ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ๋ฆฌ์ŠคํŠธ ๋“ฑ๋ก
    optimizePackageImports: ['@my-project/ui', 'heavy-icons-lib'],
  },
}

module.exports = nextConfig

 
 

4. ์š”์•ฝ ๋ฐ ๊ถŒ์žฅ ์‚ฌํ•ญ

๊ธฐ์ˆ ์  ๋ถ€์ฑ„๋ฅผ ํ”ผํ•˜๊ณ  ์„ฑ๋Šฅ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ์˜ ๊ฐ€์ด๋“œ๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

  1. ๊ฐ€๊ธ‰์  ์ง์ ‘ ์ฐธ์กฐํ•˜์„ธ์š”: ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด import Button from '@/components/Button'์ฒ˜๋Ÿผ ๋ช…ํ™•ํ•œ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์Šต๊ด€์„ ๋“ค์ด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  2. ๊ณต์‹ ๋ฌธ์„œ์˜ ๋„์›€์„ ๋ฐ›์œผ์„ธ์š”: Next.js๋Š” lucide-react, @mui/material ๋“ฑ ์ฃผ์š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด ์ด ์ตœ์ ํ™”๋ฅผ ์ด๋ฏธ ๊ธฐ๋ณธ์œผ๋กœ ์ ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์“ฐ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ํ•ด๋‹น๋˜๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์„ธ์š”.
  3. ESLint๋ฅผ ํ™œ์šฉํ•˜์„ธ์š”: no-restricted-imports ๊ทœ์น™์„ ์„ค์ •ํ•˜์—ฌ ํŒ€์›๋“ค์ด ๋ฌด๋ถ„๋ณ„ํ•˜๊ฒŒ ๋ฐฐ๋Ÿด ํŒŒ์ผ์˜ ์ž…๊ตฌ(index)๋ฅผ ์ฐธ์กฐํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

5. ์‹ค์ „ ์ ์šฉ ์‚ฌ๋ก€

์ด๋ก ์„ ๋„˜์–ด ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— optimizePackageImports๋ฅผ ์ ์šฉํ–ˆ์„ ๋•Œ ์–ด๋–ค ๋ณ€ํ™”๊ฐ€ ์žˆ๋Š”์ง€ ์ˆ˜์น˜๋กœ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์ตœ์ ํ™”๋Š” ์‚ฌ๋‚ด ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋ฌด๊ฑฐ์šด ์™ธ๋ถ€ ํŒจํ‚ค์ง€(lodash, monaco-editor ๋“ฑ)๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.
 

์ ์šฉ ์ฝ”๋“œ (next.config.js)

์ฃผ๋กœ ๋ฐฐ๋Ÿด ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„ ์‚ฌ๋‚ด ์ปดํฌ๋„ŒํŠธ ํŒจํ‚ค์ง€์™€ ํฌ๊ธฐ๊ฐ€ ํฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์ตœ์ ํ™” ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
 

// next.config.js
const nextConfig = {
  experimental: {
    optimizePackageImports: [
      '@์‚ฌ๋‚ด์ปดํฌ๋„ŒํŠธ',
      'lodash',
      'moment',
      'monaco-editor/react',
      'monaco-editor',
    ],
  },
}



์ตœ์ ํ™” ๊ฒฐ๊ณผ (First Load JS)

๊ฒฐ๊ณผ๋Š” ๊ธฐ๋Œ€ ์ด์ƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ณตํ†ต์œผ๋กœ ๋กœ๋“œ๋˜๋Š” _app.js์˜ ํฌ๊ธฐ๊ฐ€ ๋“œ๋ผ๋งˆํ‹ฑํ•˜๊ฒŒ ์ค„์–ด๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•ญ๋ชฉ์ตœ์ ํ™” ์ „์ตœ์ ํ™” ํ›„์ ˆ๊ฐ๋ฅ 

 

๊ฒฐ๊ณผ ๋ถ„์„

  • _app.js์˜ ๋ณ€ํ™”: ์ „์—ญ์—์„œ ์ฐธ์กฐํ•˜๋˜ ๋ฐฐ๋Ÿด ํŒŒ์ผ๋“ค์ด ์ง์ ‘ ์ฐธ์กฐ ๋ฐฉ์‹์œผ๋กœ ์ตœ์ ํ™”๋˜๋ฉด์„œ, ์ดˆ๊ธฐ ๋กœ๋”ฉ ์‹œ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ํฌํ•จ๋˜์—ˆ๋˜ ์ฝ”๋“œ๋“ค์ด ๋Œ€๊ฑฐ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๊ฐœ์„ : ๊ณตํ†ต ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๊ฐ€ 289kB๋‚˜ ์ค„์–ด๋“ค์—ˆ๋‹ค๋Š” ๊ฒƒ์€ ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์ฒซ ํŽ˜์ด์ง€๋ฅผ ์ง„์ž…ํ•  ๋•Œ ๋‹ค์šด๋กœ๋“œํ•ด์•ผ ํ•  JS ์šฉ๋Ÿ‰์ด ์ ˆ๋ฐ˜ ์ด์ƒ ๊ฐ€๋ฒผ์›Œ์กŒ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฒด๊ฐ ๋กœ๋”ฉ ์†๋„๋Š” ํ›จ์”ฌ ๋นจ๋ผ์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

 
์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด ๋ณธ ๊ฒฐ๊ณผ, optimizePackageImports๋Š” ๋‹จ์ˆœํžˆ ์ด๋ก ์ ์ธ ์ตœ์ ํ™”๊ฐ€ ์•„๋‹ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์„ค์ • ๋ช‡ ์ค„๋งŒ์œผ๋กœ ๊ณตํ†ต ๋ฒˆ๋“ค ์‚ฌ์ด์ฆˆ๋ฅผ 56%๋‚˜ ์ค„์ธ ์ˆ˜์น˜๊ฐ€ ๊ทธ ํšจ์šฉ์„ฑ์„ ์ฆ๋ช…ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋™์•ˆ ๋ฐฐ๋Ÿด ํŒŒ์ผ์˜ ํŽธ๋ฆฌํ•จ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์„ ํฌ๊ธฐํ•˜๊ณ  ๊ณ„์…จ๋‚˜์š”? ์•„๋‹ˆ๋ฉด ๊ฑฐ๋Œ€ํ•ด์ง„ ์˜์กด์„ฑ ๋•Œ๋ฌธ์— ์—„๋‘๋ฅผ ๋‚ด์ง€ ๋ชปํ•˜๊ณ  ๊ณ„์…จ๋‚˜์š”?
์ด์ œ Next.js์˜ ์Šค๋งˆํŠธํ•œ ์ตœ์ ํ™” ๊ธฐ๋Šฅ์„ ๋นŒ๋ ค, ๊ฐœ๋ฐœ ๊ฒฝํ—˜(DX)๊ณผ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(UX) ๋‘ ๋งˆ๋ฆฌ ํ† ๋ผ๋ฅผ ๋ชจ๋‘ ์žก์•„๋ณด์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

์ฐธ๊ณ  ์ž๋ฃŒ

๋Œ“๊ธ€