๐Ÿ“ฆ JavaScript Module System

DoonDoonยท2018๋…„ 12์›” 1์ผ
37
post-thumbnail

Photo by DD of CreamHeroes
๋ชจ๋“ˆ = ๋ฐ•์Šค = ๊ณ ์–‘์ด ์šฐ๋ฆฌ ๋‘”๋‘”์ด ์ปค๋ฒ„ ์‚ฌ์ง„์œผ๋กœ ์‚ฌ์‹ฌ ์ฑ„์šฐ๊ธฐ

๐Ÿ“š Contents


  1. Prologue
  2. Module
  3. Module System
    1. ES6 module system (ESM)
    2. CommonJS
    3. AMD
  4. ๋งˆ์น˜๋ฉฐ
  5. References

๐ŸŽค Prologue


ํ˜„์žฌ ์ฐธ์—ฌ ์ค‘์ธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์Šคํ„ฐ๋””์˜ ๋ฐœํ‘œ ์ž๋ฃŒ๋ฅผ ๋งŒ๋“ค๋ฉด์„œ
์กฐ์‚ฌํ–ˆ์—ˆ๋˜ ๋‚ด์šฉ๋“ค์„ ๊ธ€๋กœ ๋‹ค์‹œ ์ •๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค

๋”๋ถˆ์–ด, ํšŒ์‚ฌ ์—…๋ฌด์™€ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ๋งŒ ํ•˜๋‹ค ๋ณด๋‹ˆ
์ตœ๊ทผ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋„ˆ๋ฌด ์†Œํ™€ํžˆ ํ•œ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์ƒ๊ฐ๋„ ๋“ค๊ตฌ์š”

์™œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ชจ๋“ˆ์— ๋Œ€ํ•ด ๋ฐœํ‘œํ•˜๋‚˜์š”?
โ†’ ๋ชจ๋“ˆ์„ ๋งŒ๋“ค๊ณ  ๋ฐฐํฌํ•ด ๋ณธ ๊ฒฝํ—˜์ด ์ด์ง์—์„œ ์ข‹์€ ์–˜๊นƒ๊ฑฐ๋ฆฌ๊ฐ€ ๋˜์ง€ ์•Š์„๊นŒ ์กฐ์–ธ ํ•ด์ค€ ํšŒ์‚ฌ ์„ ๋ฐฐ
โ†’ yarn add moment ๋Š” ๊ณง์ž˜ ์ž…๋ ฅํ•˜๋Š”๋ฐ ๊ทธ ์ดํ›„์— ๋ฌด์Šจ ์ผ์ด ์ƒ๊ธฐ๋Š”์ง€ ์ •ํ™•ํžˆ ๋ชฐ๋ผ์š” ๐Ÿ˜‘

๊ธ€์„ ์ž‘์„ฑํ•˜๋Š”๋ฐ ๊ฑธ๋ฆฐ ์‹œ๊ฐ„์€?
โ†’ ๊ธˆ์š”์ผ ์˜ค์ „ ~ ํ† ์š”์ผ ์˜ค์ „ ๊ฑฐ์˜ ๋”ด ์ง“ ์—†์ด
โ†’ ์ง„์งœ... ์™œ ์ด๋ ‡๊ฒŒ ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๊ฑฐ์ง€...

๋‹ค ์ฝ๊ณ  ๋‚˜๋ฉด ๋ญ๊ฐ€ ์ข‹์„๊นŒ์š”?
โ†’ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์ด ์ด๋Ÿฐ๊ฒŒ ์žˆ๊ตฌ๋‚˜
โ†’ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์— ๋Œ€ํ•œ ์•ฝ๊ฐ„์˜ ์ดํ•ด

๐Ÿ“ฆ Module


๋ชจ๋“ˆ์ด ๋ญ์•ผ? ๋ผ๊ณ  ๋ฌผ์–ด๋ณธ๋‹ค๋ฉด ๋ญ๋ผ๊ณ  ํ•ด์•ผ ํ• ๊นŒ์š”...๐Ÿค”
์ด๋ฆฌ ์ €๋ฆฌ ์ฐพ์•„๋ณด๋‹ค๊ฐ€ ์ข‹์€ ๋‹ต์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค

๋ชจ๋“ˆ์€ ํ”„๋กœ๊ทธ๋žจ์˜ ์ผ๋ถ€๋ถ„์ด๋‹ค. ํ”„๋กœ๊ทธ๋žจ์€ ํ•˜๋‚˜ ์ด์ƒ์˜ ๋ชจ๋“ˆ์˜ ์กฐํ•ฉ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค
๋ชจ๋“ˆ์€ ํ•˜๋‚˜ ๋˜๋Š” ๊ทธ ์ด์ƒ์˜ Routine(ํ•จ์ˆ˜, ๋ฉ”์„œ๋“œ, ํ”„๋กœ์‹œ์ ธ ๋“ฑ)์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค

๋ชจ๋“ˆ์€ ์šฐ๋ฆฌ ํ”„๋กœ๊ทธ๋žจ์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ถ€ํ’ˆ๊ณผ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”

'๊ทธ๋Ÿผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ชจ๋“ˆ์ด๋ž‘ ๋ฌด์Šจ ์ฐจ์ด๊ฐ€ ์žˆ์ง€?'
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์šฐ๋ฆฌ ์ฝ”๋“œ๋ฅผ ์™„์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์™ธ๋ถ€ ์ž์›(๋ชจ๋“ˆ)์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค

์ž๋™์ฐจ๋ฅผ ํ”„๋กœ๊ทธ๋žจ์— ๋น—๋Œ€์–ด ๋ณด๋ฉด
๋ฐ”ํ€ด, ํ•ธ๋“ค ๋“ฑ์€ ๋ถ€ํ’ˆ(๋ชจ๋“ˆ)์ด๊ณ 
๋„ค๋น„๊ฒŒ์ด์…˜ ์‹œ์Šคํ…œ, ์ฐจ๋Ÿ‰์šฉ ์Šคํ”ผ์ปค ๋“ฑ์€ ์™ธ๋ถ€ ์ž์› (๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ) ๊ฐ€ ์•„๋‹๊นŒ์š”?

โ›‘ Module System


์šฐ๋ฆฌ๋Š” ํ•˜๋‚˜์˜ ํŒŒ์ผ์— ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ๋‹ค ์ž‘์„ฑํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค ๐Ÿ™…โ€โ™‚๏ธ๐Ÿ™…โ€โ™€๏ธ
(๋ฌผ๋ก  ๋‹ค ์ž‘์„ฑํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค ๋ฒ”๋ฒ•์€ ์•„๋‹ˆ์ž–์•„์š”?)

