๐Ÿ“ฅ npm install ์™„์ „ ํ•ด๋ถ€ โ€” lock ํŒŒ์ผ, node_modules, npm ci

2026๋…„ 3์›” 5์ผ ์ˆ˜์ •๋จ

๐Ÿ“‹ ๊ฐœ์š”

npm install ์˜ ๋‚ด๋ถ€ ๋™์ž‘, package-lock.json ์˜ ๊ตฌ์กฐ์™€ ์—ญํ• , node_modules ํ˜ธ์ด์ŠคํŒ… ์›๋ฆฌ, npm ci ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๋ฅผ ์™„๋ฒฝํžˆ ์ดํ•ดํ•œ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ


๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 20๋ถ„(์ „์ฒด) / ํ•ต์‹ฌ ํŒŒํŠธ๋งŒ: 8๋ถ„ (lock ํŒŒ์ผ + npm ci)

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ํ๋ฆ„
lock ํŒŒ์ผ ๊ตฌ์กฐ ์ดํ•ด โ†’ npm install vs npm ci โ†’ node_modules ํ˜ธ์ด์ŠคํŒ… โ†’ ํŒฌํ…€ ์˜์กด์„ฑ ํ•จ์ • โ†’ .npmrc ์„ค์ •

๐ŸŽฏ ์ด ๋ฌธ์„œ๋ฅผ ๋‹ค ์ฝ์œผ๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • package-lock.json ์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ์ฝ๊ณ  integrity ํ•„๋“œ๊ฐ€ ๋ฌด์—‡์„ ๋ณด์žฅํ•˜๋Š”์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค
  • npm install ๊ณผ npm ci ์˜ ๊ฒฐ์ •์  ์ฐจ์ด๋ฅผ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์„ ํƒํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค
  • node_modules ์˜ ํ”Œ๋žซ ๊ตฌ์กฐ์™€ ํ˜ธ์ด์ŠคํŒ… ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•œ๋‹ค
  • ํŒฌํ…€ ์˜์กด์„ฑ์ด ๋ฌด์—‡์ด๊ณ  ์™œ ์œ„ํ—˜ํ•œ์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค
  • .npmrc ๋กœ engine-strict, save-exact ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

  • ๐Ÿฃ ์˜์ฒ  ( ์‹ ์ž… ): "๋ฆฌ๋“œ ๋‹˜, CI ์—์„œ ๊ณ„์† ๋นŒ๋“œ๊ฐ€ ์‹คํŒจํ•ด์š”. ๋กœ์ปฌ์—์„œ๋Š” ์™„๋ฒฝํ•œ๋ฐ... GitHub Actions ๋กœ๊ทธ ๋ณด๋‹ˆ๊นŒ npm install ํ•  ๋•Œ๋งˆ๋‹ค ๋ฒ„์ „์ด ์กฐ๊ธˆ์”ฉ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ ๊ฐ™์•„์š”. ๊ทธ๋ฆฌ๊ณ  package-lock.json ์ด ์—„์ฒญ ๊ธธ์–ด์„œ ๋ญ” ๋‚ด์šฉ์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์–ด์š”. ์ฝ์–ด์•ผ ํ•˜๋‚˜์š”? ๊ทธ๋ƒฅ ์ž๋™ ์ƒ์„ฑ์ด๋‹ˆ๊นŒ ์‹ ๊ฒฝ ์•ˆ ์จ๋„ ๋˜๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€์š”?"
  • ๐Ÿฆ ์˜ํ˜ธ ( ๋ฆฌ๋“œ ): "์˜์ฒ  ๋‹˜, CI ์—์„œ npm install ๋Œ€์‹  npm ci ๋ฅผ ์จ์•ผ ํ•ด์š”. npm install ์€ lock ํŒŒ์ผ์„ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋งค ๋นŒ๋“œ๋งˆ๋‹ค ์กฐ๊ธˆ์”ฉ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”. package-lock.json ์€ ์ฝ์„ ํ•„์š”๋Š” ์—†์ง€๋งŒ, ์ด๊ฒŒ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ์•„์•ผ ์™œ CI ์—์„œ npm ci ๋ฅผ ์จ์•ผ ํ•˜๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์–ด์š”."

๐Ÿค” ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€

"์ œ ๋กœ์ปฌ์—์„œ๋Š” ๋˜๋Š”๋ฐ CI ์—์„œ๋งŒ ์•ˆ ๋ผ์š”" โ€” ๊ฐœ๋ฐœ์ž ์„ธ๊ณ„์—์„œ ๊ฐ€์žฅ ๊ณ ํ†ต์Šค๋Ÿฌ์šด ๋ฌธ์žฅ ์ค‘ ํ•˜๋‚˜๋‹ค.

์˜์ˆ˜๋„ค ํŒ€์ด ๋ฐฐํฌ ์ „๋‚  ๋ฐค์— ์ด ์ƒํ™ฉ์„ ๋งŒ๋‚ฌ๋‹ค. ์˜์ฒ ์ด ๋กœ์ปฌ์—์„œ๋Š” ๋นŒ๋“œ๊ฐ€ ์™„๋ฒฝํ•œ๋ฐ, GitHub Actions ์—์„œ๋Š” ๊ณ„์† ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค. ์›์ธ์„ ์ฐพ์•„๋ณด๋‹ˆ ๋กœ์ปฌ์˜ typescript@5.2.0 ๊ณผ CI ์˜ typescript@5.3.3 ์ด ๋‹ฌ๋ž๋‹ค. CI ์—์„œ npm install ์„ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค lock ํŒŒ์ผ์ด ์—†์–ด์„œ ๊ทธ๋•Œ๊ทธ๋•Œ ์ตœ์‹  ๋ฒ„์ „์„ ๊ฐ€์ ธ์™”๋˜ ๊ฒƒ์ด๋‹ค.