๊ทธ๋ž˜์„œ ๋ณดํ†ต์€ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ชจ๋“ˆ์ด ์ƒ๊น๋‹ˆ๋‹ค
(index.js, util.js, common.js ...)

์—ญํ• ์— ๋งž๊ฒŒ ๋ถ„๋ฆฌ๋œ ๋ชจ๋“ˆ๋“ค์€ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ ํ•„์š”๋กœ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค
๊ทธ๋Ÿผ ๋ชจ๋“ˆ์„ ์–ด๋–ป๊ฒŒ ๋ถˆ๋Ÿฌ์˜ฌ๊นŒ์š”?

์šฐ๋ฆฌ๊ฐ€ ์•Œ๊ณ  ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋Œ€ํ‘œ์ ์œผ๋กœ 3 ( + 1 ) ๊ฐ€์ง€ ์ž…๋‹ˆ๋‹ค

  1. ES6 Modules(ESM) โ†’ import
  2. CommonJS โ†’ require
  3. AMD โ†’ define - require
  4. Browser โ†’

(์ด ์™ธ์—๋„ System.js, Require.js ๋“ฑ์˜ ๋ชจ๋“ˆ ๋กœ๋”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค)

ESM์˜ ๊ฒฝ์šฐ์—๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ (๋ธŒ๋ผ์šฐ์ €) ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“ˆ ์‹œ์Šคํ…œ ์ž…๋‹ˆ๋‹ค
CommonJS ๋Š” Node.js ์˜ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์œผ๋กœ ์ฑ„ํƒ๋˜์–ด ํ™œ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค
AMD๋Š” require.js ๋ผ๋Š” ๊ตฌํ˜„์ฒด๋ฅผ ํ™œ์šฉํ•ด ํ™˜๊ฒฝ์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

๋ฌผ๋ก  CommonJS ๋ฅผ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๊ณ 
ESM ๋˜ํ•œ Node.js ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ์žˆ๊ธฐ๋•Œ๋ฌธ์—
ํ™˜๊ฒฝ ์ข…์†์ ์œผ๋กœ ๋”ฑ ์ž˜๋ผ ์ƒ๊ฐํ•  ํ•„์š”๋Š” ์—†์–ด ๋ณด์ž…๋‹ˆ๋‹ค

๊ทธ๋Ÿผ ๊ฐ๊ฐ์„ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด๊ณ 
์–ด๋–ค ์ฐจ์ด์ ์ด ์žˆ๋Š”์ง€๋„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค

๐Ÿ“ฆ ES6 Modules(ESM)


ES6 ์ด์ „๊นŒ์ง€๋Š”, ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ‘œ์ค€ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค
(๋งŒ์•ฝ ์ œ๊ฐ€ ์ž˜๋ชป ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š”!)

์ด์ „์˜ ํด๋ผ์ด์–ธํŠธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์€
ํ•„์š”ํ•œ ํŒŒ์ผ(๋ชจ๋“ˆ)์„ ๋งŒ๋“ค์–ด์„œ ๊ฐ™์ด ๋ฐฐํฌํ•œ ๋’ค์— <script src="..."> ๋กœ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ์‹์ด์—ˆ์Šต๋‹ˆ๋‹ค

์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ณต์‹ ๋ฐฐํฌํŒ์„ ๋‹ค์šด๋กœ๋“œ ํ•˜์—ฌ ํ•จ๊ป˜ ๋ฌถ์–ด์„œ ๋ฐฐํฌํ•˜๊ฑฐ๋‚˜
<script src="..."> ๋กœ cdnjs, unpkg ์— ์กด์žฌํ•˜๋Š” ์ฃผ์†Œ๋ฅผ ๋กœ๋“œํ•˜์—ฌ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค

(๊ทธ ์™ธ์—๋„ ๋งŽ์€ ๋ฐฉ๋ฒ•์ด ์žˆ์—ˆ๊ฒ ์ง€์š”)

<script> ์–ด์ฉŒ๋ฉด ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์˜ ํ•˜๋‚˜๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
๊ทธ์น˜๋งŒ...(์˜ค๋‹ˆ์จฉ...) ๋‹ค๋ฅธ ์–ธ์–ด์ฒ˜๋Ÿผ import, include, use ๊ฐ™์€๊ฒŒ ํ•„์š”ํ•˜๊ฒ ์ฃ 

ES6 ์—์„œ๋Š” ๋“œ๋””์–ด ์ •์‹์œผ๋กœ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์ด ๋„์ž… ๋˜์—ˆ์Šต๋‹ˆ๋‹ค ๐ŸŽ‰

import, export ๊ฐ€ ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ์นœ๊ตฌ๋“ค ์ž…๋‹ˆ๋‹ค
๊ทธ๋Ÿผ ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ์นœ๊ตฌ๋“ค์€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค

๐Ÿšข export


์ˆœ์„œ์ƒ import ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์ด์ „์— export ๋ฌธ๋ฒ•์„ ๋ช…ํ™•ํžˆ ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค
export ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ named export, default export ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค

named export

์„ ์–ธ๋œ ๋ณ€์ˆ˜๋ช… ๊ทธ๋Œ€๋กœ export ํ•ฉ๋‹ˆ๋‹ค
named export ๋Š” ๋ชจ๋“ˆ ๋‚ด์— ์—ฌ๋Ÿฌ๊ฐœ ์กด์žฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

named export ๋Š” ๋ณ€์ˆ˜ ์„ ์–ธ๊ณผ ๋™์‹œ์— ๋‚ด๋ณด๋‚ด๋„๋ก ํ•˜๊ฑฐ๋‚˜
๋จผ์ € ์ •์˜๋œ ๋ณ€์ˆ˜๋“ค์„ ๋ชจ์•„์„œ ๋‚ด๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค

// 1. ๋ณ€์ˆ˜ ์„ ์–ธ ์ฆ‰์‹œ ๋‚ด๋ณด๋‚ด๊ธฐ
export let name1;
export const name2;
export var name3;
export function name4 () {/*...*/}
export class MyClass {/*...*/}

// 2. ๋ณ€์ˆ˜ ๋จผ์ € ์ •์˜ํ•˜๊ณ , ๋ชจ์•„์„œ ๋‚ด๋ณด๋‚ด๊ธฐ
const var1;
let var2;
var var3;

export { var1, var2, var3 }

// 3. ๋จผ์ € ์ •์˜๋œ ํ•จ์ˆ˜๋ฅผ ๋ณ„์นญ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์„œ ๋‚ด๋ณด๋‚ด๊ธฐ
let var4;
export { var4 as var5 } // ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ import ํ•  ๋•Œ์—๋Š” var5 ๋กœ import ํ•ด์•ผ ํ•จ
default export