package-lock.json ๊ณผ npm ci ๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋ฉด ์ด๋Ÿฐ ์ผ์€ ์ ˆ๋Œ€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค.


๐Ÿ”’ package-lock.json ์˜ ๊ตฌ์กฐ์™€ ์—ญํ• 

ํ•ต์‹ฌ ์—ญํ•  โ€” ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋นŒ๋“œ ๋ณด์žฅ

package.json     = "์˜๋„" โ€” react@^18.2.0 ๋ฒ”์œ„๋ฉด ๋จ
package-lock.json = "๊ณต์ฆ" โ€” ์˜ค๋Š˜ 18.2.0 ์„ ์„ค์น˜ํ–ˆ๊ณ , ์ด tarball ์˜ ํ•ด์‹œ๊ฐ’์€ xxx ์ž„

lock ํŒŒ์ผ์˜ ์‹ค์ œ ๊ตฌ์กฐ

{
  "name": "youngsoo-community",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "youngsoo-community",
      "version": "1.0.0",
      "dependencies": {
        "react": "^18.2.0"
      }
    },
    // ๐Ÿ’ก node_modules ์•ˆ์— ์‹ค์ œ๋กœ ์–ด๋–ค ํŒŒ์ผ์ด ๋“ค์–ด๊ฐ”๋А๋ƒ! ํ•˜๋Š” ์‹ค๋ฌผ ์žฅ๋ถ€์ž…๋‹ˆ๋‹ค.
    "node_modules/react": {
      "version": "18.2.0", // ๐Ÿฆ ^18.2.0 ๋ฒ”์œ„ ์ค‘์—์„œ "์ •ํ™•ํžˆ ์ด ๋ฒ„์ „"์„ ๊น”์•˜๋‹ค๊ณ  ๋ช…์‹œํ•ฉ๋‹ˆ๋‹ค.
      "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
      // [์ดˆํ•ต์‹ฌ] ์ด ํŒŒ์ผ์˜ ์ง€๋ฌธ(ํ•ด์‹œ๊ฐ’)์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ์ด 1๋ฐ”์ดํŠธ๋ผ๋„ ๋‹ค๋ฅด๋ฉด ์—ฌ๊ธฐ์„œ ๊ฑธ๋Ÿฌ์ง‘๋‹ˆ๋‹ค.
      "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fA==",
      "engines": {
        "node": ">=0.10.0"
      }
    }
  }
}
ํ•„๋“œ์˜๋ฏธ
lockfileVersionlock ํŒŒ์ผ ํฌ๋งท ๋ฒ„์ „ (npm v9+ ๋Š” 3)
version์‹ค์ œ๋กœ ์„ค์น˜๋œ ์ •ํ™•ํ•œ ๋ฒ„์ „
resolvedtarball ์„ ๋ฐ›์•„์˜จ URL
integritySHA-512 ํ•ด์‹œ๊ฐ’ โ€” ํŒŒ์ผ ์œ„๋ณ€์กฐ ์—ฌ๋ถ€ ๊ฒ€์ฆ

๐Ÿ” integrity ์˜ ์—ญํ• : ์•…์˜์ ์ธ ๊ณต๊ฒฉ์ž๊ฐ€ npm ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ฅผ ์กฐ์ž‘ํ•ด ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์ฃผ์ž…ํ•˜๋”๋ผ๋„, integrity ํ•ด์‹œ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด npm ์ด ์„ค์น˜๋ฅผ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ์ด๊ฒƒ์ด ๊ณต๊ธ‰๋ง ๊ณต๊ฒฉ(supply chain attack) ์„ ๋ง‰๋Š” ์ฒซ ๋ฒˆ์งธ ๋ฐฉ์–ด์„ ์ด๋‹ค.

lock ํŒŒ์ผ ๋ฒ„์ „ ํ˜ธํ™˜์„ฑ

lockfileVersionnpm ๋ฒ„์ „์ฃผ์˜์‚ฌํ•ญ
1npm v5, v6๊ตฌ๋ฒ„์ „
2npm v7, v8v1 ํ•˜์œ„ ํ˜ธํ™˜
3npm v9+v2 ํ•˜์œ„ ํ˜ธํ™˜

ํŒ€์› ์ค‘ npm ๋ฒ„์ „์ด ๋‹ค๋ฅด๋ฉด lock ํŒŒ์ผ์ด ๊ณ„์† ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค. .npmrc ๋กœ npm ๋ฒ„์ „์„ ํ†ต์ผํ•˜๊ฑฐ๋‚˜ engines ์— "npm": ">=9.0.0" ์„ ๋ช…์‹œํ•œ๋‹ค.

์ ˆ๋Œ€ ๊ทœ์น™

โœ… package-lock.json  โ†’ ๋ฐ˜๋“œ์‹œ git ์ปค๋ฐ‹
โŒ node_modules/      โ†’ ๋ฐ˜๋“œ์‹œ .gitignore ์ถ”๊ฐ€
# .gitignore
node_modules/
.next/

โš–๏ธ npm install vs npm ci โ€” ๊ฒฐ์ •์  ์ฐจ์ด

npm install

npm install
  • package.json ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘
  • ํ—ˆ์šฉ ๋ฒ„์ „ ๋ฒ”์œ„ ๋‚ด์—์„œ ์ตœ์‹  ๋ฒ„์ „ ์„ ํƒ ๊ฐ€๋Šฅ
  • package-lock.json ์„ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ์Œ
  • ๊ธฐ์กด node_modules ๋ฅผ ์žฌ์‚ฌ์šฉ (์†๋„ ์šฐ์„ )
  • ์‚ฌ์šฉ ์‹œ์ : ๊ฐœ๋ฐœ ์ค‘ ์ƒˆ ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, ๋ฒ„์ „์„ ์˜ฌ๋ฆด ๋•Œ

npm ci

npm ci
  • package-lock.json ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘ (์ •ํ™•ํ•œ ๋ฒ„์ „๋งŒ)
  • package-lock.json ์„ ์ ˆ๋Œ€ ๊ฐฑ์‹ ํ•˜์ง€ ์•Š์Œ (lock ์—†์œผ๋ฉด ์—๋Ÿฌ)
  • ๊ธฐ์กด node_modules ๋ฅผ ์‚ญ์ œ ํ›„ ์ฒ˜์Œ๋ถ€ํ„ฐ ์„ค์น˜
  • ๋” ์—„๊ฒฉํ•˜๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์„ค์น˜
  • ์‚ฌ์šฉ ์‹œ์ : CI/CD ํ™˜๊ฒฝ, Docker ์ด๋ฏธ์ง€ ๋นŒ๋“œ, ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ
              npm install          npm ci
๊ธฐ์ค€ ํŒŒ์ผ    package.json         package-lock.json
lock ๋ณ€๊ฒฝ    ๊ฐ€๋Šฅ                 ๋ถˆ๊ฐ€ (์—๋Ÿฌ ๋ฐœ์ƒ)
lock ์—†์œผ๋ฉด  ์ƒˆ๋กœ ์ƒ์„ฑ            ์—๋Ÿฌ๋กœ ์ข…๋ฃŒ
node_modules ์žฌ์‚ฌ์šฉ              ์‚ญ์ œ ํ›„ ์žฌ์„ค์น˜
์†๋„         ๋ณดํ†ต                 ๋น ๋ฆ„ (์ดˆ๊ธฐํ™” ํ›„ ์บ์‹œ ์‚ฌ์šฉ ์‹œ)
์•ˆ์ •์„ฑ       ๋‚ฎ์Œ                 ๋†’์Œ

๐Ÿ”ฅ ์‹ค๋ฌด ํ™ฉ๊ธˆ ๊ทœ์น™:

  • ๋กœ์ปฌ ๊ฐœ๋ฐœ: npm install
  • CI/CD: ๋ฌด์กฐ๊ฑด npm ci
  • Docker Dockerfile: RUN npm ci --omit=dev
# โœ… GitHub Actions ์˜ฌ๋ฐ”๋ฅธ ์„ค์ •: 'npm install'์€ ์ ˆ๋Œ€ ๊ธˆ์ง€! 'npm ci'๊ฐ€ ์ •๋‹ต์ž…๋‹ˆ๋‹ค.
- name: Install dependencies
  run: npm ci     
 
# โœ… Dockerfile ์˜ฌ๋ฐ”๋ฅธ ์„ค์ •: ํ”„๋กœ๋•์…˜ ์ด๋ฏธ์ง€์—๋Š” ์šฉ๋Ÿ‰ ๋‹ค์ด์–ดํŠธ๋ฅผ ์œ„ํ•ด devDependencies๋ฅผ ๋บ๋‹ˆ๋‹ค.
RUN npm ci --omit=dev    

๐ŸŒณ node_modules ์˜ ๊ตฌ์กฐ โ€” ํ˜ธ์ด์ŠคํŒ…๊ณผ ์ค‘์ฒฉ

npm v3+ ์˜ ํ”Œ๋žซ(Flat) ๊ตฌ์กฐ

npm v2 ์ดํ•˜์—์„œ๋Š” ๋ชจ๋“  ์˜์กด์„ฑ์ด ์ค‘์ฒฉ ๊ตฌ์กฐ๋กœ ์„ค์น˜๋๋‹ค:

# npm v2 (๊ตฌ๋ฒ„์ „ โ€” ์ค‘์ฒฉ ๊ตฌ์กฐ)
node_modules/
  react-dom/
    node_modules/
      react/          โ† react-dom ์˜ react
  next/
    node_modules/
      react/          โ† next ์˜ react (์ค‘๋ณต!)
      react-dom/      โ† next ์˜ react-dom (์ค‘๋ณต!)

์ค‘๋ณต์ด ๋„ˆ๋ฌด ๋งŽ์•„ node_modules ํฌ๊ธฐ๊ฐ€ ํญ๋ฐœ์ ์œผ๋กœ ์ปค์กŒ๋‹ค.