default export ์™€ named export ์˜ ์ฐจ์ด์ ์€

  1. default export ๋Š” ๋ชจ๋“ˆ์—์„œ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

  2. export default { let, const, var } ์™€ ๊ฐ™์€๊ฑด ์•ˆ๋ฉ๋‹ˆ๋‹ค

    export default expression;
    export default function () {/*...*/} // ์ต๋ช…ํ•จ์ˆ˜
    export default function myFunction () {/*...*/} // ๊ธฐ๋ช…ํ•จ์ˆ˜
    export default class {/*...*/}
    export default class MyClass {/*...*/}
    export default function* () {/*...*/} // ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋„ ๋™์ผ
    
    // ๐Ÿ™…โ€โ™‚๏ธ Uncaught SyntaxError: Unexpected token const
    export default const test = /*...*/ 
    
    // named export ์ฒ˜๋Ÿผ ๋ฌถ์–ด ๋‚ด๋ณด๋‚ด๊ธฐ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
    const myModule = {/*...*/}
    const var1 = () => {}
    export { myModule as default, var1 } // as ๋ฅผ ์ด์šฉํ•ด default export ํ•˜์˜€์Šต๋‹ˆ๋‹ค

๋Œ€๋žต์ ์ธ ์‚ฌ์šฉ๋ฐฉ๋ฒ•์€ ์•Œ์•˜์œผ๋‹ˆ ํ˜ธ๊ธฐ์‹ฌ์ด ์ƒ๊น๋‹ˆ๋‹ค
๋งŒ์•ฝ export default ๋ฅผ ๋‘ ๋ฒˆ ํ•˜๋ฉด ๋ฌด์Šจ ์ผ์ด ์ƒ๊ธธ๊นŒ์š”? ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค!

// ์—ญ์‹œ๋‚˜ ์—๋Ÿฌ!
Uncaught SyntaxError: Identifier '*default*' has already been declared

์ž ๊น ์•ผํฌํ„ธ์„ ๊นŽ์•„๋ณด์ž๋ฉด (์•ผํฌํ„ธ ๊นŽ๊ธฐ๋ž€... ์„ ์•Œ๋ ค๋“œ๋ฆฌ๋ฉฐ ๋˜ ์•ผํฌํ„ธ ๊นŽ๊ธฐ)

"*default*" ๋ผ๋Š” Identifier๋Š” export ๋ฌธ์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค
ecma-262 ๋ช…์„ธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค

NOTE: "*default*" is used within this specification as a synthetic name for anonymous default export values

(์ข€ ๋” ๊ถ๊ธˆํ•˜์‹œ๋ฉด ๋ช…์„ธ๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”๐Ÿ‘๊ทธ๋ƒฅ ์˜ˆ์•ฝ๋œ ์‹๋ณ„์ž๋กœ ์ดํ•ดํ•˜์…”๋„ ์ข‹์Šต๋‹ˆ๋‹ค)

๋‹ค์‹œ ๋‚ด๋ณด๋‚ด๊ธฐ (export - from)

export ๋กœ ๋˜ ํ•œ๊ฐ€์ง€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค
๋ฐ”๋กœ import ์™€ export ๋ฅผ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” export - from ์ž…๋‹ˆ๋‹ค!

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

์ฐธ๊ณ ๋กœ, ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ from ์„ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” .js ํ™•์žฅ์ž๋ฅผ ์ ์ง€ ์•Š์œผ๋ฉด
404 Error ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค

// src/utils ํŒจํ‚ค์ง€๋Š” index.js math.js, logger.js, config.js ๋ชจ๋“ˆ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค

// ๐Ÿ“ src/utils/math.js
export function add (a, b) {/*...*/}
export function subtract (a, b) {/*...*/}
export function multiply (a, b) {/*...*/}
export function divide (a, b) {/*...*/}

// ๐Ÿ“ src/utils/logger.js
export default {
  print() { /*...*/ }
}

// ๐Ÿ“ src/utils/config.js
export const DB_HOST = 'localhost';
export const DB_USER = 'scott';
export const DB_PASSWORD = 'tiger';

// ๐Ÿ“ src/utils/index.js

// math ๋ชจ๋“ˆ์—์„œ ์ผ๋ถ€๋งŒ import ํ•œ ๋’ค ๋‹ค์‹œ export ํ•ฉ๋‹ˆ๋‹ค
export { add, subtract } from './math';

// config ๋ชจ๋“ˆ์˜ ๋ชจ๋“  export ๊ฐ€๋Šฅํ•œ ๋ณ€์ˆ˜๋ฅผ re-export ํ•ฉ๋‹ˆ๋‹ค
export * from './config';

// logger ๋ชจ๋“ˆ์˜ default export ๋ฅผ Logger ๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝํ•ด export ํ•ฉ๋‹ˆ๋‹ค
export { default as Logger } from './logger'; 


// ๐Ÿ“ src/index.js

// ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ import ํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ index.js ํŒŒ์ผ์„ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค
import * as utils from './utils';

utils.add(1, 2) // 3
utils.DB_HOST // 'localhost'
utils.Logger.print('TEST') // 'TEST'

์กฐ๊ธˆ ๊ธธ๊ธด ํ•˜์ง€๋งŒ ํ•œ ๋ฒˆ ์ญ‰ ์ฝ์–ด๋ณด์‹œ๋ฉด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•„์‹œ๊ฒ ์ฃ ?
์ด๋Ÿฐ์‹์œผ๋กœ ํŒจํ‚ค์ง€์˜ index ์—์„œ ๋ชจ๋“ˆ์˜ ๋‚ด๋ณด๋‚ด๋Š” ๋ฐฉ์‹์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์ •๋ฆฌํ•˜์—ฌ
ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ๋กœ ๋‚ด๋ณด๋‚ด๋Š” ๊ฒƒ์„ ๐Ÿ“ฆ Barrel ๋ฐฉ์‹ ์ด๋ผ๊ณ  ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค (์ •์‹ ์šฉ์–ด๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค)

์ถ”๊ฐ€์ ์œผ๋กœ export - from ๊ตฌ๋ฌธ์€ import ์™€ export ๋ฅผ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ์ถ•์•ฝ๋ฒ•์ด์ง€๋งŒ
export - from ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํŒŒ์ผ ์Šค์ฝ”ํ”„์— ์‹๋ณ„์ž๋ฅผ ๋ฐ”์ธ๋”ฉ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์„ค๋ช…์ด ์ข€ ๋ณต์žกํ•œ๊ฒƒ ๊ฐ™์•„ ์ฝ”๋“œ๋กœ ์˜ˆ๋ฅผ ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค

// ๐Ÿ“ src/utils/index.js