npm v3+ ๋Š” ํ˜ธ์ด์ŠคํŒ…(Hoisting) ์œผ๋กœ ์ด๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค:

# npm v3+ (ํ”Œ๋žซ ๊ตฌ์กฐ โ€” ํ˜ธ์ด์ŠคํŒ…)
node_modules/
  react/              โ† ์ตœ์ƒ์œ„๋กœ ์˜ฌ๋ผ์˜ด (ํ˜ธ์ด์ŠคํŒ…)
  react-dom/          โ† ์ตœ์ƒ์œ„๋กœ ์˜ฌ๋ผ์˜ด
  next/               โ† react ์—†์Œ, ์ƒ์œ„ react ๊ณต์œ 
  some-lib/           โ† react ์—†์Œ, ์ƒ์œ„ react ๊ณต์œ 

๋ชจ๋“  ํŒจํ‚ค์ง€๊ฐ€ react@18.2.0 ์„ ์š”๊ตฌํ•˜๋ฉด ์ตœ์ƒ์œ„์— ํ•˜๋‚˜๋งŒ ๋†“๊ณ  ๋ชจ๋‘ ๊ณต์œ ํ•œ๋‹ค.

๋ฒ„์ „์ด ๋‹ค๋ฅผ ๋•Œ โ€” ์ค‘์ฒฉ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ

node_modules/
  react/               โ† v18.2.0 (ํ˜ธ์ด์ŠคํŒ…)
  old-library/
    node_modules/
      react/           โ† v16.14.0 (old-library ๊ฐ€ 16 ๋ฒ„์ „ ์š”๊ตฌ)

old-library ๊ฐ€ React 16 ์„ ์š”๊ตฌํ•˜๊ณ  ๋ฉ”์ธ ์•ฑ์€ React 18 ์„ ์“ฐ๋ฉด, ๋‘ ๋ฒ„์ „์ด ๊ณต์กดํ•œ๋‹ค. ์ด๊ฒƒ์ด node_modules ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๊ณ  peerDependencies ์ถฉ๋Œ์ด ์ƒ๊ธฐ๋Š” ์›์ธ์ด๋‹ค.


๐Ÿ‘ป ํŒฌํ…€ ์˜์กด์„ฑ โ€” ์„ค์น˜ํ•œ ์  ์—†๋Š”๋ฐ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ด์œ ์™€ ํ•จ์ •

ํ˜ธ์ด์ŠคํŒ…์˜ ๋ถ€์ž‘์šฉ์œผ๋กœ ํŒฌํ…€ ์˜์กด์„ฑ(Phantom Dependency) ์ด ์ƒ๊ธด๋‹ค.

// ๋‚ด package.json
{
  "dependencies": {
    "next": "^14.1.0"
  }
}
// ๋‚ด ์ฝ”๋“œ โ€” ์ง์ ‘ ์„ค์น˜ํ•˜์ง€ ์•Š์€ lodash ๋ฅผ import!
import merge from 'lodash/merge'   // โ† ํŒฌํ…€ ์˜์กด์„ฑ

next ๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ lodash ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, node_modules/lodash ๊ฐ€ ํ˜ธ์ด์ŠคํŒ…์œผ๋กœ ์ตœ์ƒ์œ„์— ์กด์žฌํ•œ๋‹ค. ๋‚ด๊ฐ€ ์„ค์น˜ํ•œ ์  ์—†์–ด๋„ import ๊ฐ€ ๋™์ž‘ํ•œ๋‹ค.

์™œ ์ด๊ฒŒ ์œ„ํ—˜ํ•œ๊ฐ€?

์˜ค๋Š˜: next@14.1.0 ์ด lodash@4.17.21 ์„ ์‚ฌ์šฉ โ†’ ๋‚ด ์ฝ”๋“œ์—์„œ ์“ธ ์ˆ˜ ์žˆ์Œ
๋ฏธ๋ž˜: next@14.2.0 ์ด lodash ์˜์กด์„ฑ ์ œ๊ฑฐ โ†’ ๋‚ด ์ฝ”๋“œ๊ฐ€ ๊ฐ‘์ž๊ธฐ ์—๋Ÿฌ

๋‚ด๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ”๊พธ์ง€ ์•Š์•˜๋Š”๋ฐ ์„œ๋น„์Šค๊ฐ€ ๋ง๊ฐ€์ง

ํ•ด๊ฒฐ: ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ‚ค์ง€๋Š” ๋ฐ˜๋“œ์‹œ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์น˜ํ•œ๋‹ค.

npm install lodash    # ์ง์ ‘ ์„ค์น˜
// package.json ์— ๋ช…์‹œ๋จ
{
  "dependencies": {
    "lodash": "^4.17.21",
    "next": "^14.1.0"
  }
}

๐Ÿ’ก pnpm ์ด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ์‹: pnpm ์€ ํ•˜๋“œ๋งํฌ + ์‹ฌ๋ณผ๋ฆญ ๋งํฌ ๊ตฌ์กฐ๋กœ ํŒฌํ…€ ์˜์กด์„ฑ์„ ์›์ฒœ ์ฐจ๋‹จํ•œ๋‹ค. ๋ช…์‹œ์ ์œผ๋กœ ์„ค์น˜ํ•˜์ง€ ์•Š์€ ํŒจํ‚ค์ง€๋Š” import ์ž์ฒด๊ฐ€ ์—๋Ÿฌ๋‚œ๋‹ค. ๋Œ€๊ทœ๋ชจ ๋ชจ๋…ธ๋ ˆํฌ์—์„œ pnpm ์ด ์„ ํ˜ธ๋˜๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜๋‹ค.


๐Ÿงน node_modules ๊ด€๋ฆฌ ๋ช…๋ น์–ด

# ์ค‘๋ณต ์˜์กด์„ฑ ์ •๋ฆฌ
npm dedupe              # ์ค‘๋ณต ํŒจํ‚ค์ง€๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๊ณต์œ  ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ํ˜ธ์ด์ŠคํŒ…
 
# ํ˜„์žฌ ์„ค์น˜๋œ ํŒจํ‚ค์ง€ ๋ชฉ๋ก
npm list                # ์ „์ฒด ํŠธ๋ฆฌ
npm list --depth=0      # ์ง์ ‘ ์˜์กด์„ฑ๋งŒ
npm list react          # ํŠน์ • ํŒจํ‚ค์ง€ ๋ฒ„์ „ ํ™•์ธ
 
# ์“ธ๋ชจ์—†๋Š” ํŒจํ‚ค์ง€ ์ •๋ฆฌ (package.json ์— ์—†๋Š” ๊ฒƒ ์ œ๊ฑฐ)
npm prune               # ๋ถˆํ•„์š” ํŒจํ‚ค์ง€ ์‚ญ์ œ
npm prune --production  # devDependencies ์‚ญ์ œ (ํ”„๋กœ๋•์…˜ ์ด๋ฏธ์ง€ ์ตœ์ ํ™”)
 
# ํŒจํ‚ค์ง€ ์„ค์น˜ ๊ฒฝ๋กœ ๋””๋ฒ„๊น…
npm explain react       # react ๊ฐ€ ์™œ ์„ค์น˜๋๋Š”์ง€ (์–ด๋–ค ํŒจํ‚ค์ง€๊ฐ€ ์š”๊ตฌํ•˜๋Š”์ง€)

โš™๏ธ .npmrc ๋กœ install ๋™์ž‘ ์ œ์–ด

.npmrc ํŒŒ์ผ์€ npm ์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•œ๋‹ค.

# .npmrc (์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ถŒ์žฅ ์„ค์ •)
 
# ๐Ÿฆ [์‹œ์Šคํ…œ ๋ณดํ˜ธ] Node.js ๋ฒ„์ „์ด ์•ˆ ๋งž์œผ๋ฉด ์•„์˜ˆ ์„ค์น˜ ๋‹จ๊ณ„์—์„œ ์ฐจ๋‹จํ•ด๋ผ!
engine-strict=true
 
# [๋ฒ„์ „ ์—„๊ฒฉ ๊ด€๋ฆฌ] ์„ค์น˜ํ•  ๋•Œ package.json์— ์ž๋™์œผ๋กœ ^ ๊ธฐํ˜ธ๋ฅผ ๋ถ™์ด์ง€ ๋ง๊ณ , ์ •ํ™•ํ•œ ๋ฒ„์ „๋งŒ ์ ์–ด๋ผ!
save-exact=true
 
# peerDependencies ์ถฉ๋Œ์ด ๋‚˜๋ฉด ๋ฌด์‹œํ•˜์ง€ ๋ง๊ณ  ์—๋Ÿฌ๋ฅผ ๋ณด์—ฌ์ค˜๋ผ! (๊ธฐ๋ณธ๊ฐ’)
legacy-peer-deps=false
 
# ๐ŸŒ ์šฐ๋ฆฌ ํŒ€ ์ „์šฉ ๋‚ด๋ถ€ ์ €์žฅ์†Œ๊ฐ€ ์žˆ๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ ์—ฐ๊ฒฐํ•ด์ค๋‹ˆ๋‹ค.
@youngsoo:registry=https://npm.youngsoo.internal.com/

๐Ÿ”ฅ save-exact=true ์˜ ์˜ํ–ฅ:

# save-exact=false (๊ธฐ๋ณธ๊ฐ’)
npm install react
# package.json โ†’ "react": "^18.2.0"
 
# save-exact=true
npm install react
# package.json โ†’ "react": "18.2.0"

save-exact=true ๋ฅผ ์“ฐ๋ฉด package.json ์— ์ •ํ™•ํ•œ ๋ฒ„์ „์ด ๊ธฐ๋ก๋œ๋‹ค. ์—„๊ฒฉํ•˜๊ฒŒ ๋ฒ„์ „์„ ๊ด€๋ฆฌํ•˜๋Š” ํŒ€์—์„œ ์‚ฌ์šฉํ•œ๋‹ค.


๐Ÿ ์ด๋ฒˆ์— ๋ฐฐ์šด ๋‚ด์šฉ ์ด์ •๋ฆฌ