// math ๋ชจ๋“ˆ์—์„œ ์ผ๋ถ€๋งŒ import ํ•œ ๋’ค ๋‹ค์‹œ export ํ•ฉ๋‹ˆ๋‹ค
export { add, subtract } from './math';

// ๊ทผ๋ฐ ๋‚ด๋ณด๋‚ด๊ธฐ ์ „์— add ํ•จ์ˆ˜๋ฅผ ์ด ํŒŒ์ผ์—์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค...? Nope
add(1, 2); // ๐Ÿ™…โ€โ™‚๏ธ Uncaught ReferenceError: add is not defined

์œ„ ์ฝ”๋“œ์˜ ์—๋Ÿฌ์ฒ˜๋Ÿผ ์Šค์ฝ”ํ”„๋‚ด์— ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค!

๐Ÿšข import


import ๋Š” ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ๋ชจ๋“ˆ์„ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค
default export ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ฑฐ๋‚˜, named export ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

๊ทธ๋ฆฌ๊ณ  as ๋ฅผ ์ด์šฉํ•ด alias ์ฒ˜๋ฆฌ
*(asterisk) ๋ฅผ ํ†ตํ•ด named export ์ „์ฒด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค

์•„๋ž˜ ์˜ˆ์‹œ๋Š” MDN ๋ฌธ์„œ์—์„œ ๋ฐœ์ทŒํ–ˆ์Šต๋‹ˆ๋‹ค

import name from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as alias from "module-name";
import defaultMember from "module-name";
import "module-name";

name ๊ณผ member, defaultMember ๊ฐ๊ฐ์˜ ์˜๋ฏธ๋Š”...

name: import ํ•œ ๊ฐ’์˜ ํ˜„์žฌ ์Šค์ฝ”ํ”„์˜ ์ด๋ฆ„ (export ํ•˜๋Š” ์ชฝ์˜ ์ด๋ฆ„์ด ์•„๋‹™๋‹ˆ๋‹ค)
member, memberN: export ๋œ ๋ชจ๋“ˆ์˜ ๋ฉค๋ฒ„ ์ด๋ฆ„
defaultMember: name ๊ณผ ๋™์ผํ•˜๊ฒŒ default export ๋œ ๊ฐ’์„ ๋ฐ›์„ ์ด๋ฆ„
alias, aliasN: ๊ฐ€์ ธ์˜จ member ์˜ ์ƒˆ๋กœ ์ฃผ์–ด์งˆ ๋ณ„์นญ

๋ญ”๊ฐ€ ์„ค๋ช…์ด ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋˜๋„ค์š”...
๊ฐ๊ฐ ๋‚˜๋ˆ ์„œ ์ฝ”๋“œ๋กœ ์˜ˆ๋ฅผ ๋“ค์–ด ๋ณผ๊ฒŒ์š”!

๋จผ์ € util.js ๋ผ๋Š” ๋ชจ๋“ˆ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

// ๐Ÿ“ util.js
export function print (msg) {};
export function fetch (url) {};
export default {
  add(a, b) {},
  subtract(a, b) {},
}

๊ธฐ๋ณธ์ ์ธ import ๋ฌธ๋ฒ•

// ๐Ÿ“ app.js

// default export ๋งŒ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
import util from './util';

util.add(1,2) // 3

// named export ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค
import { print, fetch } from './util';

print('Hello!') // Hello!

as ๋ฅผ ์ด์šฉํ•ด ์ƒˆ ์ด๋ฆ„ ๋ถ€์—ฌํ•˜๊ธฐ

// ๐Ÿ“ app.js

import { print as logger } from './util';

logger('Hello!') // Hello!

*(asterisk) ๋ฅผ ์ด์šฉํ•ด named export ๋ฅผ ๋ชจ๋‘ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

// ๐Ÿ“ app.js

// util ๋Œ€์‹ ์— ๋‹ค๋ฅธ ์ด๋ฆ„๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
import * as util from './util';

util.print('Hello!') // Hello!

// ๐Ÿ˜Ž ๊ทธ๋ฆฌ๊ณ  ์ด ์ฝ”๋“œ์—๋Š” ์ˆจ๊ฒจ์ง„ ๋น„๋ฐ€์ด ์žˆ์Šต๋‹ˆ๋‹ค... ์กฐ๊ธˆ ํ›„์— ์•Œ๋ ค๋“œ๋ฆด๊ฒŒ์š”!

default export, named export ๋ชจ๋‘ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

// ๐Ÿ“ app.js

import util, { fetch, print } from './util';

util.add(2, 3) // 5
print('Hello!') // Hello!
fetch('https://httpbin.org').then(/*...*/)

์–ด๋–ค ๋ฐ”์ธ๋”ฉ ์—†์ด ๋ชจ๋“ˆ ์ „์ฒด์˜ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ

// ๐Ÿ“ app.js

import 'util';
// util.js ์ฝ”๋“œ๊ฐ€ ํ•œ ๋ฒˆ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋ณ€์ˆ˜์— ๋ฐ”์ธ๋”ฉ ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค

๋งŒ์•ฝ default export ์™€ named export ๋ฅผ ๊ฐ™์ด ํ•˜๋Š” ๋ชจ๋“ˆ์„ *(asterisk) ๋กœ ๋ถˆ๋Ÿฌ์™”๋‹ค๋ฉด...?

// ๐Ÿ“ app.js

import * as util from './util';

util.default.add(1, 2) // 3... ์•„๊นŒ์˜ ์ฝ”๋“œ์˜ ๋น„๋ฐ€์€ ์ด๊ฒ๋‹ˆ๋‹ค.. ์ด๋Ÿด์ˆ˜๊ฐ€!

default ๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค
๊ทธ๋ฆฌ๊ณ  default ํ”„๋กœํผํ‹ฐ๋Š” default export ๋œ ๋ชจ๋“ˆ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค

์„ค๋ช…์ด ๊ธธ์–ด์กŒ๋„ค์š”... ES6 modules์˜ export, import ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•ด ์•Œ์•„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค!
๋‹ค์Œ์€ Node.js ์—์„œ ์‚ฌ์šฉ ์ค‘์ธ CommonJS ์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ๊ฒŒ์š”!

๐Ÿ“ฆ CommonJS


CommonJS ๋Š” 2009๋…„ ๋˜ ํ•˜๋‚˜์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ‘œ์ค€์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๋…ธ๋ ฅ์œผ๋กœ ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค
์ฒ˜์Œ CommonJS ๋ฅผ ๋งŒ๋“ค๋ฉด์„œ ์ฐฝ์‹œ์ž์ธ Kevin Dangoor ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์ง€์ ํ–ˆ์Šต๋‹ˆ๋‹ค