๊ฐœ๋…ํ•ต์‹ฌ ์š”์•ฝ
package-lock.json์ •ํ™•ํ•œ ๋ฒ„์ „ + tarball URL + SHA-512 ํ•ด์‹œ ๊ธฐ๋ก. ๋ฐ˜๋“œ์‹œ git ์ปค๋ฐ‹
integrity๊ณต๊ธ‰๋ง ๊ณต๊ฒฉ ๋ฐฉ์–ด์„ . tarball ์œ„๋ณ€์กฐ ๊ฐ์ง€
npm installpackage.json ๊ธฐ์ค€. lock ๊ฐฑ์‹  ๊ฐ€๋Šฅ. ๊ฐœ๋ฐœ ์ค‘ ์‚ฌ์šฉ
npm cilock ํŒŒ์ผ ๊ธฐ์ค€. lock ๊ฐฑ์‹  ๋ถˆ๊ฐ€. CI/CD ํ•„์ˆ˜
ํ˜ธ์ด์ŠคํŒ…๊ณต์œ  ๊ฐ€๋Šฅํ•œ ํŒจํ‚ค์ง€๋ฅผ ์ตœ์ƒ์œ„๋กœ ์˜ฌ๋ ค ์ค‘๋ณต ์ œ๊ฑฐ
ํŒฌํ…€ ์˜์กด์„ฑ์ง์ ‘ ์„ค์น˜ ์•ˆ ํ•ด๋„ ์“ธ ์ˆ˜ ์žˆ๋Š” ํŒจํ‚ค์ง€. ๊ฐ„์ ‘ ์˜์กด์„ฑ์ด ๋ฐ”๋€Œ๋ฉด ๊นจ์ง
.npmrcnpm ๋™์ž‘ ์„ธ๋ฐ€ ์ œ์–ด. engine-strict, save-exact, ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์„ค์ •

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

Q1. npm ci ์™€ npm install ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ฐจ์ด์ ์€?

a) npm ci ๋Š” ๋” ๋น ๋ฅธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด ํ•ญ์ƒ ์„ค์น˜ ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค
b) npm ci ๋Š” package-lock.json ๊ธฐ์ค€์œผ๋กœ ์„ค์น˜ํ•˜๊ณ  lock ํŒŒ์ผ์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค
c) npm ci ๋Š” devDependencies ๋ฅผ ์ž๋™์œผ๋กœ ์ œ์™ธํ•œ๋‹ค
d) npm ci ๋Š” ์ „์—ญ ํŒจํ‚ค์ง€๋งŒ ์„ค์น˜ํ•œ๋‹ค

โœ… ์ •๋‹ต: b โ€” package-lock.json ๊ธฐ์ค€, lock ๋ณ€๊ฒฝ ์•ˆ ํ•จ

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

  • ์›๋ฆฌ ์„ค๋ช…: npm ci ์˜ ํ•ต์‹ฌ์€ ์žฌํ˜„ ๊ฐ€๋Šฅ์„ฑ์ด๋‹ค. package-lock.json ์— ๊ธฐ๋ก๋œ ์ •ํ™•ํ•œ ๋ฒ„์ „๋งŒ ์„ค์น˜ํ•˜๊ณ , lock ํŒŒ์ผ์„ ์ ˆ๋Œ€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š”๋‹ค. lock ํŒŒ์ผ์ด ์—†์œผ๋ฉด ์—๋Ÿฌ๋กœ ์ข…๋ฃŒํ•œ๋‹ค. CI ํ™˜๊ฒฝ์—์„œ npm install ์„ ์“ฐ๋ฉด package.json ์˜ ๋ฒ„์ „ ๋ฒ”์œ„ ๋‚ด์—์„œ ๊ทธ ์ˆœ๊ฐ„ ์ตœ์‹  ๋ฒ„์ „์ด ์„ค์น˜๋  ์ˆ˜ ์žˆ์–ด, ์–ด์ œ ํ†ต๊ณผํ•˜๋˜ ๋นŒ๋“œ๊ฐ€ ์˜ค๋Š˜ ์‹คํŒจํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์˜ค๋‹ต ํ”ผ๋“œ๋ฐฑ: a โ€” npm ci ๋Š” node_modules ๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ์„ค์น˜ํ•ด ์˜คํžˆ๋ ค ์บ์‹œ ์—†์„ ๋•Œ๋Š” ๋А๋ฆด ์ˆ˜ ์žˆ๋‹ค. c โ€” --omit=dev ์˜ต์…˜์„ ๋ณ„๋„๋กœ ์จ์•ผ ํ•œ๋‹ค. d โ€” ์ „์—ญ ์„ค์น˜์™€ ๋ฌด๊ด€ํ•˜๋‹ค.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "CI = ๋ณ€๊ฒฝ ๊ธˆ์ง€. npm ci = lock ํŒŒ์ผ ๋ณ€๊ฒฝ ๊ธˆ์ง€."

Q2. ํŒฌํ…€ ์˜์กด์„ฑ(Phantom Dependency)์ด๋ž€?

a) package.json ์— ์„ ์–ธ๋์ง€๋งŒ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ํŒจํ‚ค์ง€
b) package.json ์— ์„ ์–ธํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋‹ค๋ฅธ ํŒจํ‚ค์ง€์˜ ์˜์กด์„ฑ์ด ํ˜ธ์ด์ŠคํŒ… ๋˜์–ด import ๊ฐ€ ๋™์ž‘ํ•˜๋Š” ํŒจํ‚ค์ง€
c) node_modules ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํŒจํ‚ค์ง€
d) ๋ฒ„์ „์ด ์ž˜๋ชป๋œ ํŒจํ‚ค์ง€

โœ… ์ •๋‹ต: b โ€” ์ง์ ‘ ์„ค์น˜ ์•ˆ ํ–ˆ์ง€๋งŒ ํ˜ธ์ด์ŠคํŒ…์œผ๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ํŒจํ‚ค์ง€

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

  • ์›๋ฆฌ ์„ค๋ช…: npm ์˜ ํ”Œ๋žซ ๊ตฌ์กฐ ํ˜ธ์ด์ŠคํŒ…์œผ๋กœ ์ธํ•ด A ํŒจํ‚ค์ง€๊ฐ€ ์˜์กดํ•˜๋Š” B ํŒจํ‚ค์ง€๊ฐ€ ์ตœ์ƒ์œ„ node_modules ์— ์˜ฌ๋ผ์˜จ๋‹ค. ๋‚ด ์ฝ”๋“œ์—์„œ B ๋ฅผ ์ง์ ‘ import ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, A ๊ฐ€ B ๋ฅผ ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด B ๊ฐ€ ํ˜ธ์ด์ŠคํŒ…๋˜์ง€ ์•Š์•„ ๋‚ด ์ฝ”๋“œ๊ฐ€ ์—๋Ÿฌ๋‚œ๋‹ค. ๋‚ด๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ”๊พธ์ง€ ์•Š์•˜๋Š”๋ฐ ๋‚จ์˜ ์—…๋ฐ์ดํŠธ๋กœ ์ธํ•ด ๋‚ด ์ฝ”๋“œ๊ฐ€ ๊นจ์ง„๋‹ค.
  • ํ•ด๊ฒฐ: ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ‚ค์ง€๋Š” package.json ์— ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•œ๋‹ค.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "๋‚ด ์ฝ”๋“œ์—์„œ ์“ฐ๋Š” ๊ฒƒ์€ ๋ฐ˜๋“œ์‹œ ๋‚ด package.json ์— ์žˆ์–ด์•ผ ํ•œ๋‹ค."

Q3. ๐Ÿฃ ์˜์ฒ ์ด์˜ ํ…Œ์ŠคํŠธ ํƒ€์ž„ โ€” ๊ธด๊ธ‰ ๋””๋ฒ„๊น…

์˜์ˆ˜ PM ์ด ์Šฌ๋ž™์„ ๋ณด๋ƒˆ๋‹ค. "CI ๋นŒ๋“œ๊ฐ€ ์˜ค๋Š˜ ๊ฐ‘์ž๊ธฐ ์‹คํŒจํ–ˆ์–ด์š”. ์–ด์ œ๋Š” ๋๋Š”๋ฐ. ์ฝ”๋“œ ๋ณ€๊ฒฝ์ด ์—†์—ˆ๋‹ค๊ณ ์š”?" ์˜์ฒ ์ด๊ฐ€ GitHub Actions ๋กœ๊ทธ๋ฅผ ๋ณด๋‹ˆ:

Run npm install
...
added 847 packages in 23s

error TS2339: Property 'createServer' does not exist on type ...

๊ทธ๋ฆฌ๊ณ  npm list typescript ๋กœ ํ™•์ธํ•ด๋ณด๋‹ˆ ์–ด์ œ๋Š” 5.2.0 ์ด์—ˆ๋Š”๋ฐ ์˜ค๋Š˜์€ 5.3.0 ์œผ๋กœ ์„ค์น˜๋๋‹ค. ์›์ธ๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€?

โœ… ์ •๋‹ต: CI ์—์„œ npm install ์„ ์‚ฌ์šฉํ•ด lock ํŒŒ์ผ ์—†์ด ๋งค๋ฒˆ ์ตœ์‹  ๋ฒ„์ „์ด ์„ค์น˜๋๋‹ค. npm ci ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

# ์ˆ˜์ • ์ „ (๋ฌธ์ œ ์žˆ๋Š” ์„ค์ •)
- name: Install dependencies
  run: npm install
 
# ์ˆ˜์ • ํ›„ (์˜ฌ๋ฐ”๋ฅธ ์„ค์ •)
- name: Install dependencies
  run: npm ci

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

  • ์›์ธ: npm install ์€ package.json ์˜ "typescript": "^5.2.0" ๋ฒ”์œ„ ๋‚ด์—์„œ ๋งค ์‹คํ–‰๋งˆ๋‹ค ๊ฐ€๋Šฅํ•œ ์ตœ์‹  ๋ฒ„์ „์„ ์„ ํƒํ•œ๋‹ค. ์–ด์ œ CI ๊ฐ€ ๋Œ์•˜์„ ๋•Œ๋Š” 5.2.0 ์ด ์ตœ์‹ ์ด์—ˆ๊ณ , ์˜ค๋Š˜์€ 5.3.0 ์ด ๋‚˜์™€์„œ ๊ทธ๊ฒŒ ์„ค์น˜๋๋‹ค. TypeScript ๋งˆ์ด๋„ˆ ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ์—์„œ ํƒ€์ž… ์ฒดํฌ๊ฐ€ ๋” ์—„๊ฒฉํ•ด์ง„ ๊ฒƒ.
  • npm ci ๋ฅผ ์จ์•ผ ํ•˜๋Š” ์ด์œ : npm ci ๋Š” package-lock.json ์— ๊ธฐ๋ก๋œ ์ •ํ™•ํžˆ 5.2.0 ๋งŒ ์„ค์น˜ํ•œ๋‹ค. lock ํŒŒ์ผ์— 5.2.0 ์ด ๊ธฐ๋ก๋˜์–ด ์žˆ๋Š” ํ•œ, ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— 5.3.0 ์ด ๋‚˜์™€๋„ ๋ฌด์‹œํ•œ๋‹ค.
  • ์ถ”๊ฐ€ ์กฐ์น˜: ๊ฐœ๋ฐœํŒ€์ด TypeScript 5.3.0 ์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•  ์ค€๋น„๊ฐ€ ๋์„ ๋•Œ, ๋กœ์ปฌ์—์„œ npm update typescript ๋กœ lock ํŒŒ์ผ์„ ๊ฐฑ์‹ ํ•˜๊ณ  ํƒ€์ž… ์—๋Ÿฌ๋ฅผ ์ˆ˜์ •ํ•œ ๋‹ค์Œ ์ปค๋ฐ‹ํ•œ๋‹ค.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "CI ์—์„œ๋Š” npm ci. ํ•ญ์ƒ. ์˜ˆ์™ธ ์—†์ด."

๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋Š˜ ๋“œ๋””์–ด CI ๋นŒ๋“œ ์‹คํŒจ ์›์ธ์„ ์žก์•˜๋‹ค. npm install โ†’ npm ci ๋กœ ๋ฐ”๊ฟจ๋”๋‹ˆ ๊ฑฐ์ง“๋ง์ฒ˜๋Ÿผ ํ†ต๊ณผ๋๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋‹จ์ˆœํ•œ ๊ฑฐ์˜€์–ด.

package-lock.json ์ด ์™œ ๊ทธ๋ ‡๊ฒŒ ๊ธธ๊ณ  ๋ณต์žกํ•œ์ง€๋„ ์ด์ œ ์ดํ•ดํ•œ๋‹ค. ๋‹จ์ˆœํžˆ "๋ฒ„์ „ ๊ธฐ๋ก" ์ด ์•„๋‹ˆ๋ผ tarball URL ๊ณผ SHA-512 ํ•ด์‹œ๊ฐ’๊นŒ์ง€ ์ ์–ด์„œ ํŒŒ์ผ ์œ„๋ณ€์กฐ๋ฅผ ๋ง‰๋Š” ๊ฑฐ์˜€๋‹ค. integrity ํ•„๋“œ๊ฐ€ ๊ณต๊ธ‰๋ง ๊ณต๊ฒฉ์˜ ๋ฐฉ์–ด์„ ์ด๋ผ๋‹ˆ, ๊ทธ๋ƒฅ ์ž๋™ ์ƒ์„ฑ๋˜๋Š” ํŒŒ์ผ์ธ ์ค„๋งŒ ์•Œ์•˜๋Š”๋ฐ.

๐Ÿ’ก ์˜ค๋Š˜์˜ ๊ตํ›ˆ: "CI ์—์„œ๋Š” npm ci. ๋กœ์ปฌ์—์„œ๋Š” npm install. ์ด ๋‘ ์ค„๋งŒ ๊ธฐ์–ตํ•˜๋ฉด '๋‚ด ๋กœ์ปฌ์—์„œ๋Š” ๋˜๋Š”๋ฐ' ์ง€์˜ฅ์—์„œ ํƒˆ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค."

ํŒฌํ…€ ์˜์กด์„ฑ ์ด์•ผ๊ธฐ๋„ ์‹ ์„ ํ–ˆ๋‹ค. ๋‚ด๊ฐ€ ์„ค์น˜ ์•ˆ ํ•œ ๊ฑธ import ํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒŒ... ์ง€๊ธˆ๊นŒ์ง€ ๋ชฐ๋ž์œผ๋ฉด ์–ธ์  ๊ฐ€ ์‚ฌ๊ณ ๊ฐ€ ๋‚ฌ์„ ๊ฒƒ ๊ฐ™๋‹ค. ์•ž์œผ๋กœ๋Š” import ํ•˜๋Š” ๊ฑด ๋ฌด์กฐ๊ฑด package.json ์— ๋ช…์‹œํ•˜๋Š” ์Šต๊ด€์„ ๋“ค์—ฌ์•ผ๊ฒ ๋‹ค.

์˜ค๋Š˜์€ ํ‡ด๊ทผํ•˜๋ฉด์„œ ์šด๋™ ๊ฐ”๋‹ค ์™”๋‹ค. ๋‚ด์ผ์€ scripts ๋ž‘ ๋ผ์ดํ”„์‚ฌ์ดํด ํ›… ํŒŒ๋ณผ ์˜ˆ์ •. ์ƒ๊ฐ๋ณด๋‹ค npm ์— ๋ฐฐ์šธ ๊ฒŒ ์ด๋ ‡๊ฒŒ ๋งŽ๋‹ค๋‹ˆ, ์ฒ˜์Œ์—” ๊ทธ๋ƒฅ install ์น˜๋ฉด ๋˜๋Š” ์ค„ ์•Œ์•˜๋Š”๋ฐ.


๐Ÿ”— ๋” ์•Œ์•„๋ณด๊ธฐ