CommonJS ๊ทธ๋ฃน์ด ์ƒ๊ฐํ•˜๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ง€๊ตฌ ์ •๋ณต์˜ ๋ฐœ๋ชฉ์„ ์žก๋Š” ๊ฒƒ๋“ค...

  • JavaScript has no module system. To compose JavaScript scripts, they must be either managed in HTML, concatenated, injected, or manually fetched and evaluated. There is no native facility for scope isolation or dependency management.
  • JavaScript has no standard library. It has a browser API, dates, and math, but no file system API, much less an IO stream API or primordial types for binary data.
  • JavaScript has no standard interfaces for things like Web servers or databases.
  • JavaScript has no package management system that manages dependencies and automatically installs them, exceptย JSANย (not to be confused with JSON), which falls short for scope isolation.

๊ฐ„๋žตํ•˜๊ฒŒ ์šฐ๋ฆฌ๋ง๋กœ ์š”์•ฝํ•˜์ž๋ฉด...

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์ด ์—†๋‹ค
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—†๋‹ค (๋ธŒ๋ผ์šฐ์ € API, date, math ๋ฟ)
  • ์›น ์„œ๋ฒ„ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋“ฑ์„ ์œ„ํ•œ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†๋‹ค
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์ด ์—†๋‹ค

์ด์™€ ๊ฐ™์€ ๋ฌธ์ œ๋“ค์„ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด ์‹œ์ž‘ํ•œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ƒํƒœ๊ณ„๋ฅผ ์œ„ํ•œ ๋‹จ์ฒด์ž…๋‹ˆ๋‹ค

์ฐธ๊ณ ๋กœ, ๋‘ ๋ฒˆ์งธ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—†๋‹ค๋Š” ์ ์— ๋Œ€ํ•ด์„œ๋„
path, fs ๋“ฑ์ด Node.js ์—์„œ ๋‚ด์žฅ API ๋กœ ์ œ๊ณต๋˜๋„๋ก CommonJS ๊ทธ๋ฃน์˜ ์—ญํ• ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค

๊ทธ๋Ÿผ ๋ฐฐ๊ฒฝ์€ ์–ด๋Š์ •๋„ ํŒŒ์•…ํ–ˆ์œผ๋‹ˆ, CommonJS ์˜ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค

ESM ์— ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ์ธ import, export ๊ฐ€ ์žˆ๋“ฏ์ด
CommonJS ๋˜ํ•œ module.exports, exports, require ์„ธ ๊ฐ€์ง€์˜ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค

module.exports


๋จผ์ € module ์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋Š” ๊ณต์‹ ๋ฌธ์„œ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค

*The module free variable is a reference to the object representing the current module.*
ํ˜„์žฌ ๋ชจ๋“ˆ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ž์œ  ๋ณ€์ˆ˜(์˜ˆ์•ฝ์–ด)๋ผ๊ณ  ํ•˜๋Š”๋ฐ์š”, ๋นˆ ๊ฐ์ฒด๋กœ ์ดˆ๊ธฐํ™” ๋˜์–ด์žˆ๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค

์‰ฝ๊ฒŒ ์–˜๊ธฐํ•˜์ž๋ฉด, module ์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋Š” ํ˜„์žฌ ๋ชจ๋“ˆ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š”
์ผ์ข…์˜ ๊ฐ์ฒด(Object) ์ž…๋‹ˆ๋‹ค

๊ธฐ๋ณธ ๋ฌธ๋ฒ•์€ module.exports = expression ์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์‹์€ ๊ณง ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ’์œผ๋กœ ํ—ˆ์šฉ๋˜๋Š” ์–ด๋–ค ๊ฒƒ๋„ export ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

// ๐Ÿ“ utils.js

const PI = 3.14;
module.exports.PI = PI;


// ๐Ÿ“ app.js
const utils = require('./utils');
console.log(utils.PI); // 3.14

๋งŒ์•ฝ ์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•œ๋‹ค๋ฉด utils.js ํŒŒ์ผ์˜ module ๊ฐ์ฒด๋Š” ์–ด๋–ค ์ƒํƒœ์ผ๊นŒ์š”?

Module {
  ...
  exports: { PI: 3.14 }, // exports ๋ผ๋Š” ๊ฐ์ฒด ์•ˆ์— PI ๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค
  parent: Module {/*...*/},
  filename: '...',
  loaded: false,
  children: [],
  paths: [ /*...*/ ] 
}

๊ทธ๋Ÿผ module.exports.something ์ฒ˜๋Ÿผ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ 
๋ฐ”๋กœ module.exports = ๊ฐ’ ์œผ๋กœ ๋‚ด๋ณด๋‚ด๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

// ๐Ÿ“ utils.js

module.exports = 3.14;
console.log(module);

Module {
  ...
  exports: 3.14, // exports ๊ฐ’์€ 3.14 ์ž…๋‹ˆ๋‹ค
  parent: Module {/*...*/},
  filename: '...',
  loaded: false,
  children: [],
  paths: [ /*...*/ ] 
}

๋‹น์—ฐํ•˜์ง€๋งŒ module์˜ exports ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’์ด ๋ฉ๋‹ˆ๋‹ค

exports


exports ๋ผ๋Š” ํ‚ค์›Œ๋“œ๋กœ๋„ module.exports ์™€ ๊ฐ™์€ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
(์กฐ๊ธˆ์˜ ์˜ˆ์™ธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ์„ค๋ช…ํ• ๊ฒŒ์š”)

// ๐Ÿ“ utils.js

exports.PI = 3.14;
console.log(module.exports === exports); // true

console.log(exports); // { PI: 3.14 }

module.exports ๋Š” exports ์™€ ์™„์ „ํžˆ ๋™์ผํ•ฉ๋‹ˆ๋‹ค
๊ทธ๋ ‡๋‹ค๋Š” ๊ฒƒ์€ exports๊ฐ€ module.exports ๋ฅผ reference ์ฐธ์กฐ ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์˜๋ฏธ๊ฒ ์ฃ ?

exports ํ‚ค์›Œ๋“œ์— ๋Œ€ํ•ด Node.js API ๋ฌธ์„œ์—๋Š” ์ด๋Ÿฐ ์„ค๋ช…์ด ์žˆ์Šต๋‹ˆ๋‹ค

exports shortcut
The exports variable is available within a module's file-level scope,
and is assigned the value of module.exports before the module is evaluated.

exports ๋‹จ์ถ• ๊ตฌ๋ฌธ
exports ๋ณ€์ˆ˜๋Š” ๋ชจ๋“ˆ์˜ ํŒŒ์ผ ๋ ˆ๋ฒจ ์Šค์ฝ”ํ”„ ์•ˆ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“ˆ์ด ํ‰๊ฐ€๋˜๊ธฐ ์ „์— (require ๋˜๊ธฐ ์ „์—) module.exports ์˜ ๊ฐ’์„ ํ• ๋‹น ๋ฐ›์Šต๋‹ˆ๋‹ค

์œ„์˜ ์„ค๋ช…์˜ ์ด์œ ๋กœ ์ธํ•ด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค

// ๐Ÿ“ utils.js

module.exports = 3.14;
exports.PI = 3.14;

console.log(module.exports); // 3.14 ...?

๊ทผ๋ฐ ์ด๊ฑด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ๋‹น์—ฐํ•œ ๊ฒฐ๊ณผ๊ฐ€ ์•„๋‹๊นŒ์š”?

exports ๊ฐ€ ์ฐธ์กฐํ•˜๋Š”๊ฑด module.exports ๋ผ๋Š” ๋นˆ ์˜ค๋ธŒ์ ํŠธ์˜€๋Š”๋ฐ
์ด๊ฑธ 3.14๋กœ ๋ฎ์–ด ์”Œ์›Œ ๋ฒ„๋ฆฌ๋ฉด
exports ๊ฐ€ ์ฐธ์กฐํ•˜๋˜ ๊ฐ์ฒด๋Š” ์ € ์–ด๋”˜๊ฐ€๋กœ ์‚ฌ๋ผ์งˆ๊ฑฐ์—์š”...

๊ทธ๋ž˜์„œ exports ๋Š” module.exports = expression ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค
์•„๋ž˜์ฒ˜๋Ÿผ, ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค

export.PI = 3.14;
module.exports.sin = function (a) { /*...*/ }

console.log(module.exports) // { PI: 3.14, sin: function(a) { /*...*/ }

์„ค๋ช…์ด ์ž˜ ์ดํ•ด๊ฐ€ ์•ˆ๋˜์‹œ๋ฉด, ์ €๋ณด๋‹ค ํ›จ์”ฌ ์ž˜ ์ •๋ฆฌ๋œ ๋‹ค๋ฅธ ๊ธ€์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค

Node.js Module - exports vs module.exports
[NodeJS] module.exports ์™€ exports ์˜ ์ฐจ์ด์ 
module.exports์™€ exports ์ฐจ์ด ์ดํ•ดํ•˜๊ธฐ - 92Hz | Jongmin's Blog

require


require ๋Š” ๋‹ค๋ฅธ ๋ชจ๋“ˆ ํŒŒ์ผ์„ ๋ณผ๋Ÿฌ์˜ต๋‹ˆ๋‹ค

๋ชจ๋“ˆ์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•˜๋Š”๋ฐ์š”
๊ณต์‹ ๋ฌธ์„œ์—๋Š” ๋Œ€ํ‘œ์ ์œผ๋กœ๋Š” ์•„๋ž˜ 4 ๊ฐ€์ง€๋ฅผ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค

  1. File Modules
  2. Folders as Modules
  3. node_modules
  4. Global Directory
File Modules

์ƒ๋Œ€๊ฒฝ๋กœ์— ์žˆ๋Š” ํŒŒ์ผ ์ค‘ ํ™•์žฅ์ž๊ฐ€ .js, .json, .node ์ธ ํŒŒ์ผ์„ ๋ชจ๋“ˆ๋กœ์จ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค
ํ™•์žฅ์ž๋Š” ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

// ๐Ÿ“ data.json
{ "data": "Hello World!" }

// ๐Ÿ“ utils.js
module.exports.PI = 3.14;

// ๐Ÿ“ app.js

const data = require('./data');
const utils = require('./utils');

console.log(data); // { data: "Hello World!" }
console.log(utils.PI); // 3.14
Folders as Modules

ํด๋”๋ฅผ ์ƒ๋Œ€ ยท ์ ˆ๋Œ€ ๊ฒฝ๋กœ์˜ ํ˜•ํƒœ(/, ./, ../) ๋กœ require ํ•  ๋•Œ๋Š”
๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค

  1. package.json ํŒŒ์ผ์— ์ •์˜๋œ name ๊ณผ main ์˜ ๊ฐ’์„ ํ™œ์šฉ
  2. 1๋ฒˆ์—์„œ ํƒ์ƒ‰์— ์‹คํŒจํ•˜๋ฉด, ํ•ด๋‹น ํด๋”์— index.js ๋˜๋Š” index.node ํŒŒ์ผ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
  3. ๋ชจ๋‘ ์‹คํŒจํ•˜๋ฉด Cannot find module ์—๋Ÿฌ throw

๊ทผ๋ฐ ์‚ฌ์‹ค 1๋ฒˆ ์„ค๋ช…์€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์–ด์š”...
ํ˜น์‹œ ์•„์‹œ๋Š” ๋ถ„์ด ์žˆ์œผ์‹œ๋‹ค๋ฉด ๋„์™€์ฃผ์„ธ์š”

์•„๋ฌด๋ฆฌ ๊ณต์‹๋ฌธ์„œ์˜ ์„ค๋ช…๋Œ€๋กœ ํ•ด๋ณด๋ ค ํ•ด๋„ ์ž˜ ์•ˆ๋˜๋„ค์š”
๊ทธ๋ž˜์„œ ๋ชจ๋ฅด๋Š”๊ฑด ๊ณผ๊ฐํžˆ ์„ค๋ช…ํ•˜์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค

2๋ฒˆ์˜ ๊ฒฝ์šฐ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

// ๐Ÿ“ ./src/utils/index.js
// utils ํด๋” ์•„๋ž˜์— index.js ํŒŒ์ผ์„ ๋งŒ๋“ฆ
module.exports.PI = 3.14;

// ๐Ÿ“ ./src/app.js
const utils = require('./utils'); // ์ž๋™์œผ๋กœ ./utils/index.js ํŒŒ์ผ์„ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค
console.log(utils.PI); // 3.14
node_modules

๋งŒ์•ฝ ์ƒ๋Œ€, ์ ˆ๋Œ€ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ํ‘œ์‹œ ์—†์ด (/, ./, ../) require ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด
Node.js ๋Š” ํ˜„์žฌ ๋ชจ๋“ˆ์˜ ์ตœ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์‹œ์ž‘ํ•˜์—ฌ /node_modules ๋ผ๋Š” ๊ฒฝ๋กœ๋ฅผ ์•ž์— ๋ถ™์ด๊ณ  ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค

๋งŒ์•ฝ require('bar') ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค

  • /home/doondoony/project/node_modules/bar.js
  • /home/doondoony/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

์œ„ 4 ๊ฐ€์ง€ ํƒ์ƒ‰ ๊ฒฝ๋กœ๋Š” module.paths ํ”„๋กœํผํ‹ฐ์˜ ๊ฐ’๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค

GLOBAL_DIRECTORIES

Node.js ๋Š” ์œ„ 3 ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด OS์˜ ๊ธ€๋กœ๋ฒŒ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค

Node.js ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹ค์Œ GLOBAL_DIRECTORIES ๋ฅผ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค

  • $HOME/.node_modules
  • $HOME/.node_libraries
  • $PREFIX/lib/node

$PREFIX ์˜ ๊ฒฝ์šฐ๋Š” Node.js ๊ฐ€ ์„ค์ •ํ•œ node_prefix ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค
npm ์œผ๋กœ ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ง•์„ ํ•˜๊ณ  ๊ณ„์‹ ๋‹ค๋ฉด ์œ„์™€ ๊ฐ™์€ ๊ณณ๊นŒ์ง€ ํƒ์ƒ‰๋  ์ผ์€ ์—†๊ฒ ์ฃ ?

๐Ÿ AMD


์•”๋“œ ๊ทธ๊ฑฐ CPU ์•„๋‹Œ๊ฐ€์š”? ์•„ ์•”๋“œ ์•„์‹œ๋Š”๊ตฌ๋‚˜~ ์™€! ๋ผ์ด์  ! ์™€ ๊ฐ€์„ฑ๋น„!

์•„๋‹ˆ๊ตฌ์š” AMD(Asynchronous Module Definition) ์˜ ์•ฝ์ž์ž…๋‹ˆ๋‹ค
AMD๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ชฉํ‘œ๋ฅผ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด CommonJS ๋…๋ฆฝํ•œ ๊ทธ๋ฃน์ž…๋‹ˆ๋‹ค

The Asynchronous Module Definition (AMD) API specifies a mechanism
for defining modules such that the module and its dependencies can be asynchronously loaded.

AMD API ๋Š” ๋ชจ๋“ˆ๊ณผ ์ข…์†์„ฑ ํŒŒ์ผ๋“ค์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ชจ๋“ˆ์„ ์ •์˜ํ•˜๋Š” ๋งค์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค.

CommonJS, ESM ๋ชจ๋‘ ๋™๊ธฐ์‹ ๋กœ๋”ฉ ๋ฐฉ์‹์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค
๋”ฐ๋ผ์„œ ๋กœ๋“œํ•œ ๋ชจ๋“ˆ์ด ์•„์ง ์‚ฌ์šฉ๋˜์ง€ ์•Š์•˜์Œ์—๋„, ๋ฏธ๋ฆฌ ๋กœ๋”ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

AMD ๋Š” ๋™์  ๋กœ๋”ฉ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ณ , ์˜์กด์„ฑ ๊ด€๋ฆฌ๋‚˜ ๋ชจ๋“ˆํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” API๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค

๋‹ค๋ฅธ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ๋„ ์˜์กด์„ฑ ๊ด€๋ฆฌ์™€ ๋ชจ๋“ˆํ™”๋Š” ๋ชจ๋‘ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์—
๋™์  ๋กœ๋”ฉ์—์„œ ์ฐจ๋ณ„์ ์ด ์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์ฃ 

AMD ์— ๋Œ€ํ•ด ์กฐ์‚ฌํ•˜๋ฉด์„œ ๋Š๋‚€ ๊ฐœ์ธ์ ์ธ ์ƒ๊ฐ์€ 2018๋…„ ํ˜„์žฌ๋„ ์œ ํšจํ•œ๊ฐ€? ์ž…๋‹ˆ๋‹ค

๋จผ์ € ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š”...

  1. ES6 ๋“ฑ์žฅ๊ณผ ํ•จ๊ป˜ ๋“œ๋””์–ด ๋ธŒ๋ผ์šฐ์ €์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ESM ๋‚ด์žฅ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ ๋“ฑ์žฅ(!)
    (๋ฌผ๋ก  ํ•˜์œ„ ํ˜ธํ™˜์„ฑ ๋•๋ถ„์— ํŠธ๋žœ์ŠคํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ...)
  2. webpack ๊ณผ ๊ฐ™์€ ๋ชจ๋“ˆ ๋ฒˆ๋“ค๋Ÿฌ์˜ ๋น„๋™๊ธฐ ๋ชจ๋“ˆ ๋กœ๋”ฉ ์ฒ˜๋ฆฌ
  3. ๋™์  ๋กœ๋”ฉ ๋˜ํ•œ ๋‚ด์žฅ ๋ฉ”์„œ๋“œ import() ๋กœ ๊ตฌํ˜„๋˜์–ด proposal stage3 ๋‹จ๊ณ„ ์ž…๋‹ˆ๋‹ค

Node.js ์ชฝ์€ ์–ด๋–จ๊นŒ์š”

  1. CommonJS ๋ผ๋Š” ์นœ๊ตฌ๊ฐ€ ๊ตณ๊ฑดํ•˜๊ฒŒ ๋ฒ„ํ‹ฐ๊ณ  ์žˆ๊ณ 
  2. ์‹ฌ์ง€์–ด ์ตœ์‹  Node.js ๋Š” ESM ์„ ํ‘œ์ค€์œผ๋กœ ๋„์ž…ํ•˜๊ธฐ ์œ„ํ•ด ์‹คํ—˜์ ์ธ ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค (.mjs)

๊ทธ๋ž˜์„œ! ๊ทธ๋ƒฅ ์–ด๋–ป๊ฒŒ ์“ฐ๋Š”์ง€ ์ •๋„๋งŒ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค
(์ ˆ๋Œ€ ๊ท€์ฐฎ์•„์„œ ์•„๋‹˜ ์•„๋ฌดํŠผ ์•„๋‹˜)

// ๐Ÿ“ index.html

<!DOCTYPE html>
  <html lang="en">
    <head>
    <!-- head์— ๋“ค์–ด๊ฐˆ ์–ด๋–ค๊ฒƒ๋“ค -->
      </head>
<body>
      <!-- AMD ๊ตฌํ˜„์ฒด์ธ require.js ๋กœ๋”ฉ -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js"></script>
<!-- ์šฐ๋ฆฌ์˜ ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ ๋กœ๋”ฉ -->
  <script src="./index.js"></script>
</body>
</html>

// ๐Ÿ“ utils.js

// require.js ๋Š” define ์•ˆ์˜ callback ์Šคํƒ€์ผ๋กœ ๋ชจ๋“ˆ์„ ์ •์˜ํ•˜์—ฌ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค
define(function() {
  return {
    add(a, b) {
      return a + b;
    },
    subtract(a, b) {
      return a - b;
    }
  };
});

// ๐Ÿ“ app.js

// require ํ•จ์ˆ˜์˜ ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ๋ถˆ๋Ÿฌ์˜ฌ ๋ชจ๋“ˆ, ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” ํ•จ์ˆ˜๋กœ ์ธ์ž๋Š” ๋ฌผ๋Ÿฌ์˜จ ๋ชจ๋“ˆ์˜ ์ด๋ฆ„ ์ž…๋‹ˆ๋‹ค
require(["./utils"], function(utils) {
  const result = utils.add(1, 2);
  console.log('๊ฒฐ๊ณผ: ', result);
});

// ๊ฒฐ๊ณผ: 3

AMD ์™€ require.js ์— ๋Œ€ํ•œ ์ผ์ฒœํ•œ ๊ฒฝํ—˜์œผ๋กœ ์ธํ•ด
๋‹ค์Œ ์ข‹์€ ๊ธ€์„ ์ฐธ๊ณ ํ•˜์‹ฌ์ด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค

[RequireJS] RequireJS ์‚ฌ์šฉ ๋ฐฉ๋ฒ• ์ •๋ฆฌ
RequireJS - AMD์˜ ์ดํ•ด์™€ ๊ฐœ๋ฐœ
Learn X in Y minutes

๐ŸŒ‘ ๋งˆ์น˜๋ฉฐ


์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค

์ €๋Š” ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์„ ์‹œ์ž‘ํ•œ์ง€ ์–ผ๋งˆ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค
๊ทธ๋ž˜์„œ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์ด ํ‘œ์ค€์œผ๋กœ ๋„์ž…๋œ์ง€ ์–ผ๋งˆ ๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ์‚ฌ์‹ค์— ์ ์ž–์ด ๋†€๋ž์Šต๋‹ˆ๋‹ค... ๐Ÿ˜ฒ
๋ญ”๊ฐ€ ์ข‹์€ ์‹œ์ ˆ์— ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๊ตฌ๋‚˜ ๋ผ๋Š” ์ƒ๊ฐ๋„ ๋“ค์—ˆ๊ตฌ์š”!

๋‹ค์Œ ๊ธ€์€ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ๋„ ๋ฐฐ์› ๊ฒ ๋‹ค
Module Pattern ๊ณผ Module Pattern ์„ ์ ์šฉํ•˜์—ฌ ์‹ค์ œ๋กœ npm ์— ํŒจํ‚ค์ง€๋ฅผ ๋ฐฐํฌํ•ด๋ณผ๊นŒ ํ•ฉ๋‹ˆ๋‹ค

๊ธด ๊ธ€ ์ฝ์–ด์ฃผ์…”์„œ ํ•ญ์ƒ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค
์˜คํƒ€๋‚˜ ์ž˜๋ชป๋œ ์ •๋ณด์— ๋Œ€ํ•œ ์ œ๋ณด๋Š” ํ•ญ์ƒ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค ๐ŸŽŠ

๐Ÿ“– References


๋‹ค์Œ์˜ ๋งํฌ๋“ค์„ ๊ธ€์„ ์“ธ ๋•Œ ์ฐธ๊ณ ํ•˜์˜€์Šต๋‹ˆ๋‹ค

Module


ES6 Modules(ESM)


CommonJS


AMD


profile
Espresso Cream Cat DD

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

comment-user-thumbnail
2018๋…„ 12์›” 1์ผ

์—ญ์‹œ ํ”„๋กœ์„ธ์„œ๋Š” AMD์ฃ !!๋Š” ์•„๋‹ˆ๊ณ  ใ…‹ใ…‹,

Node ์ง„์˜์—์„œ native๋กœ ES Module์„ ์ง€์›ํ•˜๋ ค๋Š” ์‹œ๋„๊ฐ€ ์žˆ์—ˆ๊ณ , ์ตœ์‹  ๋ฒ„์ „์˜ node.js (11.3)์—์„œ๋Š” --experimental-modules flag๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  CommonJs์™€ ESM ๊ฐ„์˜ ๊ด€๊ณ„์— ๋Œ€ํ•ด ๋‹ค๋ฃฌ Medium ๊ธ€๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐธ๊ณ ๊ฐ€ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2018๋…„ 12์›” 1์ผ

์ด๊ธ€์„ ๋ฐ”ํƒ•์œผ๋กœ ์ €๋„ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์„ ์—ด๊ณตํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค ๋„ˆ๋ฌด ์ข‹์€ ๊ธ€ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค ~~ *)

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2018๋…„ 12์›” 1์ผ

๋ธ”๋กœ๊ทธ ์™ธ์ ์ธ ๋‚ด์šฉ์ธ๋ฐ..
์ œ๊ฐ€ ์•Œ๊ณ  ์žˆ๋Š” ํฌ๋ฆผํžˆ์–ด๋กœ์ฆˆ๋‹˜์ด ์ €์™€ ๊ฐ™์€ ๊ฐœ๋ฐœ์ž์˜€๋˜๊ฑด๊ฐ€์š”... ?

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2018๋…„ 12์›” 2์ผ

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋งŒ๋“ค๊ธฐ ๊ธฐ๋Œ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2018๋…„ 12์›” 2์ผ

์™€์•„ ์ข‹์€๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2018๋…„ 12์›” 21์ผ

์ข‹์€ ๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2019๋…„ 1์›” 7์ผ

๋‘”๋‘”์ด๋กœ ์‹œ์ž‘ํ•˜๋‹ค๋‹ˆ ์ข‹์€ ๊ธ€ ์ด๋„ค์š”ใ…Žใ…Ž

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2019๋…„ 7์›” 9์ผ

์•ˆ๋…•ํ•˜์„ธ์š”. ์ข€ ๋‹ค๋ฅธ ์งˆ๋ฌธ์ธ๋ฐ ์ฝ”๋“œ

 ๋ถ€๋ถ„์— ์Šคํƒ€์ผ๋ง์€ ์–ด๋–ป๊ฒŒ ํ•˜์‹ ๊ฑด๊ฐ€์š”? ^^;;;

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 6์›” 15์ผ

์™€ ์ด๋ฒˆ์— ๋ฐœํ‘œ๋ฅผ ๋ชจ๋“ˆ๋กœ ํ–ˆ๋Š”๋ฐ ๋ฐœํ‘œ๋ฅผ ๋‹คํ•˜๊ณ  ๋‚˜์„œ ์ด๊ธ€์„ ๋ดค๋„ค์š”.
์ด๊ธ€์„ ๋ดค๋‹ค๋ฉด ๋ฐœํ‘œ์ค€๋น„๋ฅผ ๋” ์•Œ์ฐจ๊ฒŒ ํ–ˆ์„๊บผ ๊ฐ™์€๋ฐ ๋Šฆ๊ฒŒ ๋ด์„œ ์•„์‰ฝ๋„ค์š”.
์ข‹์€๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2020๋…„ 12์›” 18์ผ

์ž˜ ์ฝ์—ˆ์Šต๋‹ˆ๋‹ค. : )

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