1<!DOCTYPE html><html lang="ko"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, viewport-fit=cover"/><meta name="google-site-verification" content="vtaBV0ETmVVgtWBi6a2TUBROjDjHCT5hILk7MxdF7B0"/><style> 2 @media (max-width: 390px) { 3 .formkit-slide-in { 4 display: none; 5 } 6 } 7 @media (max-height: 740px) { 8 .formkit-slide-in { 9 display: none; 10 } 11 } 12 </style><link rel="preconnect" href="https://KB3ECWAG70-dsn.algolia.net" crossorigin="true"/><title>Blog | kimcoder</title><meta name="description" content="íë¬ê°ë ì§ì, íìµì ê³¼ì , ê²½í ì 리를 ìì£¼ë¡ ìì±ëë ê¸ë¤ì ëë¤."/><link rel="icon" type="image/x-icon" href="/favicon.png"/><link rel="apple-touch-icon" href="/favicon.png"/><meta property="og:type" content="website"/><meta property="og:url" content="https://kimcoder.io"/><meta property="og:title" content="Blog"/><meta property="og:description" content="íë¬ê°ë ì§ì, íìµì ê³¼ì , ê²½í ì 리를 ìì£¼ë¡ ìì±ëë ê¸ë¤ì ëë¤."/><meta property="og:image" content="/kimcoder-og.png"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:site" content="@kimcoder"/><meta name="twitter:creator" content="@kimcoder"/><meta name="twitter:title" content="Blog"/><meta name="twitter:description" content="íë¬ê°ë ì§ì, íìµì ê³¼ì , ê²½í ì 리를 ìì£¼ë¡ ìì±ëë ê¸ë¤ì ëë¤."/><meta name="twitter:image" content="/kimcoder-og.png"/><meta name="next-head-count" content="21"/>
12<script>
vendor: 327 bytes, lines 12-16
12(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 13new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 14j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 15'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 16})(window,document,'script','dataLayer','
16GTM-MKLQHRB
vendor: 3 bytes, line 16
16');
16</script>
16<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /><link rel="preload" href="/_next/static/css/5ca929a8400de023.css" as="style" crossorigin=""/><link rel="stylesheet" href="/_next/static/css/5ca929a8400de023.css" crossorigin="" data-n-g=""/><link rel="preload" href="/_next/static/css/d1b9f621a8797bcb.css" as="style" crossorigin=""/><link rel="stylesheet" href="/_next/static/css/d1b9f621a8797bcb.css" crossorigin="" data-n-p=""/><noscript data-n-css=""></noscript>
16<script defer="" crossorigin="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script>
16<script src="/_next/static/chunks/webpack-df1f9c351e43cde0.js" defer="" crossorigin=""></script>
16<script src="/_next/static/chunks/framework-fda0a023b274c574.js" defer="" crossorigin=""></script>
16<script src="/_next/static/chunks/main-c69e4a6afd49bbe5.js" defer="" crossorigin=""></script>
16<script src="/_next/static/chunks/pages/_app-37680da0538876f5.js" defer="" crossorigin=""></script>
16<script src="/_next/static/chunks/336-1f3c353cd534fe20.js" defer="" crossorigin=""></script>
16<script src="/_next/static/chunks/pages/blog-470c084b010d54b4.js" defer="" crossorigin=""></script>
16<script src="/_next/static/mYpFDr1DZDEyR2tzQItwY/_buildManifest.js" defer="" crossorigin=""></script>
16<script src="/_next/static/mYpFDr1DZDEyR2tzQItwY/_ssgManifest.js" defer="" crossorigin=""></script>
16<style id="__jsx-6e762080cf24aab">div.jsx-6e762080cf24aab{background:#fff;position:-webkit-sticky;position:sticky}div.shadow.jsx-6e762080cf24aab{-webkit-box-shadow:rgba(0,0,0,.06)0px 6px 20px;-moz-box-shadow:rgba(0,0,0,.06)0px 6px 20px;box-shadow:rgba(0,0,0,.06)0px 6px 20px}</style><style data-href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap">@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/l/font?kit=UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfMZs&skey=c491285d6722e4fa&v=v20) format('woff')}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/l/font?kit=UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuI6fMZs&skey=c491285d6722e4fa&v=v20) format('woff')}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/l/font?kit=UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuGKYMZs&skey=c491285d6722e4fa&v=v20) format('woff')}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/l/font?kit=UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuFuYMZs&skey=c491285d6722e4fa&v=v20) format('woff')}@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+1F00-1FFF}@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2');
16unicode-range:U+1F00-1FFF}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+1F00-1FFF}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;
16src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+1F00-1FFF}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7W0Q5n-wU.woff2) format('woff2');unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/inter/v20/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7W0Q5nw.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}</style></head><body class="font-sans antialiased text-gray-900"><div id="__next"><div class="h-full min-h-full"><div style="top:0" class="jsx-6e762080cf24aab z-10"><div class="border-b border-gray-200 bg-white"><div class="container mx-auto"><div class="flex flex-wrap items-center"><div class="nav-height flex w-60 items-center"><a href="/"><h1 id="page-title">@kimcoder</h1></a></div><div class="flex-grow hidden lg:block ml-8"><div><button type="button" class="group py-2 px-3 border-gray-200 border hover:text-gray-600 hover:border-gray-300 transition duration-150 ease-in-out pointer flex items-center bg-gray-50 text-left w-full text-gray-500 rounded-lg text-sm align-middle"><svg width="1em" height="1em" class="mr-3 align-middle text-gray-600 flex-shrink-0 group-hover:text-gray-700" style="margin-bottom:2px" viewBox="0 0 20 20"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" stroke-width="2" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg>Search words<span class="ml-auto invisible lg:visible"><kbd class="border border-gray-300 mr-1 bg-gray-100 align-middle p-0 inline-flex justify-center items-center text-xs text-center mr-0 rounded group-hover:border-gray-300 transition duration-150 ease-in-out " style="min-width:1.8em">â</kbd><kbd class="border border-gray-300 bg-gray-100 align-middle p-0 inline-flex justify-center items-center text-xs text-center ml-auto mr-0 rounded group-hover:border-gray-300 transition duration-150 ease-in-out " style="min-width:1.8em">K</kbd></span></button></div></div><div class="flex-grow nav-height flex w-3/4 items-center justify-between space-x-4 md:w-auto md:justify-end md:space-x-8"><div class="flex space-x-4 text-sm md:space-x-8 md:text-base"><div><a class="font-medium leading-6" href="/blog">Blog</a></div><div><a class="font-medium leading-6" href="/books">Books</a></div></div><div class="flex"><a href="https://github.com/kimcoder" target="_blank" rel="noopener noreferrer"><span class="sr-only">GitHub</span><svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path></svg></a><a class="ml-2.5" href="https://www.facebook.com/kimcoder" target="_blank" rel="noopener noreferrer"><span class="sr-only">LinkedIn</span><svg width="24" height="24" viewBox="0 0 30 30" fill="#1877f2"><path d="M30 15.091C30 6.756 23.285 0 15 0S0 6.756 0 15.091C0 22.625 5.484 28.868 12.656 30V19.454H8.848V15.09h3.808v-3.324c0-3.782 2.239-5.872 5.666-5.872 1.64 0 3.358.295 3.358.295v3.714h-1.893c-1.863 0-2.443 1.164-2.443 2.358v2.83h4.16l-.665 4.362h-3.495V30C24.516 28.868 30 22.625 30 15.091z" fill="#1877f2"></path></svg></a><a class="ml-2.5" href="https://www.linkedin.com/in/daehyun-kim-b9a26716b/" target="_blank" rel="noopener noreferrer"><span class="sr-only">Facebook</span><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#0073b1"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"></path></svg></a></div></div></div></div></div></div><div class="container mx-auto bg-white px-4 pt-16 pb-20 lg:pt-24 lg:pb-28"><div class="relative"><div><h1 class="text-3xl font-extrabold leading-9 tracking-tight text-gray-900 sm:text-4xl sm:leading-10 lg:text-5xl ">Blog ð</h1><div class="mt-3 sm:mt-4 lg:grid lg:items-center lg:gap-5"><p class="text-xl leading-7 text-gray-500">íë¬ê°ë ì§ì, íìµì ê³¼ì , ê²½í ì 리를 ìì£¼ë¡ ìì±ëë ê¸ë¤ì
ëë¤.</p></div></div><div class="markdown_markdown__wTkaE">
16<div class="border-t mt-6 grid gap-16 border-gray-100 pt-10 lg:grid-cols-2 lg:gap-x-5 lg:gap-y-12"><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2025-10-1">2025.10.1</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/about-tanstack-start"><span class="cursor-pointer hover:underline">TanStack Start ìì보기</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">TanStackì ì ê· í ì¤í íë ììí¬ì¸ TanStack Startì ëí´ ììë´
ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/about-tanstack-start">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2024-02-04">2024.02.04</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/ts-pattern"><span class="cursor-pointer hover:underline">ts-patternì íì©íì¬ í´ê²°íë ê²</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">í¨í´ ë§¤ì¹ ê·¸ë¦¬ê³ ts-patternì ëí´ ììë³´ê³ , ì´ë¥¼ íì©íì¬ ë¬¸ì ë¤ì í´ê²°íë ì¬ë¡ë¤ì ìê°í©ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/ts-pattern">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2022-07-01">2022.07.01</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/micro-frontend-module-federation"><span class="cursor-pointer hover:underline">Micro Frontend, ê·¸ë¦¬ê³ Webpack Module Federation</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">ë§ì´í¬ë¡ íë¡ í¸ìëì ê´í ê³ ì°°ê³¼ ì¹í© 5ì Module Federation ì¼ë¶ 기ë¥ì ëí´ ììë³´ê³ , ì ë¹í ìì ì½ë ìì±ì íµí´ ì»ì ìê°ì 기ë¡íë ê¸ì
ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/micro-frontend-module-federation">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2022-05-19">2022.05.19</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/clean-frontend-architecture"><span class="cursor-pointer hover:underline">í´ë¦°í íë¡ í¸ìë ìí¤í
ì²ë¥¼ í¥í 첫 걸ì</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">ë³ê²½ì ì ì°í íë¡ í¸ìë ìí¤í
ì²ë¥¼ 구ì±íë íëì ë°©ë²ê³¼ ë°©ë²ì 근거, ê·¸ë¦¬ê³ ì´ë¥¼ ì ì´í´ ì¤ ì ìë ESLintì ê·ì¹ê¹ì§ ìê°íê³ ì í©ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/clean-frontend-architecture">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2022-02-19">2022.02.19</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/javascript-data-types"><span class="cursor-pointer hover:underline">ìë°ì¤í¬ë¦½í¸ì ë°ì´í° íì
ê³¼ ë©ëª¨ë¦¬</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">ìë°ì¤í¬ë¦½í¸ìì ì¬ì©í ì ìë ë°ì´í° íì
ì ì¢
ë¥ì ëªê°ì§ í¹ì§ë¤ì ììë´
ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/javascript-data-types">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2022-02-07">2022.02.07</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/eslint-import-order"><span class="cursor-pointer hover:underline">eslint import rule ì¤ì ì ì´ì </span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">import구문ì ì ë ¬ ê·ì¹ ì ì©ì ì´ì ì ëí´ ìê°í©ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/eslint-import-order">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2022-01-21">2022.01.21</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/enum"><span class="cursor-pointer hover:underline">Enumì ëí ê³ ì°°</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">Typescriptì Enumì ëí´ ììë´
ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/enum">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2022-01-18">2022.01.18</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/javascript-pass-by-value-function-parameters"><span class="cursor-pointer hover:underline">JavaScript Pass By Value Function Parameters</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">Kent C. Doddsì JavaScript Pass By Value Function Parameters ê¸ì ë²ìíììµëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/javascript-pass-by-value-function-parameters">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2022-01-03">2022.01.03</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/interface-vs-type"><span class="cursor-pointer hover:underline">Interfaces vs Type Aliases</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">Typescriptì Interfaceì Type Aliasingì ëí´ ììë´
ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/interface-vs-type">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2021-12-12">2021.12.12</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/image-optimize"><span class="cursor-pointer hover:underline">ì´ë¯¸ì§ íì¼ ìµì í를 íµí ì¹ ì±ë¥ í¥ì</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">ì¹ìì ì주 ì¬ì©ëì´ì§ë ì´ë¯¸ì§ì ëí´ ììë³´ê³ , ìµì í ì리ì ë°©ìì ëí´ ììë´
ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/image-optimize">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2018-10-11">2018.10.11</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/react-simple-image-slider-3"><span class="cursor-pointer hover:underline">React ì»´í¬ëí¸ ì ì기 3 / 3</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/react-simple-image-slider-3">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2018-10-08">2018.10.08</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/react-simple-image-slider-2"><span class="cursor-pointer hover:underline">React ì»´í¬ëí¸ ì ì기 2 / 3</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/react-simple-image-slider-2">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2018-09-21">2018.09.21</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/react-simple-image-slider-1"><span class="cursor-pointer hover:underline">React ì»´í¬ëí¸ ì ì기 1 / 3</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/react-simple-image-slider-1">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div><div class="space-y-2 pb-6"><div class="posted text-sm leading-5 text-gray-500"><time dateTime="2018-09-17">2018.09.17</time></div><h3 class="mt-2 text-2xl font-semibold leading-7 text-gray-900"><a class="block" href="/blog/tdz"><span class="cursor-pointer hover:underline">TDZ(Temporal Dead Zone)</span> </a></h3><div class="mt-3 leading-6 text-gray-500 "><div class="markdown_markdown__wTkaE text-gray-500">TDZ(Temporal Dead Zone)ì ëí´ ììë´
ëë¤.</div></div><div class="mt-3"><a class="transition text-base font-semibold leading-6 text-blue-600 duration-150 ease-in-out hover:text-blue-500" href="/blog/tdz">ì½ì¼ë¬ ê°ê¸°<span aria-hidden="true">â</span></a></div></div></div></div></div></div></div><!--$--><!--/$--></div>
16<script id="__NEXT_DATA__" type="application/json" crossorigin="">{"props":{"pageProps":{"posts":[{"content":"\nìµê·¼ì íì¬ìì ê³µì íë TanStack Startì ëí ë´ì©ì ê°ì§ê³ ë¸ë¡ê·¸ìë ê¸ì ì¨ë³´ê³ ì íë¤.\n\ní´ë¼ì´ì¸í¸ ì¬ì´ë ë ëë§ì ì£¼ë¡ íì©íìë 과거ì ë¬ë¦¬, ë§ì íì¬ìì í ì¤í íë ììí¬ë¥¼ ëì
íì¬ íì´ì§ ë ëë§ì ë¤ìí ë°©ìì¼ë¡ ì²ë¦¬íì¬ ìë¹ì¤ë¤ì ì´ìíê³ ìë¤.\n\në´ê° ê²½ííë íì¬ì ìë¹ì¤ë¤ ê·¸ë¦¬ê³ íì¬ìë ì´ìíê³ ìë ìë¹ì¤ë¤ì Next.js를 ì£¼ë¡ íì©íê³ ìì§ë§, TanStackìì ìë¡ê² ë°íí TanStack Startë¼ë í ì¤í íë ììí¬ê° í¥ë¯¸ë¡ìì ê°ë¨í ì´í´ë³´ìë¤.\n\n## TanStack Start?\n\nTanStack Startë TanStack Router를 ë§ë Tanner Linsleyê° ì£¼ëíë ìë¡ì´ íì¤í íë ììí¬ì´ë¤.\n\n\u003cdiv className='my-4 block justify-start gap-4 sm:flex'\u003e\n \u003cimg src='/assets/images/about-tanstack-start-1.jpg' className='w-full sm:w-1/3' /\u003e\n \u003cdiv\u003e\n \u003cblockquote className='text-lg font-bold mb-6 flex flex-col gap-4 italic'\u003e\n \u003cp\u003eTanStack Startë\u003c/p\u003e\n \u003cp\u003e95%ì TanStack Routerì\u003c/p\u003e\n \u003cp\u003e5%ì ìë²ì¬ì´ë ìì
ì ìí ìì ë ì´ì´ë¡ ì´ë£¨ì´ì ¸ìë¤.\u003c/p\u003e\n \u003c/blockquote\u003e\n \u003cp\u003e\n Tanner Linsleyë TanStack Startì ëí´{' '}\n \u003ca className='custom-anchor youtube' href='https://www.youtube.com/watch?v=4PymccvinIo\u0026t=179s'\u003e\n Next Gen Fullstack React with TanStack\n \u003c/a\u003e{' '}\n ì í¬ë¸ ìììì ìì ê°ì´ ê°ëµíê² ìê°íìë¤.\n \u003c/p\u003e\n \u003c/div\u003e\n\u003c/div\u003e\n\n5%ì ìë²ì¬ì´ë ë ì´ì´ë **Vite**, **Nitro** ë ê°ì§ë¡ 구ì±ëìë¤ê³ ìê°ë¥¼ íìë¤. ììììë Vinxië¼ë íë ììí¬ë ê°ì´ ì¸ê¸íìì§ë§, Vinxië RC ë²ì ìì ì ê±°ëìë¤.\n\n- **Vite** - 기본 ê°ë° íê²½ êµ¬ì± ë° ë¹ë, ê°ë° ìë² ì ê³µ íë ììí¬\n- **Nitro** - ìë²ë¦¬ì¤ ì°ì (Serverless-first)ì ì¸ ì¹ ì í리ì¼ì´ì
íë ììí¬ ( Nuxt3ì íµì¬ ìì§ )\n\në°ë¼ì, TanStack Start를 ì¬ì©íë¤ë©´ TanStack Routerìì ì ê³µíë ê¸°ë¥ ì¸ì ì¶ê°ì ì¼ë¡ ìëì ê°ì 기ë¥ë¤ì ì´ì©í ì ìë¤.\n\n- **ì ì²´ 문ì SSR ë° íì´ëë ì´ì
**\n- **ì¤í¸ë¦¬ë° SSR**\n- **ìë² í¨ì / RPC**\n- **ì§ìëë ë¤ìí ë°íì ( Node, Bun, Deno, Edge )**\n\nê³µì 문ìììë Tanstack Routerë¡ í´ê²°í ì ìë ë¶ë¶ ì¸ì ìì ëì´ë 기ë¥ë¤ì´ íìí ê²½ì° ì¬ì©ì ê¶ì¥íê³ ìë¤.\n\nReact Server Components(ì´í RSC) ê°ì ê²½ì°ë íì¬ ì§ìíì§ ìê³ ìì¼ë©°, ê³§ ì§ìí ìì ì´ë¼ê³ ë°í ìíì´ë¤.\n\n## TanStack Router?\n\nTanStack Start를 ì¬ì©íë ¤ë©´ 먼ì TanStack Routerì ëí´ ììëë©´ ë§¤ì° ì½ê² ì ê·¼í ì ìëë°, ì¼ë°ì ì¼ë¡ CSR íë ììí¬ë¡ ë¶ë¥ëì´ ìëì ê°ì 기ë¥ë¤ì ì´ì©í ì ìë¤.\n\n- **모ë ë¼ì°í
ê´ë ¨ ìì(ê²½ë¡, íë¼ë¯¸í°, ê²ì 매ê°ë³ì ë±)ë¤ì ëí´ ìë²½í íì
ì¤í¬ë¦½í¸ ì§ìì íµí´ íì
ìì ì± ì ê³µ**\n\n- **íì¼ ê¸°ë° ë¼ì°í
ìì¤í
ê³¼ ì¤ì²©, ë ì´ìì 구조를 íµí ì ì°í ë¼ì°í
ì¤ê³**\n\n- **ë´ì¥ë ë°ì´í° ë¡ë \u0026 ìºì±**\n\n- **ë¼ì°í¸ 매ì¹/ë¡ê¹
미ë¤ì¨ì´ ì ê³µ**\n\nReact Router를 ì¬ì©í´ 본 ê²½íì´ ìë¤ë©´ ì´ë µì§ ìê² ì¬ì©í ì ìë 기ë¥ë¤ì´ê³ , íë¥í íì
ì¤í¬ë¦½í¸ ì§ì ëë¶ì ì¢ì DXê¹ì§ ëë ì ì기ë íë¤.\n\nì¡°ê¸ ë ìì¸í ììë³´ë©´ ì¬ë¯¸ëê²ë **TanStack Routerë ì¤íì 기ë¥ì ì¬ì©íì¬ SSRì í ì ìë¤ë ì **ì´ë¤.\n\n### TanStack Routerì SSR\n\n기ë¥ì ì¼ë¡ë ì ì²´ 문ì SSR ë° íì´ëë ì´ì
, Streaming SSRì´ ì§ìëëë° CSRì¼ë¡ë§ ì¤ì í TanStack Routerê³¼ë ë¤ë¥´ê² ìëì ê°ì´ **ìë², í´ë¼ì´ì¸í¸ ìí¸ë¦¬ 모ëì´ íìíë¤.**\n\n```tsx title=\"src/entry-server.tsx\"\nimport { createRequestHandler, defaultStreamHandler } from '@tanstack/react-router/ssr/server';\nimport { createRouter } from './router';
16\n\nexport async function render({ request }: { request: Request }) {\n const handler = createRequestHandler({ request, createRouter });\n\n return await handler(defaultStreamHandler);\n}\n```\n\n```tsx title=\"src/entry-client.tsx\"\nimport { hydrateRoot } from 'react-dom/client';\nimport { RouterClient } from '@tanstack/react-router/ssr/client';\nimport { createRouter } from './router';\n\nconst router = createRouter();\n\nhydrateRoot(document, \u003cRouterClient router={router} /\u003e);\n```\n\nìì ê°ì´ ìí¸ë¦¬ë¤ì 구ì±í í, ìë² ë°íììì ìëì ê°ì´ ìë² ëª¨ëì ì¤ííì¬ SSRì ì²ë¦¬í ì ìë¤.\n\n```json title=\"package.json\"\n ...\n \"scripts\": {\n \"serve\": \"NODE_ENV=production node server.js\",\n }\n\n// server.js ë´ë¶ìë server, client ìí¸ë¦¬ë¥¼ ë¶ë¬ìì SSRì ì²ë¦¬íë ì½ëê° ë¤ì´ê°ë¤.\n```\n\në ìì¸í ìì ë [ê³µì 문ìì ìì ](https://tanstack.com/router/latest/docs/framework/react/examples/basic-ssr-streaming-file-based)ìì íì¸í ì ìë¤.\n\n## TanStack Startì Tanstack Routerì ê´ê³\n\n**ë´ë¶ì ì¼ë¡ @tanstack/router-core 모ëì íµí´ SSRì´ ì§ì**ëë©°, ì´ë **TanStack Startììë ëì¼íê² êµ¬ì±**ëì´ ìë ìí©ì´ë¤.\n\nTanStack Routerì SSR ê´ë ¨ 주ì 기ë¥ë¤, ê·¸ë¦¬ê³ TanStack Startê³¼ ì½íìë ë´ì©ë¤ì ì 리íë©´ ìëê³¼ ê°ì´ ë³¼ ì ìë¤.\n\n| ìì | ë´ì© |\n| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| 2023ë
| @tanstack/router ì´ê¸° ê°ë° ìì.\u003cbr/\u003eíµì¬ ê²½ë¡ ë§¤ì¹, history ê´ë¦¬, loader 구조 ì¤ê³ì ì§ì¤. SSRì ìì§ ìì. |\n| 2024ë
ìë°ê¸° | **@tanstack/router-core v1.0 ë² í ë¨ê³ìì createServerRouter, dehydrate, hydrate APIê° ì¤íì ì¼ë¡ ëì
ë¨**\u003cbr/\u003eìë²ìì ë¼ì°í°ë¥¼ ì¤ííê³ loader를 í리í¨ì¹íë SSR ì í¸ë¦¬í°ê° ì¶ê°ë¨. |\n| 2024ë
íë°ê¸° | **@tanstack/start ìí ê³µê°.**\u003cbr/\u003e@tanstack/router-core SSR ì í¸ë¦¬í°ë¥¼ ì¤ì Vite + React íê²½ìì DX ì¢ê² ëíí íì¼ ê¸°ë° íì¤í íë ììí¬ë¡ ë±ì¥. |\n| 2025ë
7ì | @tanstack/router-core ì SSR 기ë¥ì ì¬ì í experimentalë¡ ê´ë¦¬ ì¤.\u003cbr/\u003e**@tanstack/startë** router-core SSRì 기본ì¼ë¡ ì¬ì©íì¬ createServerRouter + Vite SSR + React Query hydrationì ìëì¼ë¡ ì²ë¦¬.\u003cbr/\u003eë¤ìí ì¤ì ì¬ì© í¼ëë°±ì ë°ì **ìì í ì§í ì¤.** |\n| 2025ë
9ì | **@tanstack/start RC 릴리ì¦.** |\n\nì¶ì¸¡ì»¨ë° TanStack Router를 ì ê³µí ë¹ìë¶í° SSR 기ë¥ì ì¼ëì ëê³ ì¤ê³ê° ì§íëì§ ìììê¹ ìê°ëë¤.\n\nTanStack Startê° RC ë²ì ì¼ë¡ 릴리ì¦ë ì§ê¸ë ì¬ì í @tanstack/router-coreì ëí ìì¡´ì±ì ê°ì§ê³ ìë ìí©ì´ë¤.\n\n```mermaid\ngraph TD\n Start[\"\u003cb\u003e@tanstack/start\u003c/b\u003e\"]\n\n %% start -\u003e (direct deps)\n Start --\u003e|\"Startì Client/Server ìí¸ë¦¬(ë°íì ì°ê²°)\"| RSC[\"@tanstack/react-start-client\\n@tanstack/react-start-server\"]\n Start --\u003e|ë¼ì°í° ê³µíµ ì í¸/í¬í¼ ë ì´ì´| RU[\"@tanstack/router-utils\"]\n Start --\u003e|\"React ë¼ì°í° íµí©(ë¼ì°í
API)\"| RR[\"\u003cb\u003e@tanstack/react-router\u003c/b\u003e\"]\n Start --\u003e|Start íë¬ê·¸ì¸ ìì¤í
ì½ì´| SPC[\"@tanstack/start-plugin-core\"]\n Start --\u003e|\"í´ë¼/ìë² ì½ì´ ë°íì(ê¸°ë° ëª¨ë)\"| SCC[\"@tanstack/start-client-core\\n@tanstack/start-server-core\"]\n\n %% each -\u003e router-core (shared foundation)\n RSC --\u003e RC[\"\u003cb\u003e@tanstack/router-core\u003c/b\u003e\"]\n RU --\u003e RC\n RR --\u003e RC\n SPC --\u003e RC\n SCC --\u003e RC\n```\n\n## TanStack Startì 주ì 기ë¥ë¤\n\nTanStack Startì 주ì 기ë¥ë¤ì íëì© ì´í´ë³´ì.\n\n- **ì ì²´ 문ì SSR ë° íì´ëë ì´ì
**\n- **ì¤í¸ë¦¬ë° SSR**\n- **ìë² í¨ì / RPC**\n- **ì§ìëë ë¤ìí ë°íì ( Node, Bu
16n, Deno, Edge )**\n\n### ì ì²´ 문ì SSR ë° íì´ëë ì´ì
\n\nTanStack Startë **기본ì ì¼ë¡ 모ë ë¼ì°í¸ì ëí´ SSRì´ íì±í**ëì´ ìë¤.\nì´ë ë£¨í¸ ë¼ì°í¸ìì ì ìì¼ë¡ ì¤ì ì í ì ìê³ , íì ë¼ì°í¸ ê°ë³ì ì¼ë¡ ì¤ì ì´ ê°ë¥íë¤.\n\nSSR ëìì ìë²ë¡ ìì²ì´ ë¤ì´ì¤ë©´ ìë²ê° í´ë¹ ë¼ì°í¸ì `beforeLoad`, `loader`를 ì¤ííê³ , ì»´í¬ëí¸ë¥¼ HTMLë¡ ë ëë§í ë¤ ë´ë ¤ì¤ë¤.\nê·¸ë¦¬ê³ ë¸ë¼ì°ì ììë `\u003cScripts /\u003e`를 íµí´ ë¡ëë ë²ë¤ì´ hydrationì ìííë©´ì \"ì´ë¯¸ ê·¸ë ¤ì§ HTML\"ì \"ëìíë React ì±\"ì¼ë¡ ë°ê¾¼ë¤. ( ê³µì 문ìììë ì´ ê¸°ë³¸ ëìì ssr: trueë¡ ì¤ëª
)\n\n**TanStack Startê° ì ì²´ 문ì(full-document) SSRì´ë¼ê³ ë§íë ì´ì ë, ë£¨í¸ ë¼ì°í¸ìì `\u003chtml\u003e`, `\u003chead\u003e`, `\u003cbody\u003e`ê¹ì§ í¬í¨í 문ì 골격ì ì§ì 구ì±íëë¡ ê°ì´ëí기 ë문ì´ë¤.**\nì를 ë¤ì´ Start 기본 ìì ììë ë£¨í¸ ë¼ì°í¸ìì shellComponent를 ì ìíê³ , ê·¸ ìì `\u003cHeadContent /\u003e`ì `\u003cScripts /\u003e`를 ë°°ì¹íë¤.\n\n```tsx title=\"src/routes/__root.tsx\"\nimport { HeadContent, Scripts, Outlet, createRootRoute } from '@tanstack/react-router';
16\n\nexport const Route = createRootRoute({\n shellComponent: RootDocument,\n});\n\nfunction RootDocument({ children }: { children: React.ReactNode }) {\n return (\n \u003chtml\u003e\n \u003chead\u003e\n \u003cHeadContent /\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n {children}\n \u003cScripts /\u003e\n \u003c/body\u003e\n \u003c/html\u003e\n );\n}\n```\n\n```tsx title=\"src/routes/demo/start/ssr/full-ssr.tsx ( íì ë¼ì°í¸ì ì 체 문ì SSR ìì  )\" {4-6}\nimport { createFileRoute } from '@tanstack/react-router';\nimport { createServerFn } from '@tanstack/react-start';\n\nexport const getPunkSongs = createServerFn({\n method: 'GET',\n}).handler(async () =\u003e [\n { id: 1, name: 'Teenage Dirtbag', artist: 'Wheatus' },\n { id: 2, name: 'Smells Like Teen Spirit', artist: 'Nirvana' },\n { id: 3, name: 'The Middle', artist: 'Jimmy Eat World' },\n { id: 4, name: 'My Own Worst Enemy', artist: 'Lit' },\n { id: 5, name: 'Fat Lip', artist: 'Sum 41' },\n { id: 6, name: 'All the Small Things', artist: 'blink-182' },\n { id: 7, name: 'Beverly Hills', artist: 'Weezer' },\n]);\n\nexport const Route = createFileRoute('/demo/start/ssr/full-ssr')({\n component: RouteComponent,\n loader: async () =\u003e await getPunkSongs(), // ìë²ìì ë°ì´í° íì¹\n});\n// loaderë \"ì´ê¸° ìì² ëë ìë²ìì\", \"ì´í í´ë¼ì´ì¸í¸ ë´ë¹ê²ì´ì
ììë ë¸ë¼ì°ì ìì\"ë ì¤íë ì ìë¤.\n// ê·¸ëì process.env ê°ì ê°ì loader ììì ë°ë¡ ì½ì¼ë©´, í´ë¼ì´ì¸í¸ ë²ë¤ì ìì´ê±°ë(í¹ì ë°íììì í°ì§ê±°ë) 문ì ê° ëë¤.\n// ì´ë° ê²½ì°ìë ìë² í¨ì(createServerFn)ë ìë² ì ì© ì í¸(createServerOnlyFn)ë¡ ê²½ê³ë¥¼ ëª
íí ëëë ê² íµì¬ì´ë¤.\n\nfunction RouteComponent() {\n const punkSongs = Route.useLoaderData();\n\n return (\n \u003cdiv\n className='flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white'\n style={{\n backgroundImage: 'radial-gradient(50% 50% at 20% 60%, #1a1a1a 0%, #0a0a0a 50%, #000000 100%)',\n }}\u003e\n \u003cdiv className='w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10'\u003e\n \u003ch1 className='text-3xl font-bold mb-6 text-purple-400'\u003eFull SSR - Punk Songs\u003c/h1\u003e\n \u003cul className='space-y-3'\u003e\n {punkSongs.map((song) =\u003e (\n \u003cli key={song.id} className='bg-white/10 border border-white/20 rounded-lg p-4 backdrop-blur-sm shadow-md'\u003e\n \u003cspan className='text-lg text-white font-medium'\u003e{song.name}\u003c/span\u003e\n \u003cspan className='text-white/60'\u003e - {song.artist}\u003c/span\u003e\n \u003c/li\u003e\n ))}\n \u003c/ul\u003e\n \u003c/div\u003e\n \u003c/div\u003e\n );\n}\n```\n\n**ìì ì¸ê¸íëë¡ ë¼ì°í¸ ë¨ìë¡ SSR ëìì ì¡°ì í ìë ìë¤.** ( **Selective SSR** )\n\n기본ì `ssr: true`ì§ë§, ë¼ì°í¸ì `ssr: false`(ìì CSR) ëë `ssr: 'data-only'`(ë°ì´í°ë ìë²ìì ì¤ë¹, UIë í´ë¼ì´ì¸í¸ìì ë ë)ì²ë¼ 모ë를 ì¤ ì ìë¤.\n\n### ì¤í¸ë¦¬ë° SSR\n\nì¤í¸ë¦¬ë° SSR(Streaming Server-Side Rendering)ì **\"모ë ë°ì´í°ê° ì¤ë¹ë ë¤ì í ë²ì HTMLì ë´ë ¤ì£¼ë ë°©ì\"** ëì , **먼ì 그릴 ì ìë UI를 ì¦ì ë´ë ¤ì£¼ê³ ** **ëë¨¸ì§ UIë ì¤ë¹ëë ììëë¡ ì±ì ë£ë** ë ëë§ ì ëµì´ë¤.\n\ní¹í ìëì ê°ì íë©´ìì í¨ê³¼ê° í¬ë¤.\n\n- **ë ì´ìì/ìë¨ íµì¬ ì½í
ì¸ /ë´ë¹ê²ì´ì
**ì²ë¼ ì´ê¸° ê°ìì±ì´ ì¤ìí ììì ë¹ ë¥´ê² ë
¸ì¶íë ê²½ì°\n- **ëê¸/ì¶ì²/íµê³Â·ì§ê³/ì¸ë¶ ì°ë ë°ì´í°**ì²ë¼ ì§ì°ë ì ìë ë°ì´í°ë ì¤ë¹ëë ì¦ì í´ë¹ ììë§ ì´ì´ì ë ëë§íë ê²½ì°\n\nì´ ë°©ìì ì¬ì©ì ì
ì¥ììë **ë¹ íë©´ ë기 ìê°**ì ì¤ì¬ì£¼ê³ , ê°ë°ì ì
ì¥ììë **UI를 Suspense boundary ë¨ìë¡ ìëì ì¼ë¡ 쪼ê°ì,** ë린 ììë§ ë
립ì ì¼ë¡ ì²ë¦¬í ì ìê² í´ì¤ë¤.\n\nloaderììë **ì¦ì íìí ë°ì´í°ë `await` í´ì 먼ì íì **íê³ , ì¤ë ê±¸ë ¤ë ëë ë°ì´í°ë **Promise를 ê·¸ëë¡ ë°ííë deferred í¨í´**ì¼ë¡ 미ë¤ë ì ìë¤.\n\nTanStack Startë ì´ê±¸ **[TanStack Routerì Deferred Data Loading](https://tanstack.com/router/v1/docs/framework/react/guide/deferred-data-loading) + `\u003cAwait /\u003e`** ì¡°í©ì¼ë¡ ìì½ê² 구íí ì ìë¤.\nê·¸ë¦¬ê³ ì´ í¨í´ì **ìë²ììë§**ì´ ìëë¼, ì´í **í´ë¼ì´ì¸í¸ ë´ë¹ê²ì´ì
ììë ëì¼íê² ëì**íë¤ë ê² í¬ì¸í¸ë¤.\n\n```tsx title=\"src/routes/home.tsx\"\nimport { Await, createFileRoute } from '@tanstack/react-router';\nimport { createServerFn } from '@tanstack/react-start';\nimport * as React from 'react';\n\n// ë¹ ë¥¸ ë°ì´í°\nconst getHero = createServerFn().handler(async () =\u003e {\n return { title: 'Hello Start', subtitle: 'TTFBë ë¹ ë¥´ê², ìì±ëë ì ì§ì ì¼ë¡' };\n});\n\n// ë린 ë°ì´í° (ë°ëª¨ì©)\nconst getFeed = createServerFn().handler(async () =\u003e {\n await new Promise((r) =\u003e setTimeout(r, 1_500));\n return Array.from({ length: 5 }).map((_, i) =\u003e ({\n id: i + 1,\n text: `feed item #${i + 1}`,\n }));\n});\n\nexport const Route = createFileRoute('/home')({\n ssr: true, // 기본ê°ì´ê¸´ íë° ëª
ìí´ë OK\n loader: async () =\u003e {\n return {\n hero: await getHero(),\n feed: getFeed(), // await íì§ ìì (deferred)\n };\n },\n component: HomePage,\n});\n\nfunction HomePage() {\n const data = Route.useLoaderData();\n\n return (\n \u003cmain style={{ padding: 24 }}\u003e\n \u003ch1\u003e{data.hero.title}\u003c/h1\u003e\n \u003cp\u003e{data.hero.subtitle}\u003c/p\u003e\n\n \u003csection style={{ marginTop: 24 }}\u003e\n \u003ch2\u003eFeed\u003c/h2\u003e\n\n \u003cAwait\n promise={data.feed}\n fallback={\u003cdiv style={{ opacity: 0.6 }}\u003eí¼ë ë¶ë¬ì¤ë ì¤...\u003c/div\u003e}\n children={(items) =\u003e (\n \u003cul\u003e\n {items.map((it) =\u003e (\n \u003cli key={it.id}\u003e{it.text}\u003c/li\u003e\n ))}\n \u003c/ul\u003e\n )}\n /\u003e\n \u003c/section\u003e\n \u003c/main\u003e\n );\n}\n```\n\në´ë¶ì ì¼ë¡ **TanStack Startì ì¤í¸ë¦¬ë° SSRì Web Streams ê¸°ë° ë ëë§ì ì°ì **íë¤.\n\n`react-dom/server`ìì `renderToReadableStream`ì ì¸ ì ìë íê²½ì´ë©´ ì´ ë©ìë를 í¸ì¶íê³ , íê²½ì´ ì ë§ì¼ë©´ Nodeì© `renderToPipeableStream`ì¼ë¡ í´ë°±íë ìì´ë¤.\nëë¶ì **Nodeë¿ ìëë¼ Bun/Deno/Edge ê°ì ë°íìììë \"ì¤í¸ë¦¼ì¼ë¡ ìëµì íë ¤ë³´ë´ë\" í° êµ¬ì¡°ë ëì¼**íê² ê°ì ¸ê° ì ìë¤. ( [ë´ë¶ 구í ì½ë](https://github.com/TanStack/router/blob/main/packages/react-router/src/ssr/renderRouterToStream.tsx) )\n\nê²°ë¡ ì ì¼ë¡ Next.jsì ì¤í¸ë¦¬ë° SSRê³¼ ê°ì ê²°ì´ë¤. 먼ì **shellìì TTFB/ì´ê¸° ê°ìì±ì íë³´**íê³ , ë린 ì¹ì
ì ë°ì´í°ê° ì¤ë¹ëë ëë¡ **ì¤í¸ë¦¼ìì ìì°¨ì ì¼ë¡ í©ë¥**íë©´ì íë©´ì´ ì ì ìì±ëë¤.\n\nì´ êµ¬íì ìì½ê² ì²ë¦¬í´ 주ë **`Deferred Data Loading`** + **`\u003cAwait /\u003e`** API를 íµí´, React 18ì´ ì ê³µíë ì¤í¸ë¦¬ë° SSR +
16Suspense를 ì ë
¹ì¬ ë¸ê²ì¼ë¡ ë³´ì¸ë¤.\n\nê°ì¸ì ì¼ë¡ TanStackë§ì ì¢ì DXê° ì´ ì§ì ìì ëì¨ë¤ê³ ëê¼ë¤.\nì¤í¸ë¦¬ë° SSR ìì²´ë React 18ì´ ì ê³µíë 기본 기ë¥ì´ê³ Next.jsë ê°ì ê²°ë¡ íì´ê°ì§ë§, TanStackì 그걸 ë¼ì°í°, ë¡ë ë ì´ì´ìì íëì \"í¨í´\"ì¼ë¡ ì 리í´ë ëëì´ë¤.\n\n### Selective SSR\n\n기본ì ì¼ë¡ TanStack Startë **모ë ë¼ì°í¸ê° SSR íì±í**ë¡ ì¤ì ëì´ ìë¤.\n\në¤ë§ ë¼ì°í¸ ë¨ìë¡ `ssr` ìµì
ì ì¤ ì ìì´ì, íë©´ ì±ê²©ì ë§ê² ë ëë§ ì ëµì ë°ê¿ ì ìë¤.\n\n| ìµì
| ì»´í¬ëí¸(ìë²) | ì»´í¬ëí¸(í´ë¼) | loader(ìë²) | loader(í´ë¼) | beforeLoad(ìë²) | beforeLoad(í´ë¼) |\n| ------------------ | -------------- | -------------- | ------------ | ------------ | ---------------- | ---------------- |\n| `ssr: true` (기본) | â
| â
| â
| â
| â
| â
|\n| `ssr: \"data-only\"` | â | â
| â
| â
| â
| â
|\n| `ssr: false` | â | â
| â | â
| â | â
|\n\n- **`true` (기본)** : SSR. ì¤í¸ë¦¬ë°ì´ 걸리면 shellì´ ë¨¼ì ëì¤ê³ ë머ì§ê° í©ë¥íë¤.\n- **`\"data-only\"`** : ë°ì´í°ë§ ìë²ìì 미리 ê°ì ¸ì¤ê³ ë ëë§ì í´ë¼ì´ì¸í¸ììë§ ì§ííë¤.\n- **`false`** : ìì CSR. HTMLì ë¹ì´ ìê³ í´ë¼ì´ì¸í¸ìì ì ë¶ ììíë¤.\n\nì§ë/3D/ìºë²ì¤ì²ë¼ ë¸ë¼ì°ì ììë§ ë ëë§ëë íë©´ì 구ì±íë¤ë©´ SSRì ì´ì ì´ ì íì ì´ë¯ë¡ ìì½ê² ë¹íì±í ì²ë¦¬ë¥¼ í ì ìê³ , SEO/TTFBê° ì¤ìí íë©´ì SSRë¡ ì ê³µíì¬ ë¼ì°í¸ë³ë¡ ë¤ìí ì ëµì ìì½ê² 구íí ì ìë¤ë ê²ì´ ë§¤ë ¥ì ì´ë¤.\n\n### ìë² í¨ì(Server Functions)\n\nTanStack Startì ìë² í¨ìë **\"í´ë¼ì´ì¸í¸ìì ìë² ë¡ì§ì í¨ìì²ë¼ í¸ì¶\"í ì ìê² ë§ëë RPC ë ì´ì´**ë¤.\n\n**ì¬ì© ê²½í(í¸ì¶ ë°©ì)ì í¨ì í¸ì¶ì²ë¼ ì ì§**íë©´ì, **ì¤ì ë¡ë ë¤í¸ìí¬ ê²½ê³ë¥¼ ìì íê² ëë í¸ì¶ë¡ ì»´íì¼**ëë ííì´ë¤.\n\n**ì í리ì¼ì´ì
ì´ëììë ìë² ë¡ì§ì í¨ì ííë¡ í¸ì¶**í ì ìê³ , í´ë¼ì´ì¸í¸ìì ìë² í¨ì를 í¸ì¶íë ê²½ì°ìë í¸ì¶ì´ ìë²ë¡ì fetch ìì²ì¼ë¡ ë°ëë¤.\në°ë¼ì, **í´ë¼ì´ì¸í¸ ì»´í¬ëí¸ë¥¼ ë¤ë£¨ë ì½ëìì ìë² í¨ì를 importí´ë ìì **íê³ , ë¹ë ê³¼ì ì¤ í´ë¼ì´ì¸í¸ ë²ë¤ìì ìë² ë¡ì§ì´ RPC stubì¼ë¡ êµì²´ë기 ë문ì ì¤ì ìë² ì½ëë ë¸ë¼ì°ì ë¡ ì ë¬ëì§ ìëë¤.\n\n#### 기본 ìì\n\nìë² í¨ìë ë³´íµ ìë ì²´ì¸ì¼ë¡ 구ì±íë¤.\n\n`createServerFn({ method })` : ì´ í¨ìê° ì´ë¤ HTTP ë©ìë ì±ê²©ì¸ì§(ì¡°í/ë³ê²½)를 ëª
ì\u003cbr /\u003e\n\u0026nbsp;\u0026nbsp; `.inputValidator(...)`: ë¤í¸ìí¬ ê²½ê³ë¥¼ ëë ì
ë ¥ì ê²ì¦/ì ê·í\u003cbr/\u003e\n\u0026nbsp;\u0026nbsp;`.handler(...)` : ìë²ììë§ ì¤íë ì¤ì ë¡ì§\n\nì´ êµ¬ì¡° ëë¶ì **ì
ë ¥ íì
â ê²ì¦ â ì¤í ë¡ì§**ì´ í ê³³ì 모ì´ê³ , í¸ì¶ìë ëì¼í ì¸í°íì´ì¤ë¡ë§ ì¬ì©íê² ëë¤.\n\n```tsx\nimport { createServerFn } from '@tanstack/react-start';\nimport { z } from 'zod';\n\nconst UserSchema = z.object({\n name: z.string().min(1),\n age: z.number().min(0),\n});\n\nexport const getUser = createServerFn({ method: 'GET' })\n .inputValidator(UserSchema)\n .handler(async ({ data }) =\u003e {\n return findUserById(data.id);\n });\n```\n\nëí, ìë² í¨ìë **ë¨ì¼ data íë¼ë¯¸í°ë¥¼ ë°ì¼ë©°**, ë¤í¸ìí¬ ê²½ê³ì´ê¸° ë문ì** validationì´ íì
ìì ì±ê³¼ ë°íì ì íì±ì ë³´ì¥**íë©°\n\në¼ì°í°ì **`loader` ê°ì ìë² ìëª
ì£¼ê¸°ë¿ ìëë¼, ì»´í¬ëí¸ììë `useServerFn()` ííë¡ í¸ì¶**í ì ìë¤.\n\n```tsx\n// In a route loader\nexport const Route = createFileRoute('/posts')({\n loader: () =\u003e getServerPosts(),\n});\n\n// In a component\nfunction PostList() {\n const getPosts = useServerFn(getServerPosts);\n\n const { data } = useQuery({\n queryKey: ['posts'],\n queryFn: () =\u003e getPosts(),\n });\n}\n```\n\n#### ìë¬ ì²ë¦¬\n\nìë² í¨ìë ì±ê³µ ê°ë¿ ìëë¼ ìë¬/리ë¤ì´ë í¸/notFound ê°ì ì ì´ íë¦ë ì§ìíë¤.\u003cbr/\u003e\nê·¸ë¦¬ê³ ì´ë° ê²°ê³¼ë `useServerFn()`ì´ë ë¼ì°í¸ ìëª
주기ìì \"ìì°ì¤ë½ê²\" ì²ë¦¬ëëë¡ ì¤ê³ëì´ ìë¤.\n\n```tsx title=\"ì¼ë°Â ìë¬ë í´ë¼ì´ì¸í¸ë¡Â serializeëì´Â ì ë¬\"\nimport { createServerFn } from '@tanstack/react-start';
16\n\nexport const riskyFunction = createServerFn().handler(async () =\u003e {\n if (Math.random() \u003e 0.5) {\n throw new Error('Something went wrong!');\n }\n return { success: true };\n});\n\n// Errors are serialized to the client\ntry {\n await riskyFunction();\n} catch (error) {\n console.log(error.message); // \"Something went wrong!\"\n}\n```\n\n```tsx title=\"ì¸ì¦Â íì ì redirect()를 throw\"\nimport { createServerFn } from '@tanstack/react-start';\nimport { redirect } from '@tanstack/react-router';\n\nexport const requireAuth = createServerFn().handler(async () =\u003e {\n const user = await getCurrentUser();\n\n if (!user) {\n throw redirect({ to: '/login' });\n }\n\n return user;\n});\n```\n\n```tsx title=\"리ìì¤ê°Â ìì¼ë©´Â notFound()를 throw\"\nimport { createServerFn } from '@tanstack/react-start';\nimport { notFound } from '@tanstack/react-router';\n\nexport const getPost = createServerFn()\n .inputValidator((data: { id: string }) =\u003e data)\n .handler(async ({ data }) =\u003e {\n const post = await db.findPost(data.id);\n\n if (!post) {\n throw notFound();\n }\n\n return post;\n });\n```\n\nì´ë¬í 구조ë \"API ìëµì status codeë¡ ë¶ê¸°íê³ , íë¡ í¸ìì ë¤ì í´ìíë\" í¨í´ë³´ë¤ ë¼ì°í
/ë ëë§ ìëª
주기ì ë ì§ì ì ì¼ë¡ ê²°í©ëë¤.\n\n#### ë¤ìí 기ë¥ê³¼ ííë¡ ì¬ì©\n\nìë² í¨ìë \"ê·¸ë¥ RPC\"를 ëì´ì, ìì²/ìëµ ì»¨í
ì¤í¸ë¥¼ ë¤ë£° ìë ìë¤.\u003cbr/\u003e\nìë ììì²ë¼ `getRequest()`, `getRequestHeader()`ë¡ ìì²ì ì½ê³ , `setResponseHeaders()`, `setResponseStatus()`ë¡ ìëµì ì¡°ì í ì ìë¤.\n\n```tsx\nimport { createServerFn } from '@tanstack/react-start';\nimport { getRequest, getRequestHeader } from '@tanstack/react-start/server';\nimport { setResponseHeaders, setResponseStatus } from '@tanstack/react-start/server';\n\nexport const getCachedData = createServerFn({ method: 'GET' }).handler(async () =\u003e {\n // Access the incoming request\n const request = getRequest();\n const authHeader = getRequestHeader('Authorization');\n\n // Set response headers (e.g., for caching)\n setResponseHeaders(\n new Headers({\n 'Cache-Control': 'public, max-age=300',\n 'CDN-Cache-Control': 'max-age=3600, stale-while-revalidate=600',\n }),\n );\n\n // Optionally set status code\n setResponseStatus(200);\n\n return fetchData();\n});\n```\n\në, **ìë² í¨ì 미ë¤ì¨ì´**ì í¨ê» ì¬ì©íë¤ë©´ ì
ë ¥ ë°ì´í°ë¥¼ ê²ì¦íê±°ë ìë² í¨ì ì¤í ì íì í´ë¼ì´ì¸í¸ 측 ë¡ì§ì ìííë ë±ì ì²ë¦¬ë¥¼ í ì ìë¤.\n\n- ì¸ì¦/ì¸ê°: \"ìë² í¨ì ì¤í ì ì\" ê°ì í기\n- ë¡ê¹
/í¸ë ì´ì±: \"RPC í¸ì¶ ë¨ìë¡\" ì¼ê´ë ê´ì¸¡ì± ë¶ì¬í기\n- ê³µíµ ì»¨í
ì¤í¸ 주ì
: request ë¨ì ë°ì´í°(ì: workspaceId) ì íí기\n\n```tsx\nimport { createMiddleware, createServerFn } from '@tanstack/react-start';\n\nconst loggingMiddleware = createMiddleware({ type: 'function' })\n .client(() =\u003e {\n // ìë² í¨ì í¸ì¶ ì íì í´ë¼ì´ì¸í¸ 측ìì ì¤íí ë¡ì§\n })\n .server(() =\u003e {\n // ìë² í¨ìê° ì¤íë기 ì , ì¤íë íì ìë²ìì ì¤íí ìë² ì¸¡ ë¡ì§\n });\n\nconst fn = createServerFn()\n .middleware([loggingMiddleware])\n .handler(async () =\u003e {\n //...\n });\n```\n\nì´ì¸ìë **ë¹ë기 ì ëë ì´í°ì í¨ê» ì¤í¸ë¦¬ë° ë°ì´í°**를 ì ë¬í ì ìê³ , **ë¹ë íìì ì ì ì¼ë¡ ìë² í¨ì를 구ì±íì¬ ê²°ê³¼ë¥¼ ìºì±**í ìë ìì¼ë©°, ìë² í¨ìì `.url` ìì±ì íì©í´ JSìì´ HTML formì¼ë¡ë í¸ì¶í ì ìë¤ê³ íë¤.\n\nìë² í¨ìë TanStack Startì íµì¬ ê¸°ë¥ ì¤ íëë¡, íì
ìì ì±, ì¤í ê²½ê³(í´ë¼ì´ì¸í¸/ìë²) ë¶ë¦¬, ê·¸ë¦¬ê³ í¸ì¶ ì¼ê´ì±ì íëì ì¶ìíë¡ ë¬¶ëë¤. ì´ë¬í ì ê·¼ì ë³ëì API ë ì´ì´ ìì´ ìë² ë¡ì§ì 구ì±í ì ìê² íë©°, í´ë¼ì´ì¸í¸ì ìë² ì¬ì´ì ê²½ê³ë¥¼ ë³´ë¤ ëª
ííê³ ì¼ê´ë ë°©ìì¼ë¡ ë¤ë£° ì ìê² ë§ë ë¤.\n\n## ë§ì¹ë©°\n\nTanStack Start를 ì´í´ë³´ë©´ì ëë ì ì, ì´ íë ììí¬ê° ë¨ìí ìë¡ì´ 기ë¥ì ì¶ê°í ê²ì´ ìëë¼ **기존 íì¤í ê°ë° ë°©ì ì체를 ë¤ë¥¸ ìì ì¼ë¡ ë°ë¼ë³´ê² ë§ë ë¤**ë ì ì´ìë¤.\n\ní¹í **ë¼ì°í° ì¤ì¬ 구조 ìì SSR, ì¤í¸ë¦¬ë°, ìë² í¨ìê° ìì°ì¤ë½ê² ì¹íë ë°©ì**ì 기존ì API ë ì´ì´ë¥¼ ë³ëë¡ ì¤ê³íë íë¦ê³¼ë ë¤ë¥¸ ë°©í¥ì±ì ë³´ì¬ì¤ë¤.\n\nTanStack Router를 ì¬ì©í´ 본 ê²½íì´ ìë¤ë©´ **ë¹êµì ë¹ ë¥´ê² ì ìí ì ìì ê² ê°ë¤ë ì¸ì**ë ë°ìê³ , ê°ì¸ì ì¼ë¡ë Next.js를 ì¬ì©í´ ì¨ ê²½íê³¼ ë¹êµíì ë **ë°ì´í° íë¦ê³¼ ìë² ë¡ì§ì´ ë ì¼ê´ëê³ ë¨ì**íê² ëê»´ì§ë ì§ì ë ììë¤.\n\në¬¼ë¡ ìì§ì RC ë¨ê³ì¸ ë§í¼ ì¤ì ìë¹ì¤ ì ì©ìë ê³ ë ¤í ììë¤ì´ ë¨ììì§ë§, ì´ë¬í ì ê·¼ì´ **ìì¼ë¡ ì´ë¤ ííë¡ ì리 ì¡ìì§ë ì¶©ë¶í ì§ì¼ë³¼ ë§í ê°ì¹ê° ìì´ ë³´ì¸ë¤.**\n\n---\n\n## ì°¸ê³ \n\n- [TanStack Start 문ì
16](https://tanstack.com/start/latest)\n- [TanStack Startê° Nitro를 ì¬ì©í ì´ì ](https://tanstack.com/blog/why-tanstack-start-is-ditching-adapters#tanstack-start--nitro--vite--tanstack-router)\n- [TanStack Router ìì¤ ë° SSR](https://github.com/TanStack/router)\n- [React DOM Server â renderToReadableStream / renderToPipeableStream](https://react.dev/reference/react-dom/server/renderToReadableStream)\n- [Sentry à TanStack Start ê°ì´ë](https://docs.sentry.io/platforms/javascript/guides/tanstackstart-react/)\n- [Tanner Linsley ì¸í°ë·° â Next Gen Fullstack React with TanStack (YouTube)](https://www.youtube.com/watch?v=XXXXX)\n","data":{"id":"about-tanstack-start","title":"TanStack Start ìì보기","description":"TanStackì ì ê· í ì¤í íë ììí¬ì¸ TanStack Startì ëí´ ììë´
ëë¤.","preview":"TanStackì ì ê· í ì¤í íë ììí¬ì¸ TanStack Startì ëí´ ììë´
ëë¤.","keywords":"tanstack, tanstack start, full stack framework, react, next.js, ssr, streaming ssr, server functions, nitro, vite, selective ssr, node, bun, deno","createdAt":"2025.10.1","published":true},"filePath":"about-tanstack-start.mdx"},{"content":"\níì¬ ì´ì ì¤ì¸ ìë¹ì¤ìì ëì
í **`ts-pattern`** ì´ë¼ë ë¼ì´ë¸ë¬ë¦¬ë¥¼ íµí´ ì¬ë¬ 문ì ë¤ì í´ê²°íë ë´ì©ë¤ì ëí´ ìì±í´ ë³¼ ìì ì´ë¤.\n\ní¨í´ 매ì¹ì ìë°ì¤í¬ë¦½í¸ë [ì ì ë¨ê³](https://github.com/tc39/proposal-pattern-matching)ì´ê¸° ë문ì ìê³ ìë ì¬ëë¤ë ìê² ì§ë§, ì¼ë°ì ì¸ ê²½ì°ì ìë°ì¤í¬ë¦½í¸ë¡ë§ ê°ë°ì í´ìë ê°ë°ìë¼ë©´ í¨í´ 매ì¹ì´ë¼ë ê°ë
ìì²´ë ììí ì ìë¤.\n\në°ë¼ì, ê¸ì 주ì ì¸ **`ts-pattern`** ì íì©íì¬ í´ê²°íë ê²ì ì´ì¼ê¸°í기 ì ì, í¨í´ 매ì¹ì´ë¼ë ê²ë¶í° ì¹ìí´ì§ ì ìë ìê°ì ê°ì ¸ë³´ì.\n\n## í¨í´ 매ì¹?\n\n**í¨í´ 매ì¹(pattern matching)**ì **ë°ì´í°ë¥¼ ê²ìí ë í¹ì í¨í´ì´ ì¶ííëì§, ëí ì´ëì ì¶ííëì§ ë±ì í¹ì íë ë°©ë²ì ì¼ì¢
**ì´ë¤.\n\ní¨í´ 매ì¹ì ê²ì, ë¶ì, ì ê·í, ì¶ì¶ ë± ë¤ìí ìì© ë¶ì¼ìì ì¬ì©íê³ ìì¼ë©°, ìë°ì¤í¬ë¦½í¸ììë ì ê·ííìì íì©íì¬ ë¬¸ìì´ìì í¹ì í¨í´ì ì°¾ì ê²ì, ì¶ì¶, ëì²´ ë±ì ìíí ë ì¬ì©ëë ê°ë
ì´ë¤.\n\níì¬ ë§ì í¨ìí ì¸ì´(Rust, Swift, Elixir, Haskell, Erlang, F#, Scala ë±)ìì ì§ì ì ì¸ í¨í´ 매ì¹ì´ ì§ìëë©°, Pythonë 3.10 ë²ì ìì [구조ì í¨í´ 매ì¹(Structural Pattern Matching)](https://peps.python.org/pep-0634/)ì´ë¼ë ì´ë¦ì¼ë¡ ëì
ëìë¤.\n\nì§ì í¨í´ ë§¤ì¹ ê¸°ë¥ì íì©íë©´ ë°ì´í°ì **ê°, ìë£êµ¬ì¡°, íì
ë± ì¬ë¬ê°ì§ ì íì í¨í´ì¼ë¡ ê²ì**ì ìíí ì ìê³ , í¹ì ë°ì´í° 구조ìì **ìíë ê°ì ì¶ì¶**í ìë ìë¤. ì´ë ì ì ìì ì½ëë¡ ë§ì ìì ë°ì´í°ë¥¼ ì½ê³ ë¤ë£¨ê¸°ì ì주 ì¢ì íí ë°©ë²ì´ë©°, ì´ë¡ ì¸í´ ì½ëì ê°ë
ì±ê³¼ ì ì§ë³´ìì±ë í¥ììí¬ ì ìë¤.\n\n### ìë°ì¤í¬ë¦½í¸ììì ì¬ì©\n\nìì§ê¹ì§ ìë°ì¤í¬ë¦½í¸ììë ì¬ì©í ì ìë¤.\n\nìì ë§í ë¯ì´ ECMA íì¤ì´ ë기 ìí **[ì ì ë¨ê³(TC39 process, Stage 1)](https://tc39.es/proposal-pattern-matching/)ì¼ë¿ì´ë¤.** ìëì ê°ì 문ì ë¤ì ê°ì§ê³ ì ìì´ ììëìì¼ë ê°ë¨í ë§¥ë½ ì ëë§ ì§ê³ ëì´ê° ë³´ì.\n\n- ìë°ì¤í¬ë¦½í¸ì **ê°ì ì¼ì¹ìí¤ë ë°©ë²ì ë§ì§ë§**, 문ìì´ì ìí **ì ê·ííì ì¸ì í¨í´ì ì¼ì¹ìí¤ë ë°©ë²ì ìë¤.**\n- `switch`ìë ë§ì ì ì½ì´ ìë¤.\n - ì ì¼í ë¹êµë ì¼ì¹ ì°ì°ì(`===`)ë§ì´ ì¬ì© ê°ë¥\n - ì°ë°ì ì¸ ì¤í¨ë¥¼ ë°©ì§í기 ìí´ì ê° `case`ë³ë¡ `break` ë¬¸ì´ íì\n - `case` ì ì 매í scope ( ì¤ê´í¸ë¡ ê°ì¸ì§ ìëë¤ë©´ ë¸ë¡ ë²ì ë³ìë ë¤ë¥¸ `case` ììë ì ê·¼ ê°ë¥ )\n - 기í ë±ë±\n\nì¤ëì ìë°ì¤í¬ë¦½í¸ ìíê³ì ë¬ë¦¬ ë¤ë£° ì ìë ê²ë¤ ê²ë¤ì´ ëê³ ë ê¹ì´ì§ë©´ì í¬ê³ ë¤ìí ê°ë¤ì ì²ë¦¬í기 ìí ë°©ë²ì´ íìí´ì§ ê²ì¼ë¡ ë§¥ë½ì í´ìí ìë ìì ê² ê°ë¤.\n\n매ë
ì°ë§ì ì¤ìíë **[State of JavaScript](https://stateofjs.com/en-US)**ììë í¨í´ ë§¤ì¹ ê¸°ë¥ì ëí ëì¦ë¥¼ ë³´ì¬ì£¼ê³ ìë¤.\n\n\n\nìë°ì¤í¬ë¦½í¸ ìíê³ë ìëì
16§ë§ [íì´ì¬ì í¨í´ ë§¤ì¹ ëì
ì ì½í ì´ì¼ê¸°](https://ryanking13.github.io/2021/03/04/python-patma.html)ë ê°ì´ ì½ì´ë³´ë©´ ì¬ë¯¸ìì ê² ê°ë¤.\n\n**ê²°êµ íìì ìì ìë°ì¤í¬ë¦½í¸ìì ì¬ì©ì ë³ë ë¼ì´ë¸ë¬ë¦¬ì ëìì ë°ì ìë°ì ìë ìí©ì´ê³ ,** ì´ë¥¼ ëì주ë **`ts-pattern`** ê³¼ ëª ê°ì§ ì¬ë¡ë¥¼ ìê°íê² ë¤.\n\n## ts-pattern\n\n[TC39ë¡ì ì ì ê¹íë¸](https://github.com/tc39/proposal-pattern-matching?tab=readme-ov-file#userland-matching)ìë ìê°ë **`ts-pattern`**ì íì
ì¤í¬ë¦½í¸ íê²½ìì í¨í´ 매ì¹ì ì½ê² ííí ì ìê² í´ì£¼ë ë¼ì´ë¸ë¬ë¦¬ì´ë¤.\n\në ìì íê³ ëì ì¡°ê±´ì ìì±í ì ìê³ , ë³µì¡í¨ì ê°ê²°íê² ííí ì ìì¼ë©° ê·¸ì ë°ë¼ ì½ë ê°ë
ì±ë ì¢ìì§ê³ ì² ì í íì
ì²´í¬ë¥¼ íµí´ ì¼ì´ì¤ ëë½ë ë°©ì§í ì ìë¤.\n\nì§ë 2ë
ê°ì npm trendsë§ ë³´ëë¼ë ë¼ì´ë¸ë¬ë¦¬ì 꾸ì¤í ì¸ê¸°ì ìì²ë 기ì¸ë¥¼ íì¸í ì ìë¤.\n\n\n\n**`ts-pattern`**ì 주ì 기ë¥ê³¼ APIë¤ì ê°ë¨í ëë¬ë³´ê³ ì´ê²ë¤ì ë°íì¼ë¡ ì´ë¤ 문ì ë¤ì í´ê²°íëì§ íì¸í´ ë³´ì.\n\n### 주ì 기ë¥\n\n- ì¤ì²©ë ê°ì²´, ë°°ì´, íí, ì
, ë§µ ë° ëª¨ë 기본 ì í ë± **모ë ë°ì´í° 구조ì ëí´ í¨í´ ë§¤ì¹ ê°ë¥**\n- **íì
ì¶ë¡ ì íµí íì
ìì ì± íë³´**\n- ì² ì í íì
ì²´í¬ë¥¼ íµí´ **ê°ë¥í 모ë ê²½ì°ë¥¼ `.exhaustive()`ì ì¼ì¹íëë¡ ê°ì **\n- í¨í´ì ì¬ì©íì¬ **`isMatching`**ì¼ë¡ ë°ì´í° íí를 ê²ì¦ ê°ë¥\n- **catch-all**, **type-specific wildcards**를 ì ê³µíì¬ **ííë ¥ ì¢ì API**\n - catch-all: `P._`\n - type-specific wildcards: `P.string`, `P.number`, `P.array`, etc..\n- ë³µì¡í ê²½ì°ë¥¼ ìí´ **ì측, ê²°í©, êµì°¨ ë° ì ì¸ í¨í´ì ì§ì**\n- `P.select(name?)` í¨ì를 íµí´ **ìì± ì íì ì§ì**\n- ~2kB ë°ì ëì§ ìì **ìì ë²ë¤ í¬ê¸°**\n\n### 주ì API\n\nììì ëì´íë 기ë¥ë¤ ëë¹íì¬, **`ts-pattern`**ì ì¬ì©í기 ìí´ ì¬ì ì ììëì´ì¼ í APIê° ë§ì§ë ìë¤.\n\në¤ë¥¸ ì¸ì´ìì í¨í´ 매ì¹ì ì¬ì©íë 문ë²ë¤ì´ ìµìíë¤ë©´ ì주 ì½ê² ì ê·¼í ì ìì ê²ì´ë¤. ê·¸ë ì§ ìëë¼ë ì´ë ¤ì´ ê²ì ìì¼ë í¬ê² ê±±ì í ê²ì ìë¤. ì²ì²í ìì ì½ëë¤ê³¼ APIë¤ì ëí´ íì¸í´ ë³´ì.\n\n기본ì ì¸ ì½ëì ííë ìëì ê°ì 모ìµì´ë¤.\n\n```ts {1,5-9}\nimport { match } from 'ts-pattern';\n\nconst value = [1, 2, 3];\n\nconst result = match(value)\n .with([1, 2, 3, 4], () =\u003e 'it is [1, 2, 3, 4]')\n .with([1, 2, 3], () =\u003e 'it is [1, 2, 3]')\n .with([1, 2], () =\u003e 'it is [1, 2]')\n .run();\n\nconsole.log(result); // it is [1, 2, 3]\n```\n\n#### match(value)\n\n**`ts-pattern`**ì ë´ë¶ì ì¼ë¡ [ë¹ë í¨í´](https://en.wikipedia.org/wiki/Builder_pattern)ì¼ë¡ ëìì¸ë `MatchExpression`ì´ë¼ë í´ëì¤ë¥¼ ì¬ì©íì¬ ë§¤ì¹ì ì²ë¦¬íë¤.\n\n**`match(value)`**ë ì´ í´ëì¤ì ì¸ì¤í´ì¤ë¥¼ ìì±íì¬ ë°íí´ ì£¼ë ì주 ê°ë¨í í¨ìì´ë¤. ë°ë¼ì, ì´ í¨ìì ì¤íì íì ì íëì´ì¼ íë¤.\n\n#### .with(pattern, [...patterns], handler)\n\n**ì
ë ¥ ê°ì í¨í´ë³ë¡ 매ì¹ì ìì¼ì£¼ë ë©ìë**ì´ë¤.\n\n**í¨í´ ì¸ìì íì
ì ì¼ë°ì ì¼ë¡ ì
ë ¥ ê°ì íì
ì ìí´ ê²°ì ëë¤.** (ë¬¼ë¡ , ìëì²ë¼ ì
ë ¥ì íì
ì¶ë¡ ì´ íë ê²½ì°ë ìë¤. )\n\n```ts {1,5-8}\nimport { match, P } from 'ts-pattern';\n\nconst toString = (value: unknown): string =\u003e\n match(value) // -\u003e valueê° unknownì´ê¸° ë문ì ìë with í¨ìì í¨í´ ì¸ìë¡ ì¬ë¬ íì
ì ë£ì ì ìë¤.\n .with(P.string, (str) =\u003e str)\n .with(P.number, (num) =\u003e num.toFixed(2))\n .with(P.boolean, (bool) =\u003e `${bool}`)\n .with({ kimcoder: 'ð' }, (obj) =\u003e JSON.stringify(obj))\n .otherwise(() =\u003e 'Unknown');\n\nconsole.log(toString('aa')); // 'aa'\nconsole.log(toString(123)); // 123.00\nconsole.log(toString({ kimcoder: 'ð' })); // {\"kimcoder\":\"ð\"}\n```\n\níì
ì¤í¬ë¦½í¸ë¥¼ ì¬ì©íë©´ì ë§ì íì
ë¤ì ëí ì ìê° ëì´ ìì´ ì¶ë¡ ì´ ì ëë ìí©ì´ë¼ë©´, ìì ìì
16ë ìì¸ì ì¸ ìí©ì´ë¼ê³ ë³¼ ì ìë¤.\n\në, **`.with`** ë©ìëë ì¤ë²ë¡ë©ë í¨ìë¡, ìëì²ë¼ ì¬ë¬ í¨í´ë¤ì ëì´í ííë¡ í¸ì¶í ìë ìë¤.\n\n```ts {8-11,15-16}\nimport { match } from 'ts-pattern';\n\nconst upperCase: string = 'A';\nconst printUpper = () =\u003e 'it is upper';\nconst printLower = () =\u003e 'it is lower';\n\nconst first = match(upperCase)\n .with('a', printLower)\n .with('b', printLower)\n .with('A', printUpper)\n .with('B', printUpper)\n .otherwise(() =\u003e 'where is it?');\n\nconst second = match(upperCase)\n .with('a,', 'b', printLower)\n .with('A', 'B', printUpper)\n .otherwise(() =\u003e 'where is it?');\n\nconsole.log(first); // 'it is upper'\nconsole.log(second); // 'it is upper'\n```\n\n**`.with`**ê° ì²´ì´ëëë 모ìµì²ë¼ **í¸ì¶ ììê° ììì ìëë¡ í른ë¤ë ì ì ê¼ ê¸°ìµí´ëì´ì¼ íë¤.**\n\nì¤ì²© ê°ì²´ì ê°ì´ ë³µì¡í 구조를 ê°ì§ ê°ì í¨í´ë¤ì ê²ì¬íê³ ì íë¤ë©´ **íì ì¸ë¶ì ì¸ ííì í¨í´ì 먼ì ê²ì¬ë¥¼ í´ì¼ íë¤.** ( ì´ë ë¤ë¥¸ ì¸ì´ììë ë§ì°¬ê°ì§ì´ë¤. )\n\n#### .exhaustive(), .otherwise(), .run()\n\nì í¨ìë¤ì **í¨í´ ë§¤ì¹ ííìì ì¤ííê³ , 결과를 ë°í**íë `MatchExpression`ì ë©ìëì´ë¤.\n\n| ë©ìë | ì¤ëª
|\n| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `exhaustive(): TOutput` | - **ì
ë ¥ ê°ê³¼ ì¼ì¹íë í¨í´ì´ ìì¼ë©´ íì
ì²´í¬ê° ì¤í¨íë¤.**\u003cbr/\u003e(ì² ì í íì
ì²´í¬, Exhaustiveness Type Check)\u003cbr/\u003e- **ì¼ì¹íë í¨í´ì´ ë°íìì ê¼ ìì´ì¼ íë¤.**\u003cbr/\u003e(ê·¸ë ì§ ìì¼ë©´ ì¤ë¥ê° ë°ìíë¤.) |\n| `otherwise(handler: (value: TInput) =\u003e TOutput): TOutput` | - **ì¼ì¹íë í¨í´ì´ ìì ê²½ì°ì ì¤íëë¤.**\u003cbr/\u003e- `switch`ì `default`ë¡ ìê°íë©´ í¸íë¤. |\n| `run(): TOutput` | - **ì¼ì¹íë í¨í´ì´ ë°íìì ê¼ ìì´ì¼ íë¤.**\u003cbr/\u003e(ê·¸ë ì§ ìì¼ë©´ ì¤ë¥ê° ë°ìíë¤.) |\n\n```ts {1}\nmatch('2024 years!').exhaustive();\n\n/*\n ì ì½ëë NonExhaustiveError ëª
목ì¼ë¡ íì
ì²´í¬ê° ì¤í¨íë¤.\n ë§ì½, íì
ë¶ì¼ì¹ ê²½ê³ ë¥¼ 무ìíê³ ì½ë를 ì»´íì¼íê³ ì¤ííë©´, ë°íììì ìëì ê°ì ì
16¤ë¥ê° ë°ìíë¤.\n Error: Pattern matching error: no pattern matches value \"2024 years!\"\n \n ìëì ê°ì´ ìì íë©´ ì ìì ì¼ë¡ íì
ì²´í¬ë¥¼ ìíí ì ìë¤.\n\n match(\"2024 years!\")\n .with(\"2024 years!\", () =\u003e \"okay\")\n .exhaustive();\n*/\n```\n\n```ts {1}\nmatch('2024 years!').run();\n\n/*\n ì ì½ë를 ì»´íì¼íê³ ì¤ííë©´, ë°íììì ìëì ê°ì ì¤ë¥ê° ë°ìíë¤.\n Error: Pattern matching error: no pattern matches value \"2024 years!\"\n*/\n```\n\nì ë©ìëë¤ì 결과를 ë°íí기 ìí´ìë íí ì¨ì¼ íë, ìì ê°ì í¹ì§ë¤ì ì ì¸ì§íê³ ìì´ì¼ íë¤.\n\n#### isMatching(pattern, value?)\n\n**`isMatching`**ë íì
ê°ë í¨ìì´ë¤. 커ë§ì´ ë ë²ì ê³¼ ê·¸ë ì§ ìì ë²ì , 2ê°ì§ ë²ì ì¼ë¡ ì¬ì©í ì ìë¤.\n\n- `isMatching(pattern, value): boolean`: í¨í´ê³¼ ê°ì 매ì¹ê° ì±ê³µíë©´ 결과를 `boolean` ê°ì¼ë¡ ìë ¤ì¤ë¤.\n- `isMatching(pattern): (value) =\u003e boolean` : í¨í´ë§ ë£ê³ í¨ì를 ì¤ííë©´ í´ë¹ í¨í´ì ëí íì
ê°ë í¨ìê° ë°íëë¤.\n\n커ë§ì´ ë ë²ì ì ìëì ê°ì´ ì¢ ë ì미 ìë ì´ë¦ì¼ë¡ íííì¬ ì¬ì©í ìë ìë¤.\n\n```ts {1,3}\nimport { isMatching } from 'ts-pattern';\n\nconst isDiscountProduct = isMatching({\n salePrice: P.number.gt(0),\n discountedSalePrice: P.number.gt(0),\n});\n\nif (isDiscountProduct(res.data)) {\n // do something!\n}\n```\n\n#### Patterns\n\n**`.with`** ë©ìëì **`isMatching`** í¨ìì ì¸ìë¡ ë¤ì´ê°ë í¨í´ë¤ì ëí´ìë ììì¼ íë¤.\n\ní¨í´ì¼ë¡ ì¬ì©í ì ìë ííë ì주 ë§ê³ , ííë ¥ë ì¢ì í¸ì´ë¼ ì½ë를 ìì±íëë°ë ì½ê³ ì½ëë°ë ì´ë ¤ìì´ ìë¤.\n\nìëì ê°ì´ ë§ì í¨í´ë¤ì´ ì¡´ì¬íì§ë§, ì´ ê¸ììë ëª ê°ì§ë§ ë¤ë£° ìì ì´ë¤. ìì¸í ê±´ [ts-pattern 문ì](https://github.com/gvergnaud/ts-pattern/tree/main?tab=readme-ov-file#patterns)ììë íì¸í ì ìë¤.\n\n- **`Literals`**\n- **`Wildcards`**\n- **`Objects`**\n- **`Tuples (arrays)`**\n- **`Sets`**\n- **`Maps`**\n- **`P.array patterns`**\n- **`P.when patterns`**\n- **`P.not patterns`**\n- **`P.select patterns`**\n- **`P.optional patterns`**\n- **`P.instanceOf patterns`**\n- **`P.union patterns`**\n- **`P.intersection patterns`**\n- **`P.string predicates`**\n- **`P.number and P.bigint predicates`**\n\n#### P.select(name?)\n\n**`P.select`**ë ì
ë ¥í ë°ì´í° 구조ìì í¹ì ê°ì ì¶ì¶íê³ , í¸ë¤ë¬ í¨ìì ê°ì 주ì
ìí¬ ì ìë¤.\n\nì´ë ë³µì¡í 구조ìì í¹ì ê°ë§ ì¶ì¶íì¬ ë°ííê³ ì í ë ì ì©íê² ì°ì¼ ì ìë¤.\n\n```ts {4}\nimport { match, P } from 'ts-pattern';\n\nconst message = match(data)\n .with({ order: { showOrderCount: true, orderCount: P.select() } }, (count) =\u003e {\n return match(count)\n .with(P.number.gt(0), () =\u003e `${count}ë²ì´ë 주문íë ê³ ê°ì
ëë¤!`)\n .with(0, () =\u003e '첫 주문 ê³ ê°ì
ëë¤!')\n .with(null, () =\u003e undefined)\n .exhaustive();\n })\n .otherwise(() =\u003e undefined);\n```\n\në, **`P.select`**를 í¸ì¶ ì ì¸ìë¡ ì´ë¦ì ì§ì í ìë ìë¤. ì
ë ¥ë°ì ì´ë¦ì¼ë¡ í¸ë¤ë¬ í¨ììì ê°ì 참조í ì ìë¤.\n\n```ts {17}\ntype Data = {\n product: {\n name: string;\n price: number;\n isSale: boolean;\n relateProducts: Product[];\n };\n ad: {\n url: string;\n bannersImages: string[];\n };\n};\n\nmatch(res)\n .with(\n {\n product: { name: P.select('name'), price: P.select('price') },\n ad: { url: P.select('adUrl') },\n },\n ({ name, price, adUrl }) =\u003e {\n return { name, price: price.toLocaleString(), adUrl };\n },\n )\n .otherwise(() =\u003e '');\n```\n\n#### P.union()\n\n**`P.union(...subpatterns)`**ë ì¸ìë¡ ì£¼ì´ì§ í¨í´ë¤ ì¤ íëë¼ë ì¼ì¹íë©´ 매ì¹ì´ ì±ê³µíë ê²ì¼ë¡ ì²ë¦¬ìí¬ ì ìë í¨í´ì´ë¤.\n\n```ts {10}\nimport { match, P } from 'ts-pattern';\n\ntype Input =\n | { type: 'user'; name: string }\n | { type: 'org'; name: string }\n | { type: 'text'; content: string }\n | { type: 'img'; src: string };\n\nconst output = match(input)\n .with({ type: P.union('user', 'org') }, (userOrOrg) =\u003e {\n // userOrOrg: User | Org\n return userOrOrg.name;\n })\n .otherwise(() =\u003e '');\n```\n\n주ì´ì§ í¨í´ë¤ì´ 모ë ì¼ì¹í´ì¼ì§ë§ 매ì¹ì´ ëë **`P.intersection(...subpatterns)`**ì ê°ì í¨í´ë ìë¤.\n\n#### Wildcards\n\nìë°ì¤í¬ë¦½í¸ì ìì íì
ë¤ì ëí ìì¼ëì¹´ëë¡ë ê²ì¬ë¥¼ ìíí ì ìë¤.\n\nìì¼ëì¹´ëì ì¢
ë¥ë ë¤ìê³¼ ê°ì´ ìê³ , ì¤ëª
ì ì´ë¦ ê·¸ ìì²´ë¡ë ì¶©ë¶íë¤.\n\n**`P._(=P.any)`** **`P.string`** **`P.number`** **`P.bigint`** **`P.boolean`** **`P.symbol`** **`P.nullish`**\n\n```ts title=\"wildcards\" {4-10}\nimport { match, P } from 'ts-pattern';\n\nconst output = match\u003cunknown\u003e(input)\n .with(P.string, () =\u003e 'it is a string!')\n .with(P.number, () =\u003e 'it is a number!')\n .with(P.bigint, () =\u003e 'it is a bigint!')\n .with(P.boolean, () =\u003e 'it is a boolean!')\n .with(P.symbol, () =\u003e 'it is a symbol!')\n .with(P.nullish, () =\u003e 'it is either null or undefined!')\n .with(P._, () =\u003e 'it is any!')\n .run();\n```\n\n#### Predicates\n\nì«ìì 문ì ì íì ê°ë¤ì ëí ê²ì¬ë¥¼ ìí ì, `predicates`ë¤ì ì¬ì©íì¬ ì¢ ë ííë ¥ ì¢ê³ ê°ê²°í ì½ë를 ìì±í ì ìë¤.\n\n```ts {4-7,13-15}\nimport { match, P } from 'ts-pattern';\n\nconst output = match('kimcoder')\n .with(P.string.startsWith('c'), () =\u003e 'ð')\n .with(P.string.regex(/sparkle/), () =\u003e 'â')\n .with(P.string.minLength(100), () =\u003e 'it is so long')\n .with(P.string.includes('coder'), () =\u003e 'coder')\n .otherwise(() =\u003e 'it is default handler');\n\nconsole.log(output); // coder\n\nconst output2 = match(2024)\n .with(P.number.between(1, 10), () =\u003e '1 ~ 10')\n .with(P.number.negative(), () =\u003e 'it is negative number')\n .with(P.number.gte(2024), () =\u003e '2024! ð')\n .otherwise(() =\u003e 'it is default handler');\n\nconsole.log(output2); // 2024! ð\n```\n\n## í´ê²°íë 문ì \n\níì¬ ì´ì ì¤ì¸ [배민ì¬ì¥ëì±](
16https://apps.apple.com/kr/app/%EB%B0%B0%EB%AF%BC%EC%82%AC%EC%9E%A5%EB%8B%98/id1042003297)ì ì¹ë·°ë¥¼ ê°ë°íë©´ì **`ts-pattern`**ì ì ì©íì¬ í´ê²°íë 문ì ë¤ì ê³µì íê³ ì íë¤.\n\n배민ì¬ì¥ëì±ì ì¬ì©ìê° ë°°ë¬ì민족ì ì¬ë¬ ì íì 주문ë¤ì ì ìíê³ ìí를 ë³¼ ì ìë 기ë¥ì ì ê³µíê³ ìë¤.\n주문 ì ì ì²ë¦¬ ë° ì£¼ë¬¸ì ìí를 íë©´ì ë³´ì¬ì£¼ê¸° ìí´ì API를 í¸ì¶íì¬ ë°ì´í°ë¥¼ ë°ìì¤ê³ ìê³ , ì´ APIì ìëµ ê°ì²´ë ì¬ì©ëë ë´ì©ë¤ì ë¹í´ ì주 í¬ê³ , ê¹ì ëì¤ë¥¼ ê°ì§ ìì±ë¤ë ìë¤.\n\nì¬ì¤ ìì ë´ì©ì´ í° ë¬¸ì ë ìëì§ë§, **ê°ì¥ ê¹ë¤ë¡ê³ ì´ë ¤ì´ 문ì ë ì´ íëì ë°ì´í° 구조ìì ë무 ë§ì ë¶ê¸°ê° ì¼ì´ëë¤ë ê²ì´ë¤.** ê·¸ë¦¬ê³ ìì¼ë¡ ìë¹ì¤ê° ê³ ëíë ìë¡ ë ë³µì¡í´ì§ ê°ë¥ì±ì´ í¬ë¤ë ê²ì´ë¤.\n\nìì ë´ì©ì ë¨ìííì¬ ëìì¼ë¡ ê·¸ë ¤ë³´ë©´ ìëì²ë¼ ííí ì ìê² ë¤.\n\n```mermaid\nstateDiagram-v2\n state A \u003c\u003cfork\u003e\u003e\n ì¬ì©ì --\u003e A: 주문 ì§ë©´ì ì ìíì¬ í¸ì¶ë APIë¡ë¶í° ì ë¬ë ë°ì´í°ê° ì íë³ë¡ ì²ë¦¬ëë¤.\n A --\u003e 배민1주문\n A --\u003e 배민배ë¬ì£¼ë¬¸\n A --\u003e 배민í¬ì¥ì£¼ë¬¸\n A --\u003e 배민매ì¥ì£¼ë¬¸\n A --\u003e 배민배ë¬ìì½ì£¼ë¬¸\n A --\u003e 배민í¬ì¥ìì½ì£¼ë¬¸\n A --\u003e 배민매ì¥ìì½ì£¼ë¬¸\n A --\u003e ì¤í ì´ë°°ë¬ì£¼ë¬¸\n A --\u003e ì¤í ì´í½ì
주문\n\n state B \u003c\u003cjoin\u003e\u003e\n 배민1주문 --\u003e B\n 배민배ë¬ì£¼ë¬¸ --\u003e B\n 배민í¬ì¥ì£¼ë¬¸ --\u003e B\n 배민매ì¥ì£¼ë¬¸ --\u003e B\n 배민배ë¬ìì½ì£¼ë¬¸ --\u003e B\n 배민í¬ì¥ìì½ì£¼ë¬¸ --\u003e B\n 배민매ì¥ìì½ì£¼ë¬¸ --\u003e B\n ì¤í ì´ë°°ë¬ì£¼ë¬¸ --\u003e B\n ì¤í ì´í½ì
주문 --\u003e B\n\n B --\u003e ë ëë§: ììì ì²ë¦¬ë ê°ë¤ì´ íë©´ì ì ë¬ëì´ ì íì ë§ê² ë ëë§ëë¤.\n```\n\në¨ìíê² ì£¼ë¬¸ì ì íë§ íìíì§ë§ ë´ë¶ì ì¼ë¡ë ë ëë§ì íì§ ìëë¡ ì²ë¦¬ê° íìí ê³³ì´ ìê³ , 주문ì ìíì ë°ë¼ ë¶ê¸°ê° ë íìíê³ , ë°°ë¬ ì£¼ë¬¸ì ê²½ì° ë°°ë¬ íí© ìí ë
¸ì¶ ë±ì ì²ë¦¬ë íìíë¤.\n\n주문ì ë°°ë¬ íí©ì ë
¸ì¶íë ë¡ì§ì ë¨ìííì¬ í¨í´ ë§¤ì¹ ì¬ì© ì /í를 ê°ë³ê² ë¹êµí´ ë³´ì.\n\n```ts title=\"useOrderRiderStatus.ts\" showLineNumbers\nimport { match, P } from 'ts-pattern';\n\n/*\n ë¼ì´ë ìíì ëí ììì ì ì±
ì 구ì±íì¬ [ë¼ì´ë íí© í
ì¤í¸]를 ì²ë¦¬íë¤.\n\n 1. ì ê·, ì·¨ì 주문 ìíììë íë©´ì ë
¸ì¶íì§ ìëë¤.\n 2. ë°°ë¬ ì£¼ë¬¸ììë§ íë©´ì ë
¸ì¶íë¤.\n 3. ìììì´ ë§ì ë¼ì´ëê° ì¬ë¬ ëª
ì¸ ê²½ì° íí© í
ì¤í¸ì ì¤ëª
문구를 ì¶ê°íë¤.\n 4. ë¼ì´ëì ìíì ë°ë¥¸ 문구를 ë
¸ì¶íë¤.\n 5. ë°°ì°¨ê° ìë£ë ìì½ ì£¼ë¬¸ì¸ ê²½ì°ì íí© í
ì¤í¸ë¥¼ ë¤ë¥´ê² ë
¸ì¶íë¤.\n*/\ntype Order = {\n status: 'ì ê·' | 'ì ìì¤' | 'ì·¨ì' | 'ìë£';\n type: 'ë°°ë¬' | 'í¬ì¥' | '매ì¥';\n reservation: boolean;\n rider: null | {\n riderCompany: string;\n status: 'ë°°ì°¨ ì ' | 'ë°°ì°¨ ìë£' | 'ë°°ì°¨ ì·¨ì' | 'ì¤ë ì¤' | 'ë°°ë¬ ì¤' | 'ë°°ë¬ ìë£';\n riderAssignTime: string;\n riderCount: number;\n };\n}; // ììì ì ì±
ì ë§ê² íìí ë¶ë¶ë§ íì´í\n\nconst getStatusText = (data: Order) =\u003e {\n if (data.status === 'ì ê·' || data.status === 'ì·¨ì') return '';\n if (data.type !== 'ë°°ë¬') return '';\n if (!data.rider) return '';\n\n if (data.rider.status === 'ë°°ì°¨ ì ') return 'ë¼ì´ë 배차를 기ë¤ë¦¬ê³ ìì´ì.';\n if (data.rider.status === 'ë°°ì°¨ ìë£') {\n if (data.reservation) {\n return '주문ì ìì½ ìê°ì íì¸íì
¨ëì? ë°°ì°¨ê° ë°©ê¸ ë§ ëìì´ì.';\n }\n return 'ë¼ì´ë ë°°ì°¨ê° ìë£ëìì´ì.';\n }\n // ì¼ë¶ ë¡ì§ ìëµ\n};\n\nconst getStatusTextWithPatterMatching = (data: Order) =\u003e {\n const getEmpty = () =\u003e '';\n\n return match(data)\n .with({ status: P.union('ì ê·', 'ì·¨ì') }, { type: P.not('ë°°ë¬') }, getEmpty)\n .with({ rider: { status: 'ë°°ì°¨ ì ' } }, () =\u003e 'ë¼ì´ë 배차를 기ë¤ë¦¬ê³ ìì´ì.')\n .with(\n { reservation: true, rider: { status: 'ë°°ì°¨ ìë£' } },\n () =\u003e '주문ì ìì½ ìê°ì íì¸íì
¨ëì? ë°°ì°¨ê° ë°©ê¸ ë§ ëìì´ì.',\n )\n .with({ reservation: false, rider: { status: 'ë°°ì°¨ ìë£' } }, () =\u003e 'ë¼ì´ë ë°°ì°¨ê° ìë£ëìì´ì.')\n .otherwise(getEmpty);\n // ì¼ë¶ ë¡ì§ ìëµ\n};\n```\n\ní¨í´ 매ì¹ì ì¬ì©í ì½ëììë ë§ì ì¡°ê±´ìê³¼ ë¸ëë¤ì´ ì¬ë¼ì¡ë¤. ì°ì°ì ëí ì¬ë¼ì§ 모ìµì´ë¤.\n\n**ë¨ì§ ì구ì¬í 구íì ë¶í©íë í¨í´ë¤ì ëì´íê³ êµ¬í ì²ë¦¬ë¥¼ í´ì£¼ë í¨ìë¤ì ì ì¸í´ëìì ë¿ì´ë¤.**\n\nì¸ë¼ì¸ì¼ë¡ ë£ì ê°ì²´ íìì í¨í´ë¤ì´ ë§ì ê°ë
ì± ì¸¡ë©´ìì ì¡°ê¸ ë¶í¸í ì ìë¤ë©´, ì´ í¨í´ë¤ì ë³ìë¡ ì ì¸íì¬ ì¡°ê¸ ë ì미 ìë ê°ì¼ë¡ íííê³ ì¬ì¬ì©ì±ë ëì¼ ì ìë¤.\n주문 ê´ë ¨ ìììì ë¹ì·í ì구ì¬íë¤ì ì²ë¦¬íë ê³³ì´ ë§ìì `{ status: P.union('ì ê·', 'ì·¨ì') }` í¨í´ì ììë¡ ì ì¸íê³ ê·¸ ìì를 참조íë ê²ì¼ë¡ë ì½ëì ì¬ì¬ì©ì±ê³¼ ê°ë
ì±ì ëì¼ ì ìì ê²ì´ë¤.\n\n`.with({ status: P.union('ì ê·', 'ì·¨ì') }, handler)` -\u003e `.with(NEW_ORDER, CANCELED_ORDER, handler)`\n\nê²°ê³¼ì ì¼ë¡ ë³´ë©´ ëì¼í ëìì ìííë ì½ëë ìëì ê°ì 모ìµì¼ë¡ ë°ëê² ëë¤.\n\n```ts title=\"ASIS-TOBE\"\nif (data.status === 'ì ê·' || data.status === 'ì·¨ì') return ''; // ASIS\n\n.with(NEW_ORDER, CANCELED_ORDER, handler); // TOBE\n```\n\n## ë§ì¹ë©°\n\nìì ì´ì¼ê¸°íë¯ì´ ìì§ì ìë°ì¤í¬ë¦½í¸ê° í¨í´ 매ì¹ì ì§ì ì ì¼ë¡ ì¬ì©í ì ìë íê²½ì ìëë¤.\n\në°ë¼ì, **ìë¹ì¤ì ì¸ë¶ ìì¡´ì±ì íë ì¶ê°íê³ ìë¡ì´ ì íì ì½ë를 ì½ì´ì¼ íë¤ë ê²ì´ ê°ì¥ í° íë¤ì´ ë ê²ì´ë¤.**\n\nê·¸ë¼ìë ë¶êµ¬íê³ ë¤ë£¨ê³ ìë 문ì ë¤ì ë³µì¡ëê° ëê³ ìì ì ì¼ë¡ ìë¹ì¤ë¥¼ ì ê³µíëë° ì¡°ê¸ ë í¬ì»¤ì¤ë¥¼ ë§ì¶ê³ ì íë¤ë©´, ì¬ì©ì ê³ ë¯¼íê³ ëë£ì ë
¼ìí´ ë³´ë ê²ë§ì¼ë¡ë ì¢ì ìê°ì´ ë ê²ì´ë¼ íì íë¤.\nì´ë¬í ìê°ì ê°ì§ë ê²ë§ì¼ë¡ë í¨í´ 매ì¹ì´ë ê²ì ëí´ ì¸ì§í ì ìê³ ë³µì¡í 문ì í´ê²°ì ìí ìµì
ë¤ì´ ëì´ëë ê²ì´ë¼ê³ ìê°íë¤.\n\n**ë§ì½ íì¬ ë§ì£¼íê³ ìë 문ì ë¤ì ë³µì¡ëê° ëê³ ì²ë¦¬íë ë° ë§ì ìê°ì í ì íê³ ìë¤ë©´ `ts-pattern`ì´ ì°ë¦¬ë¥¼ ëìì¤ ê²ì´ë¤.**\n\n## ì°¸ê³ \n\n- [í¨í´ ë§¤ì¹ TC39 ì¬ë¼ì´ë](https://hackmd.io/@mpcsh/HkZ712ig_#/)\n- [íì´ì¬ì í¨í´ ë§¤ì¹ ëì
ì ì½í ì´ì¼ê¸°](https://ryanking13.github.io/2021/03/04/python-patma.html)\n- [ts-pattern ê¹íë¸](https://github.com/gvergnaud/ts-pattern)\n- [í¨í´ ë§¤ì¹ ìí¤í¼ëì](https://ko.wikipedia.org/wiki/%ED%8C%A8%ED%84%B4_%EB%A7%A4%EC%B9%AD)\n","data":{"id":"ts-pattern","title":"ts-patternì íì©íì¬ í´ê²°íë ê²","description":"í¨í´ ë§¤ì¹ ê·¸ë¦¬ê³ ts-patternì ëí´ ììë³´ê³ , ì´ë¥¼ íì©íì¬ ë¬¸ì ë¤ì í´ê²°íë ì¬ë¡ë¤ì ìê°í©ëë¤.","preview":"í¨í´ ë§¤ì¹ ê·¸ë¦¬ê³ ts-patternì ëí´ ììë³´ê³ , ì´ë¥¼ íì©íì¬ ë¬¸ì ë¤ì í´ê²°íë ì¬ë¡ë¤ì ìê°í©ëë¤.","keywords":"javascript, typescript, pattern, Pattern matching, ts-pattern","slug":"ts-pattern","createdAt":"2024.02.04","published":true},"filePath":"ts-pattern.mdx"},{"content":"\nì´ ê¸ììë ë§ì´í¬ë¡ íë¡ í¸ìëì ê´í ê³ ì°°ê³¼ [ì¹í© 5ì Module Federation](https://webpack.kr/concepts/module-federation/) ì¼ë¶ 기ë¥ì ëí´ ììë³´ê³ , ì ë¹í ìì
16 ì½ë ìì±ì íµí´ ì»ì ìê°ì ëë ë³¼ ìê°ì´ë¤.\n\në´ê° ë§ì´í¬ë¡ íë¡ í¸ìë ìí¤í
ì²ì ê´ì¬ì ê°ì§ê³ ê³ ì°°ì íê² ë ê³ê¸°ë íì¬ ê°ë°/ì´ì ì¤ì¸ [배민ìí](https://mart.baemin.com/)ë¼ë ìë¹ì¤ì í경과 ê´ë ¨ì´ ìë¤.\n( 배민ìíë ììì
ì¬ì¥ëë¤ì ëìì¼ë¡ íìí ìíë¤ì í매íë ì´ì»¤ë¨¸ì¤ ìë¹ì¤ )\n\nì¬ë ì¼í몰ë¤ê³¼ ë§ì°¬ê°ì§ë¡ ë§ì íì´ì§ê° ì¡´ì¬íê³ , ì§ë ìë
ê° ë§ì ê°ë°ìë¤ì ì´ì ê³¼ ë
¸ë ¥ì¼ë¡ ìì°ë ì½ëì ìë í족í ìí©ì´ë¤. `Webpack Bundle Analyzer` 를 íµí´ ë¶ìí 결과를 ì ê¹ íì¸ì í´ë³´ë©´,\n\n\n\nì¼í몰ìì ì ê³µíë **ì½ 120ê°ì íì´ì§ë 14Mì ì¡ë°íë ë²ë¤ ì½ëê° 158ê°ì ì²í¬ë¡ ë¶ë¦¬**ëì´ ìë¤.\n\n( ìë²ì¬ì´ë ì½ëì íë¡ì í¸ ì¸ë¶ì ìë ëìì¸ ìì¤í
ê³¼ ê°ì ì½ëë¤ê¹ì§ ê³ ë ¤íë©´ ì¡°ê¸ ë ë§ì ê² ê°ë¤. )\n과거 ê°ë° ì´ê¸° ë¨ê³ìì ì íë 모ë
¸ë¦¬ì¤í Single-Page-Application ë°©ìì ê°ë°ì íì¬ê¹ì§ ê³ ìëì´ ìê³ ,\n\në¹ëí´ì§ ì í리ì¼ì´ì
ì ë¹ë í¼í¬ë¨¼ì¤, ì½ë íì¬, ìì¡´ ê´ë¦¬ ë±ì ë¹ì©ì ì ì°¨ ì¦ê°íê³ ìë¤.\n\nê°ë° í¸ìì±ê³¼ ìì°ì±ì ìí´ ìí¤í
ì² ê°ì ì´ íìí ìê°ì´ ë ê²ì´ë¼ê³ ìê°ì´ ë¤ìë¤.\n\nì¬ë¬ê°ì§ ë°©ìì íµí´ ê°ì ì´ ê°ë¥íê² ì§ë§,\n\nëë **ë§ì´í¬ë¡ íë¡ í¸ìëì ëí ê³ ì°°**ê³¼ **ê²ì ì²´ì¸ì ë¼ê³ ë¶ë¦¬ì°ë [ì¹í© 5ì Module Federation](https://webpack.kr/concepts/module-federation/)**ì ì¼ë¶ 기ë¥ì ëí´ ìì ë³¼ ìì ì´ê³ , ìì ì½ë ìì± ê²½íì íµí´ 리í©í°ë§ì ë°ê±°ë¦ì ë§ë¤ ìê°ì´ë¤.\n\n## Micro Frontend?\n\në§ì´í¬ë¡ íë¡ í¸ìëì ê°ë
ì ìë§ì ê°ë°ì, ê·¸ë¦¬ê³ ì¡°ì§ë¤ì´ 모ë
¸ë¦¬ì¤ ìí¤í
ì²ìì ë§ì´í¬ë¡ ìë¹ì¤ ìí¤í
ì²ë¡ ì ííë©´ì ì»ì ì´ì ë¤ì ì¹ ì í리ì¼ì´ì
ê°ë° í경과 ìíê³ìë ì ì©íê³ ì íë ì ê·¼ì¼ë¡ë¶í° ëì¨ ê²ì´ë¤.\n\në§ì´í¬ë¡ íë¡ í¸ìëì ëí ì¤ëª
ê³¼ ì¸ë¶ì ì¸ êµ¬í ìë [ë§í´íì¸ë¬ ê¸](https://martinfowler.com/articles/micro-frontends.html#TheMicroFrontends)ìë ìê°ë [Cam Jackson](https://camjackson.net/)ì ê¸ì ì ì¤ëª
ì´ ëì´ìë¤. ì´ ê¸ììë ë§ì´í¬ë¡ íë¡ í¸ìëì 구íì¼ë¡ ì¬ë¬ ê°ì§ ë°©ìì ì를 ë¤ìì§ë§ ê²°ê³¼ì ì¼ë¡ ì±íí ë°©ìì **컨í
ì´ë ì í리ì¼ì´ì
ì ë§ì´í¬ë¡ ì í리ì¼ì´ì
ì ë¶ë¦¬íê³ ** **ë°íììì 컨í
ì´ë ì í리ì¼ì´ì
ì´ ë§ì´í¬ë¡ ì í리ì¼ì´ì
ë¤ì íµí©**íë ë°©ìì´ìë¤. ì í리ì¼ì´ì
ë¤ì 모ë ë
립ë íê²½ìì ê°ë°í ì ìì¼ë©°, íìì ìí´ ê³µíµ UI êµ¬ì± ììë¤ì ì¬ì©í ìë ìë¤. 컨í
ì´ë ì í리ì¼ì´ì
íµí©íë ìí ì ë§¡ì ë¼ì°í
ê²½ë¡ì ë°ë¼ ê° ë§ì´í¬ë¡ ì í리ì¼ì´ì
ì ì ê³µí ì ìëë¡ ì²ë¦¬ëë¤.\n\n\n\në§ì´í¬ë¡ íë¡ í¸ìëì 주ìí ì¥ë¨ì ì ìëì ê°ì´ ìì½í ì ìë¤.\n\n**ì¥ì **\n\n- ë§ì´í¬ë¡ ì í리ì¼ì´ì
ë¤ì **기ì ì¤í, ì½ë ë² ì´ì¤, ì¸ë¶ í¨í¤ì§ ë²ì ê´ë¦¬ë ê°ë³ì ì¼ë¡ ì²ë¦¬**í ì ìë¤.\n- ë§ì´í¬ë¡ ì í리ì¼ì´ì
ë¤ì **ê°ë°, í
ì¤í¸, ë°°í¬ë ë
립ì **ì´ë¤.\n - ì½ëë² ì´ì¤ë 모ë ê° ì í리ì¼ì´ì
ì ëª
ì¸ì ë§ê² ë¨ìíê² ì¤ê³ ê°ë¥.\n- **ì¬ì©ììê²ë ë¨ì¼ ì í리ì¼ì´ì
ì²ë¼ ëì**íë¤.\n - ê° ê¸°ë¥ìì ê°ë³ë¡ 구íë UI/UXë ëì¼í 룩ì¤íê³¼ ê²½íì ì ê³µ.\n\n**ë¨ì **\n\n- **ì¬ì©ìë¡ë¶í°ì ì¸ë¶ í¨í¤ì§ ë²ë¤ ì¤ë³µ ìì²**.\n - ex) reactì ê°ì í¨í¤ì§ê° ì í리ì¼ì´ì
Aì Bì ë²ë¤ë§ ì½ëì ì¤ë³µì¼ë¡ ë¤ì´ê° ì ìì.\n- **ê°ë° íê²½.**\n - ë
립ì ì¸ ê°ë° íê²½ì ë³´ì¥ë°ì ì ìì§ë§, íµí©ë ì í리ì¼ì´ì
ì í경과 ì°¨ì´ê° ìì¼ë¯ë¡ ë°ìí ì ìë 문ì ì .\n- **ì´ì ë³µì¡ë**\n - 기ì ì¤í, ê°ë° ê´ìµì íí¸í ê°ë¥ì±.\n - ì½ë ì ì¥ì, ë°°í¬ íì´íë¼ì¸, í
ì¤í¸ ë° ë¦´ë¦¬ì¦ íë¡ì¸ì¤ ì¦ê° ê°ë¥ì±.\n\nìí¤í
ì²ìë íì ë¤ìí ê´ì ê³¼ ìí©ììì í´ë²ì´ ì¬ë¿ ìê³ ë§ì´í¬ë¡ íë¡ í¸ìëì ëí´ ìê°íë ê²ë
16 ë§ì°¬ê°ì§ì¼ ê²ì´ë¤. ëë [Cam Jackson ê¸](https://martinfowler.com/articles/micro-frontends.html#TheMicroFrontends)ì ìê°ë ë§ì´í¬ë¡ íë¡ í¸ìëì ëí í´ë²ì ì ì ì¼ë¡ ëìíë¤.\n\nì í리ì¼ì´ì
ë¤ì ë°íì íê²½ìì íµí©ì´ ëì´ì¼ íê³ , ê°ìì ê°ë° ìëª
주기를 ê°ì§ ì ìì´ì¼ íë¤. ì´ë CI/CDë 모ë ë
립ì ì¼ë¡ 구ì±ì´ ë ì ìë¤ë ë»ì´ë©°, ì¼ë¶ ë³ê²½ë 기ë¥ì ìí´ ì í리ì¼ì´ì
ì ì²´ê° ë¤ì ë¹ë, ë°°í¬ê° ëì§ ììë ëë¤ë ê²ì´ë¤.\n\nì´ì , ë§ì´í¬ë¡ íë¡ í¸ìë 구ì±ì ìì½ê² í´ì¤ [ì¹í© 5ì Module Federation](https://webpack.kr/concepts/module-federation/)ì ëí´ì ììë³´ëë¡ íì.\n\n## Module Federation?\n\nì¹í© 5 ë²ì ì ì¶ìì í¨ê» ëì¨ ê¸°ë¥ ì¤ íëì¸ **모ë íëë ì´ì
ì í¹ì ì í리ì¼ì´ì
(모ë)ìì ëì ì¼ë¡ ë¤ë¥¸ ë¹ëì 모ë ì½ë를 ë¶ë¬ì ì¤íì í ì ìê² í´ì¤ë¤.**\n\nì¦, ì¬ë¬ ê°ì ê°ë³ ë¹ë ì½ëê° íëì ì´í리ì¼ì´ì
ë´ìì 구ëëë ê²ì´ë¤. ëí, ê°ë³ ë¹ëë ìë¡ ìì¡´ì±ì´ ìì´ ê°ë³ì ì¼ë¡ ë¹ë, ë°°í¬ê° ê°ë¥íë¤.\n\n모ë íëë ì´ì
ì ëª ê°ì§ ì©ì´ì í¹ì§ì ( _ê³ ìì¤ ê´ì ì¼ë¡_ )ìì½í´ ë³´ê² ë¤.\n( ìì¸í ë´ì©ì [ê³µì 문ì](https://webpack.kr/concepts/module-federation/)ìì íì¸í ì ìë¤. )\n\n- **ê°ê°ì ë¹ëë 컨í
ì´ë ìí ì íë¤.**\n- **ê°ê°ì ë¹ëë í¸ì¤í¸ì ë¦¬ëª¨í¸ ëª¨ë ë ì ìë¤.**\n - **host :** í¸ì¤í¸ë íì´ì§ ë¡ë ì ê°ì¥ 먼ì ì´ê¸°íëë ë¹ë.\n - **remote :** 리모í¸ë í¸ì¤í¸ì ìí´ ìë¹ëë ë¹ë.\n - ë¹ë ë **모ëì ë°íììì 모ë ìë°©í¥(Bidirectional)ì¼ë¡ ìë¹ë ì ìë¤.**\n- ê° ì»¨í
ì´ëë¤ìì ê³µíµì ì¸ ì¸ë¶ í¨í¤ì§ì ëíëìë ì¤ì ì¼ë¡ ì²í¬ì ì¤ë³µì ë§ì ì ìë¤.\n - í¹ì ë²ì ì ëª
ìíë¤ë©´, í´ë¹ ë²ì ì¼ë¡ ì¬ì©í ì ìë¤.\n - ex) react, react-dom, etc..\n- ìì **ì¤ì ë¤ì ì¹í©ì ModuleFederationPluginì íµí´ í ì ìë¤.**\n- íê²½ì ìì¡´íì§ ìëë¤.\n - ex) browser, node.js ë±ìì ì¬ì© ê°ë¥.\n\n### ì ì¦ì¼ì´ì¤\n\n- **ê³µì© ì»´í¬ëí¸ ë¼ì´ë¸ë¬ë¦¬ì 컨í
ì´ëë¡ ì¬ì©**\n ì¬ë¬ ì í리ì¼ì´ì
ìì ì¬ì©íë ëìì¸ ìì¤í
ê³¼ ê°ì ê³µì© ì»´í¬ëí¸ í¹ì ì¶ìíë ì½ëë¤ì ë¼ì´ë¸ë¬ë¦¬ 컨í
ì´ëë¡ ë§ë¤ì´ ê³µì íë ë°©ë²ì´ë¤.\n ì´ë ì í리ì¼ì´ì
ê³¼ ê³µì© ì½ëë¤ì ë
립ì ì¸ ê°ë°, ë°°í¬ê° ê°ë¥íë¤.\n ê³µì© ì»´í¬ëí¸ì ì
ë°ì´í¸ê° ì¼ì´ë ê²½ì°, ì í리ì¼ì´ì
ë¤ì ë°°í¬ ìì´ ë°íììì ìµì ë²ì ì ì»´í¬ëí¸ ë¼ì´ë¸ë¬ë¦¬ë¥¼ ìëì¼ë¡ ì¬ì©í ì ìë¤.\n\n\u003cbr /\u003e\n\n\n\n\u003cbr /\u003e\n\n- **íì´ì§ë³ ë
립ì ë¹ë ì ì¬ì©**\n ë¨ì¼ íì´ì§ ì í리ì¼ì´ì
ìì ê° íì´ì§ë¥¼ ë¶ë¦¬íì¬ ë
립ì ì¸ ê°ë°ê³¼ ë°°í¬ íë¡ì¸ì¤ë¥¼ ê°ì§ ì ìë¤.\n ì í리ì¼ì´ì
ìì ìì ë 벨ì ëê³ , íì´ì§ ë¼ì°í
ì ë§ë ê° ì í리ì¼ì´ì
ì ì격 모ëë¡ ì°¸ì¡°íë ë°©ìì´ë¤. ì í리ì¼ì´ì
ìì ì¼ë°ì ì¼ë¡ ì¬ì©ëë ë¼ì´ë¸ë¬ë¦¬ë¥¼ ê³µì 모ëë¡ ì ìí ì ìê³ , ë¼ì°í
ê²½ë¡ì ë³ê²½ì´ ìì´ë ê²½ì°ì ë°°í¬ë¥¼ íê² ëë¤. ê° íì´ì§ ì í리ì¼ì´ì
ì ë¤ë¥¸ íì´ì§ì ìê´ìì´ ë
립ì ì¸ ë°°í¬ê° ê°ë¥íë¤.\n\n\u003cbr /\u003e\n\n\n\n\u003cbr /\u003e\n\n리모í¸ì í¸ì¤í¸ ì¬ì´ì íì´íë **모ëë¤ì´ ë°íììì 모ë ìë°©í¥(Bidirectional)ì¼ë¡ ìë¹ê° ê°ë¥í ê²ì ë³´ì¬ì¤ë¤.** ì´ë ìì ìì ì¡°ê¸ ë ìì¸í ë¤ë£¨ê² ë¤.\n\nìì ë ê°ì§ì ì¬ë¡ë¥¼ ì ì íê² ì¡°í©íì¬ ë¤ì ìì 를 구ì±í´ ë³´ì.\n\n## ìì \n\n\n\nìì ê°ì êµ¬ì¡°ë¡ ì¤ê³ë¥¼ íë¤ê³ ê°ì íì¬, ëª ê°ì§ ì¤ì ì ëí´ êµ¬ì²´ì ì¸ ì½ë를 ìì±í´ ë³´ì\n\n## ëë í 리 구조\n\n```tsx\n- packages\n\t- core\n\t\t- ...\n\t\t- webpack.config.js\n\t\t- package.json\n\t- order\n\t\t- coreì ì ì¬\n\t- shell\n\t\t- coreì ì ì¬\n\t- products\n\t\t- coreì ì ì¬\n\t- ...\n- ...\n- package.json // í¨í¤ì§ ì¤í¬ë¦½í¸ ë³ë ¬ ì¤íì ìí ì¤í¬ë¦½í¸\n```\n\n- ê° ëª¨ëì packages ëë í 리 íìì ìì¹íë¤.\n- ê° ëª¨ëì webpackì ì¬ì©íë©°, ë
립ì ì¼ë¡ ì¸ë¶ í¨í¤ì§ ìì¡´ì±ì ê°ì§ë¤.\n- ë£¨í¸ ëë í 리ì package.jsonì ê° ëª¨ëì ì¤í¬ë¦½í¸ë¥¼ ë³ë ¬ë¡ ì¤íí ì ìê² ì¤ì íë¤.\n\n## Shell Module\n\n### webpack.config.js\n\n- **shell**ì webpack ì¤ì ì ìëì ê°ì ë´ì©ì ë°ë¥´ëë¡ íë¤.\n - í¸ì¤í¸ ì í리ì¼ì´ì
ì¼ë¡ì¨, 모ë ë¦¬ëª¨í¸ ì í리ì¼ì´ì
모ë ìë¹.\n - orderì ê°ì ë¤ë¥¸ ì í리ì¼ì´ì
ë¤ìì íëë ì´í¸ê° ê°ë¥íëë¡ `Shell App` ì 리모í¸ë¡ ë
¸ì¶.\n - ë§ì½, íì´ì§ ì ììì ì¬ì©ë
16Context ë±ê³¼ ê°ì ì½ëê° ìë¤ë©´ ë
¸ì¶.\n - ì½ì´ ë¼ì´ë¸ë¬ë¦¬ 컨í
ì´ë 모ë ìë¹.\n - ë¡ì»¬ìì 3000ë² í¬í¸ë¡ ëì.\n - ê³µì© ì¸ë¶ í¨í¤ì§ë ì¤ë³µë ì²í¬ê° ë°ìëì§ ìëë¡ ì ì¸.\n\n```tsx\nplugins: [\n new ModuleFederationPlugin({\n name: 'shell',\n filename: 'shell.remoteEntry.js', // shellì ë¦¬ëª¨í¸ ìí¸ë¦¬\n remotes: {\n\t\t\t\tcore: 'core@http://localhost:2000/core.remoteEntry.js',\n\t\t\t\tmain: \"main@http://localhost:3001/main.remoteEntry.js\",\n products: \"products@http://localhost:3002/products.remoteEntry.js\",\n order: \"order@http://localhost:3003/order.remoteEntry.js\",\n },\n exposes: {\n './Shell': './src/Shell'\n },\n shared: [\n {\n react: {\n singleton: true,\n requiredVersion: deps.react,\n },\n 'react-dom': {\n singleton: true,\n requiredVersion: deps['react-dom'],\n },\n },\n ],\n }),\n]\n```\n\n### Entry of webpack\n\n- 모ë íëë ì´ì
ì, ì¼ë°ì ì¼ë¡ ë¹ë기 ê²½ê³ë¥¼ ì¬ì©íë ê²ì´ ì¶ì²ë기 ë문ì ì´ ë´ì©ì ë°ë¥¸ë¤.\n - ë¹ë기 ê²½ê³ê° ì¶ì²ëë ì´ì ë ì±ë¥ í¥ìì ìí´ ì²í¬ì ì´ê¸°í ì½ë를 ë¶í í기 ìí¨.\n\n```tsx\n// index.js\nimport('bootstrap');\n\n// bootstrap.js\nimport ShellApp from \"./ShellApp\";\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nconst root = createRoot(document.getElementById(\"root\"));\n\nroot.render(\u003cShellApp /\u003e);\n```\n\n### React App\n\n- ì½ì´ ì»´í¬ëí¸, í¹ì ëìì¸ ìì¤í
ì»´í¬ëí¸ë **ì½ì´ ì»´í¬ëí¸ ë¼ì´ë¸ë¬ë¦¬ 컨í
ì´ë 모ëìì** **ê°ì ¸ì¨ë¤**.\n- ê° **íì´ì§ë¤ì ê°ë³ íì´ì§ ì í리ì¼ì´ì
모ëìì ê°ì ¸ì¨ë¤**.\n\n```tsx\nconst Tabs = React.lazy(() =\u003e import('core/Tabs'));\n\nconst MainPage = React.lazy(() =\u003e import('main/MainPage'));\nconst ProductsPage = React.lazy(() =\u003e import('products/ProductsPage'));\n....\n\nconst ShellApp = () =\u003e {\n\treturn (\n\t \u003cProvider\u003e\n\t\t\t\u003cReact.Suspense fallback={'Loading'}\u003e\n\t\t\t\t\u003cGNB\u003e\n\t\t\t\t\t\u003cTabs\u003e\n\t \u003cLink to=\"/\"\u003e...\u003c/Link\u003e\n\t \u003cLink to=\"/products\"\u003eProducts\u003c/Link\u003e\n\t\t\t\t\t\t\t....\n\t \u003c/Tabs\u003e\n\t\t\t\t\u003c/GNB\u003e\n\t\t\t\u003c/React.Suspense\u003e\n\t\t\t\u003cReact.Suspense fallback={'Loading'}\u003e\n\t\t\t\t\u003cRoutes\u003e\n \u003cRoute path=\"/\" element={\u003cMainPage /\u003e} /\u003e\n \u003cRoute path=\"products/*\" element={\u003cProductsPage /\u003e} /\u003e\n\t\t\t\t\t\t....\n\t\t\t\t\u003c/Routes\u003e\n\t\t\t\u003c/React.Suspense\u003e\n\t\t\u003c/Provider\u003e\n\t)\n};\n\nexport default ShellApp;\n```\n\n## Core Component Library Module\n\n### webpack.config.js\n\n- **Core Component Library**ì webpack ì¤ì ì ìëì ê°ì ë´ì©ì ë°ë¥´ëë¡ íë¤.\n - ë¦¬ëª¨í¸ ëª¨ëë¡ë§ ì¬ì©.\n - ë¡ì»¬ìì 2000ë² í¬í¸ë¡ ëì.\n - ê³µì© ì¸ë¶ í¨í¤ì§ë ì¤ë³µë ì²í¬ê° ë°ìëì§ ìëë¡ ì ì¸.\n\n```tsx\nplugins: [\n new ModuleFederationPlugin({\n name: 'core',\n filename: 'core.remoteEntry.js',\n exposes: {\n './Button': './src/Button'\n './Tabs': './src/Tabs'\n },\n shared: {\n react: {\n singleton: true,\n requiredVersion: deps.react,\n },\n 'react-dom': {\n singleton: true,\n requiredVersion: deps['react-dom'],\n },\n },\n }),\n ],\n```\n\n**Components**\n\n- ì»´í¬ëí¸ë¤ì ì¼ë°ì ì¸ ì½ì´ ì»´í¬ëí¸ í¹ì ëìì¸ ìì¤í
ì ì¤ê³ í¨í´ì¼ë¡ 구ííë¤.\n\n## Page Application Module\n\n### webpack.config.js\n\n- **page application**ë¤**ì** webpack ì¤ì ì ìëì ê°ì ë´ì©ì ë°ë¥´ëë¡ íë¤.\n - ë¦¬ëª¨í¸ ì í리ì¼ì´ì
ì´ì§ë§, ë¡ì»¬ììë í¸ì¤í¸ê° ë ì ìë¤.\n - íì´ì§ë¥¼ 리모í¸ë¡ ë
¸ì¶.\n - ì½ì´ ë¼ì´ë¸ë¬ë¦¬ 컨í
ì´ë 모ë ìë¹.\n - ë¡ì»¬ìì 3000ë² ì´ìì í¬í¸ìì í¸ì¤í¸ë¡ ëì.\n - ê³µì© ì¸ë¶ í¨í¤ì§ë ì¤ë³µë ì²í¬ê° ë°ìëì§ ìëë¡ ì ì¸.\n\n```tsx\nplugins: [\n new ModuleFederationPlugin({\n name: 'main',\n filename: 'main.remoteEntry.js',\n remotes: {\n shell: 'shell@http://localhost:3000/shell.remoteEntry.js',\n core: 'core@http://localhost:2000/core.remoteEntry.js',\n },\n exposes: {\n \"./MainApplication\": \"./src/MainApplication\",\n },\n shared: {\n react: {\n singleton: true,\n requiredVersion: deps.react,\n },\n 'react-dom': {\n singleton: true,\n requiredVersion: deps['react-dom'],\n }\n },\n }),\n new HtmlWebpackPlugin({\n template: './public/index.html',\n }),\n ],\n```\n\n### Entry of webpack\n\n- `Shell` ê³¼ ë§ì°¬ê°ì§ë¡ ìí¸ë¦¬ë ë¹ëê¸°ë¡ êµ¬íëëë¡ ì²ë¦¬íë¤.\n- ë¡ì»¬ ê°ë° ì, Shellì ìë¹íì¬ ë¨ì¼ ì í리ì¼ì´ì
ì²ë¼ ëìí ì ìëë¡ íë¤.\n\n```tsx\n// index.js\nimport('bootstrap');\n\n// bootstrap.js\nimport ShellApp from \"./ShellApp\";\nimport React from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nconst root = createRoot(document.getElementById(\"root\"));\n\nroot.render(\u003cShellApp /\u003e);\n\n// app.js\nimport React from \"react\";\n\nconst Shell = React.lazy(() =\u003e import(\"shell/Shell\"));\n\nfunction App() {\n return (\n \u003cReact.Suspense fallback={\"Loading Shell\"}\u003e\n \u003cShell /\u003e\n \u003c/React.Suspense\u003e\n );\n}\n\nexport default App;\n```\n\n### Consumed React App\n\n- ì½ì´ ì»´í¬ëí¸, í¹ì ëìì¸ ìì¤í
ì»´í¬ëí¸ë **ì½ì´ ì»´í¬ëí¸ ë¼ì´ë¸ë¬ë¦¬ 컨í
ì´ë 모ëìì** **ê°ì ¸ì¨ë¤**.\n\n```tsx\n\nimport React from \"react\";\n\nconst Button = React.lazy(() =\u003e import(\"core/Button\"));\n\nconst MainApplication = () =\u003e {\n return (\n \u003cdiv\u003e\n \u003csection\u003e\n \u003ch1\u003eMAIN PAGE\u003c/h1\u003e\n \u003c/section\u003e\n \u003csection\u003e\n \u003cReact.Suspense fallback=\"fallback\"\u003e\n \u003cButton\u003eButton of MAIN\u003c/Button\u003e\n \u003c/React.Suspense\u003e\n \u003c/section\u003e\n \u003c/div\u003e\n );\n};\n\nexport default MainApplication;\n```\n\nìì ê°ì´ 구í í ì¹ íì´ì§ì ë¤í¸ìí¬ ë¡ê·¸ë ìëì ê°ì 모ìµì¼ë¡ ëíëë¤.\n\n\n\nê³µì© ì¸ë¶ í¨í¤ì§ë¡ ì ì¸í 리ì¡í¸ë íëì ì²í¬ë¡ 구ì±ëì´ ë¡ëëê³ , ê° ëª¨ëë¤ì ì격 ìí¸ë¦¬ë¥¼ íµí´ ë¡ëëë¤.\në¤í¸ìí¬ ë¡ê·¸ë§ ë³´ìì ëë, ë¨ìí ì½ë ì¤í리í
ì´ ë ê²ì²ë¼ ë³´ì´ì§ë§ **ê°ì¥ ì¤ìí ê²ì ê° ëª¨ëë¤ì´ ë
립ì ì¼ë¡ ê°ë°, ì´ì, ë°°í¬ê° ëìë¤ë ê²**ì´ë¤.\n\n**ë¨ì¼ ì í리ì¼ì´ì
ì¼ë¡ì¨ì íµí©ì ë°íììì ì¼ì´ëê² ëë¤.**\n\nì´ ìì ì ì½ëë¤ì 모ë ìëìì íì¸ì´ ê°ë¥íë¤.\n\n- Github : [https://github.com/kimcoder/module-federation-example](https://github.com/kimcoder/module-federation-example)\n- CodeSandbox : [https://codesandbox.io/s/stupefied-kapitsa-gd5255](https://codesandbox.io/s/stupefied-kapitsa-gd5255)\n- CodeSandbox Page : [https://gd5255.sse.codesandbox.io/order](https://gd5255.sse.codesandbox.io/order)\n\n\u003ciframe\n src='https://codesandbox.io/embed/stupefied-kapitsa-gd5255?fontsize=14\u0026hidenavigation=1\u0026theme=dark'\n className='w-full overflow-hidden rounded-md border-none'\n style={{ height: 500 }}\n title='stupefied-kapitsa-gd5255'\n allow='accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr;
16 xr-spatial-tracking'\n sandbox='allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts'\n/\u003e\n\n## ë§ì¹ë©°\n\nì´ ì¥ë¬¸ì ê¸ìì ìê°í **Micro Frontend Architecture**ì ì§í¥ì ê³¼ **Webpack 5ì Module Federation**ì 주ìí í¬ì¸í¸ë ìë 2ê°ì§ë¼ê³ ìê°ëë¤.\n\n- **ê° ëª¨ëì ë
립ì ì¼ë¡ ê°ë°, ì´ì, ë°°í¬**를 í ì ìë¤.\n- **ë°íììì ì¬ë¬ 모ëë¤ì´ íµí©ëê³ , ì¬ì©ììê²ë 모ëë¤ì´ ë¨ì¼ ì í리ì¼ì´ì
ì²ë¼ ëì**íë¤.\n\në¨ì¼ 모ëì ë
립ì ì´ê³ ì ì°í ê°ë° íë¡ì¸ì¤ë¥¼ ê°ì§ ì ìê³ , ë°°í¬ì 롤백ë ë³´ë¤ ë 민첩íê² í ì ìë¤ë ì¶ê°ì ì¸ ì¥ì ì´ ìì ì ìë¤. íì§ë§ ë¶ëª
í ê²ì ì¢ì ë°©ìì ì¤ê³ì ëí ê·¸ë§í ë¹ì©ì´ ë°ìí ê²ì´ë©° ê±°ë²ëì¤ ì¸¡ë©´ììë ë§ì ê³ ë¯¼ê³¼ íì, ê·¸ë¦¬ê³ í©ë¦¬ì ì¸ ì ì±
ë¤ì´ íìíë¤ë ê²ì´ë¤.\n\nì¶ê°ì ì¼ë¡ Angular, Vue, Server Side Rendering, React \u0026 Vue ë± ì´ [ë§í¬](https://github.com/module-federation/module-federation-examples)ìì ë¤ìí Module Federationì ìì ë¤ë ìì¼ë íì¸í´ ë³´ë©´ ì¢ì ê² ê°ë¤.\n\n## ì°¸ê³ \n\n- [https://www.thoughtworks.com/radar/techniques/micro-frontends](https://www.thoughtworks.com/radar/techniques/micro-frontends)\n- [https://microfrontends.com/](https://microfrontends.com/)\n- [https://martinfowler.com/articles/micro-frontends.html](https://martinfowler.com/articles/micro-frontends.html)\n- [https://webpack.kr/concepts/module-federation/](https://webpack.kr/concepts/module-federation/)\n- [https://github.com/module-federation/module-federation-examples](https://github.com/module-federation/module-federation-examples)\n- [https://github.com/kimcoder/module-federation-example](https://github.com/kimcoder/module-federation-example)\n- [https://codesandbox.io/s/stupefied-kapitsa-gd5255](https://codesandbox.io/s/stupefied-kapitsa-gd5255)\n- [https://gd5255.sse.codesandbox.io/order](https://gd5255.sse.codesandbox.io/order)\n","data":{"id":"micro frontend and module federation","title":"Micro Frontend, ê·¸ë¦¬ê³ Webpack Module Federation","description":"ë§ì´í¬ë¡ íë¡ í¸ìëì ê´í ê³ ì°°, ê·¸ë¦¬ê³ ì¹í©ì 모ë íëë ì´ì
","preview":"ë§ì´í¬ë¡ íë¡ í¸ìëì ê´í ê³ ì°°ê³¼ ì¹í© 5ì Module Federation ì¼ë¶ 기ë¥ì ëí´ ììë³´ê³ , ì ë¹í ìì ì½ë ìì±ì íµí´ ì»ì ìê°ì 기ë¡íë ê¸ì
ëë¤.","keywords":"react, next, create-react-app, clean architecture, architecture","slug":"micro-frontend-module-federation","createdAt":"2022.07.01","published":true},"filePath":"micro-frontend-module-federation.mdx"},{"content":"\n**_ìíí¸ì¨ì´ë íì ë¶ëë¬ìì¼ íë¤_**\n\nì´ ê¸ììë ìì ì¸ì©êµ¬ì²ë¼ **ë³ê²½ì ì ì°í íë¡ í¸ìë ìí¤í
ì²ë¥¼ 구ì±íë íëì ë°©ë²ê³¼ ë°©ë²ì 근거, ê·¸ë¦¬ê³ ì´ë¥¼ ì ì´í´ ì¤ ì ìë ESLintì ê·ì¹ê¹ì§ ìê°íê³ ì íë¤.**\u003cbr/\u003e\n\nëë ì§ë ëª ë
ê° ì¦ì ì´ì§ì¼ë¡ 꽤ë ë§ê³ ë¤ìí íë¡ì í¸ë¥¼ ê²½íí ë°ê° ìë¤.\u003cbr/\u003e\nëë¶ë¶ì `React`ë¡ êµ¬ì±ì´ ëì´ììê³ , ì´ë¥¼ ê°ë°íê³ ì ì§ ë³´ìíë ë§ì ê°ë°ìë¶ë¤ë ìê² ëìë¤.\u003cbr/\u003e\nì¹ ì í리ì¼ì´ì
ì ê·ëª¨, ì´ì 기ê°, íë«í¼, ì¸íë¼, ê°ë° íê²½, í¬ì
ì¸ë ¥, 컨벤ì
ê³¼ ê°ì ê²ì 모ë ë¬ëì§ë§,\u003cbr/\u003e\n`React` ì ëë°ëë ë¼ì´ë¸ë¬ë¦¬, ì½ë í¨í´, ê·¸ë¦¬ê³ ì´ë¥¼ ì ì§ ë³´ìí기 ìí ê°ë°ìë¤ì ì´ì ê³¼ ë
¸ë ¥ë¤ì ë¹ì·í ì ì´ ë§ìë¤.\u003cbr/\u003e\n\në§ì ê°ë°ìë¤ì´ íì ì³ì ì íì íë ¤ê³ ë
¸ë ¥íì§ë§,\u003cbr/\u003e\ní¬ê³ ìì í¼ì³ë¤, ì ì§ ë³´ì, ë²ê·¸/ ì¥ì ëì, íìì ì¸ íë«í¼ ë²ì ëì ë± ë¤ìí ì
무ë¤ê³¼ íì´í¸í ì¼ì ìì í¸ìì ì¸ ì íë¤ì íë ê²½ì°ë ë§ì´ ë³´ìë¤.\u003cbr/\u003e\nì´ë¬í í¸ìì ì¸ ì íì ì¸ì ê° ë¤ì ì°ë¦¬ë¤ì ë°ëª©ì ì¡ê² ë ê²ì´ë¤.\u003cbr/\u003e\n\nìì ë¡ì´ ë°ëª©ê³¼ í¨ê» í¨í¨ ë ìê°ê¸° ì¢ì ìí¤í
ì²ë¥¼ 구ì±í´ ë³´ì.\n\n## ì¢ì ìí¤í
ì²? íë¡ í¸ìëììë?\n\n`í´ë¦° ìí¤í
ì² (ë¡ë²í¸ C.ë§í´ )`ìì ì¢ì ìí¤í
ì²ì ëí´ ì¤ëª
í ê² ì¤ ëª ê°ì§ë¥¼ ì¶ë ¤ë³´ìë¤.\n\n- **ì¢ì ìí¤í
ì²ë ì¸ë¶ì¬íì ì ì±
ì¼ë¡ë¶í° ì ì¤íê² ê°ë ¤ë´ê³ , ëì´ ê²°í©ëì§ ìëë¡ ì격íê² ë¶ë¦¬íë¤.**\n- **ì¢ì ìí¤í
ì²ë ìì¡´ì±ì ë°©í¥ì´ ì»´í¬ëí¸ ìì¤ì 기ë°ì¼ë¡ ì°ê²°ëëë¡ ë§ë¤ì´ì¼ íë¤.**\n- **ì¢ì ìí¤í
í¸ë ê²°ì ëì§ ìì ì¬íì ì를 ìµëííë¤.**\n - ( í¥í ìì¤í
ì ë³ê²½ì´ íìí ë ì´ë¤ ë°©í¥ì¼ë¡ë ì½ê² ë³ê²½í ì ìëë¡ íë¤. )\n\nìì ë´ì©ê³¼ ëì ì´í´ë¥¼ ë°íì¼ë¡ ì
16´ë í 목ì ê³¼ ìì¹ì ê°ì§ê³ íë¡ í¸ìë ìí¤í
ì²ì ì ì©ì íìëì§ ê°ëµí ì 리를 í´ë³´ìë©´..\n\n### 목ì \n\n\u003e **ì¢ì ìí¤í
ì²**ì ê¶ê·¹ì ì¸ ëª©ì ì ìíí¸ì¨ì´ë¥¼ ê°ë°íê³ ì ì§ ë³´ìíë ë° ìì´, **ìµìíì ë
¸ë ¥ì¼ë¡ ìµëì í¨ì¨ì ì»ê² í´ì£¼ë ê²**ì´ë¤.\n\nì´ë ê°ë°ìê° ìì¤í
ì ì½ê² ì´í´íëë¡ í´ì£¼ê³ , ì½ê² ê°ë°íê² í´ì£¼ë©°, ì ì§ ë³´ì ë° ë°°í¬ê¹ì§ ì½ê² í´ì¤ ì ìê² íë¤ë ê²ì¼ë¡ íì´ì ííì´ ê°ë¥íë¤.\u003cbr/\u003e\n\nìí¤í
ì² ê´ì ìì ì½ê² ì´í´íê³ , ê°ë°, ì ì§ ë³´ìíë¤ë ê²ì ì´ë¤ ì미ì¼ê¹?\u003cbr/\u003e\nì ì´ë ëìê²ë ì í리ì¼ì´ì
ì êµ¬ì¡°ê° í ëì ëë¬ë ë구ë ì½ê² íì
í ì ìì¼ë©°, 기ë¥ë³ 모ëíê° ì ëì´ ìê³ , ë
립ì ì´ë©° ì½ê² ë°°í¬ê¹ì§ í ì ìì´ì¼ íë¤ë ê²ì¼ë¡ ì´í´íê³ ìë¤.\u003cbr/\u003e\n\nì¹ ì í리ì¼ì´ì
ì ê·ëª¨ì ë°ë¼ ì°¨ì´ê° ìì ì ìê³ ì¢ì ìí¤í
ì²ë¥¼ 구ì±íë ì¬ë¬ ì íì§ê° ìê² ì§ë§,\u003cbr/\u003e\nì¬ê¸°ìë **ë¨ì¼ ìì¤ ìì¤ì¼ë¡ 모ë
¸ë¦¬í±í 구조ìì 모ë ê° ìì¡´ì±ì ì ì´íë ë°©ìì íµí´ 구ì±**í´ ë³¼ ê²ì´ë¤.\u003cbr/\u003e\n\në³íê° ë§ê³ 기ì ì ë°ì ìëë ë¹ ë¥¸ ìíê³ ììì ì ì°í ìí¤í
ì²ë¥¼ 구ì±íì¬ ìµìíì ë
¸ë ¥ì¼ë¡ ìµëì í¨ì¨ì ê°ì§ ì ìëë¡ í´ë³´ì.\n\n### ê·ì¹\n\n- ì¹ ì í리ì¼ì´ì
ë¡ì§ê³¼ ì¸ë¶ì ì¸ ëë©ì¸ ë¡ì§ì ë¶ë¦¬íë¤.\n- ë¶ë¦¬ë ë¡ì§ê°ì ìì¡´ ë°©í¥ì ëª
ííê² íë¤.\n- ë³íê° ë§ì ì¸ë¶ 모ëì ê°ì¶ê³ , ì¶ìíë ì¸í°íì´ì¤ë¥¼ ì¬ì©í ì ìê²íë¤.\n\n## ëë í 리 구조\n\nì´ ê¸ììë `Next.js` íë¡ì í¸ë¥¼ ëìì¼ë¡ ìì ê·ì¹ì ì¤ìíì¬ êµ¬ì±í´ ë³´ê² ë¤.\u003cbr/\u003e\n[Next.js](https://github.com/vercel/next.js/tree/canary/examples)ì ë§ì ìì ë¤ì ìì¤ê³¼ ë¹ì·íê² íë¤ë©´, ìëì ê°ì ê³ì¸µì ê°ì§ 구조ì 모ìì´ ëì¬ ì ìë¤.\n\n\n\n### Core\n\nì
ë ¥ê³¼ ì¶ë ¥ì¼ë¡ë¶í° ê±°ë¦¬ê° ë©ê¸° ë문ì ê³ ìì¤ì´ë¼ê³ ë³¼ ì ìë ê³ì¸µì´ë¤.\u003cbr/\u003e\nìì ë§í ìì¹ìì ì¸ë¶ì ì¸ ëë©ì¸ ë¡ì§ì´ ìë, ì¹ ì í리ì¼ì´ì
ë¡ì§ê³¼ ì¶ìíë ì½ëë¤ì´ ë¤ì´ê°ë¤.\u003cbr/\u003e\nì를 ë¤ë©´ ìëì ê°ì ì±ê²©ì ì½ëë¤ì´ ë¤ì´ê° ì ìë¤.\n\n- ì í리ì¼ì´ì
ì´ ì¸ë¶ìì íµì ì ìí´ íìí 구íì²´\n- ëë©ì¸ê³¼ ì°ê´ì´ ìë ê³ ìì¤ì ì í¸ë¦¬í°\n- ì¬ì¬ì©ê°ë¥í ì»´í¬ëí¸\n - ex) Button, Input, Select\n- ì¤ìëê° ëì ì¸ë¶ 모ë(ë¼ì´ë¸ë¬ë¦¬)ì ì´ëí°\n\n**Core ê³ì¸µì ìë ì½ëë¤ì ì ë Core ìì ì¸ë¶ì ìë ê³ì¸µ**(lib/components, pages)**ì 참조íë©´ ì ëë¤.**\n\n### Components / Lib\n\nì´ ê³ì¸µì ëë©ì¸ì ì¢
ìì ì´ë©°, Core ê³ì¸µì ì½ëë¤ì 참조í ì ìê³ , ìë ììì ê°ì ì½ëë¤ì´ ë¤ì´ê°ë¤.\u003cbr/\u003e\n( 주문ì´ë¼ë ëë©ì¸ì´ ìí íë¡ì í¸ë¼ê³ ê°ì . )\n\n```tsx\n- src\n\t- lib\n\t\t- order\n\t\t\t- constatns\n\t\t\t- hooks\n\t\t\t- mutations\n\t\t\t- queries\n\t\t\t- utils\n\t\t\t- ....\n\n- src\n\t- components\n\t\t- order\n\t\t\t- ItemList.tsx\n\t\t\t- Price.tsx\n\t\t\t- Payment.tsx\n\t\t\t- ...\n```\n\n- **Lib**\n - ëë©ì¸ì ê´ë ¨ëì´ ìë ë¡ì§ë¤.\n - components ê³ì¸µê³¼ pages ê³ì¸µìì 참조ëì´ì§ë¤.\n- **Components**\n - ëë©ì¸ì ê´ë ¨ëì´ ìë ì»´í¬ëí¸.\n - ëë©ì¸ì êµíëì´ ì¬ì¬ì©ì±ì ë®ë¤.\n - pages ê³ì¸µìì 참조ëì´ì§ë¤.\n\n### **Pages**\n\nëë©ì¸ì ìì¡´ëê° ëì ê³ì¸µ. ì
ë ¥/ì¶ë ¥ê³¼ ë°ì í´ìì¼ë©°, ê°ì¥ ì ìì¤ì´ë¼ê³ ë³¼ ì ìë¤.\u003cbr/\u003e\n`Next.js`ì 기본 ì¤ì ê°ì¸ íì¼ ìì¤í
기ë°ì¼ë¡ ë¼ì°í
ì²ë¦¬ë¥¼ íë©°, **Components**ì **Lib** ê³ì¸µì ì½ëë¤ì 참조íì¬ êµ¬ì±í ì ìë¤.\n\n```tsx\n- src\n - pages\n - api\n - order\n - [...slug].tsx // src/lib/order/.. 참조\n - ...\n - order\n - [id].tsx // src/components/order/.. 참조\n - _middleware.tsx // src/lib/order/.. 참조\n - ...\n```\n\n### Dependency diagram\n\nìì 구조ì ê·ì¹ì ê°ì§ê³ ê°ëµí ìì¡´ì± ê·¸ëíë¡ íííë©´ ìëì ê°ì 모ìì´ ë ê²ì´ë¤.\n\n\n\nìì¡´ì±ì 모ë ë¨ë°©í¥ì¼ë¡ë§ íë¬ê°ê³ , ìì¼ë¡ 참조í´ìë ì ëë¤.\u003cbr/\u003e\n\nì를 ë¤ì´, core ê³ì¸µì API íµì ì ìí 구íì²´ê° ìë¤ê³ ê°ì í´ ë³´ì.\u003cbr/\u003e\nì´ êµ¬íì²´ë UIì íí í¹ì ìí, ì¸ë¶ì ì¸ ëë©ì¸ ë¡ì§ë¥¼ ìììë ìëë©°, ììë ì¢ì ê² ìë¤.\u003cbr/\u003e\në§ì°¬ê°ì§ë¡ ëë©ì¸ì ì¢
ìì ì¸ ì½ëë¤ ëí, ì´ êµ¬íì²´ê° ë¹ë기 íµì ì ìíì¬ ì´ë¤ ê°ì²´ë¥¼ ì¬ì©íì¬ êµ¬íì´ ëìëì§, ì´ë»ê² API ìë²ì íµì ì íëì§ ì í ì íìê° ìë¤.\u003cbr/\u003e\n\nì´ë¬í **ê´ì¬ì¬ì ë¶ë¦¬ë¡ ì¸í´ ê° ëª¨ëì ì¬ë¬ ì±
ì
16ìì ë²ì´ë기 ì½ê³ , í
ì¤í¸í기ë ë ì¬ìì§ë©°, ì ì§ ë³´ì ë¹ì©ë ì¤ì´ë¤ ê²**ì´ë¤.\n\n## ESLint íë¬ê·¸ì¸ íì©\n\nìì ìê°íë ìí¤í
ì²ì ê³ì¸µê³¼ ê²½ê³ë¥¼ í¨ê³¼ì ì¼ë¡ ë¤ë£¨ê¸° ìí´ ESLint를 íì©íê³ , ì´ê²ì´ ê°ë° 주기ì ìì°ì¤ë ë
¹ìë¤ ì ìê² í´ë³´ì.\nESLint 기본 ê·ì¹ìë 참조를 ì íí ì ìë `no-restricted-imports`ê° ìì§ë§ ì´ê²ì¼ë¡ë ìì ìì¡´ì± ê·ì¹ì í´ê²°í ìë ìë¤.\u003cbr/\u003e\n\në°ë¼ì, `eslint-plugin-import`ë¼ë íë¬ê·¸ì¸ì ì¬ì©íì¬ **ê³ì¸µ ê°ì ìì¡´ì± ì ì´**를 ë¤ë¤ë³´ê³ ,\u003cbr/\u003e\nì¶ê°ì ì¼ë¡ **ì¸ë¶ 모ëì ìì¡´ì± ì ì´**ë ê°ì´ ë¤ë¤ë³´ëë¡ íê² ë¤.\n\n### ìê°\n\n[eslint-plugin-import](https://github.com/import-js/eslint-plugin-import)ë [creact-react-app](https://www.npmjs.com/package/eslint-config-react-app)ê³¼ [next.js](https://www.npmjs.com/package/next)ììë ì¬ì©íê³ ìë íë¬ê·¸ì¸ì´ë©°,\u003cbr/\u003e\nì´ê²ì¼ë¡ ESLintì import ê´ë ¨í 기본 ê·ì¹ë¤ë³´ë¤ ì¡°ê¸ ë íì¥ë 기ë¥ë¤ë¡ 린í
ì í ì ìë¤.\u003cbr/\u003e\níë¬ê·¸ì¸ íìì ì¬ë¬ ë£°ì´ ìì§ë§, ì´ ê¸ììë [no-restricted-paths](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-restricted-paths.md)ë§ ë¤ë£¨ëë¡ íê² ë¤.\n\n### ê³ì¸µ ê° ìì¡´ì± ì ì´\n\nìì ìì¡´ì± ê·ì¹ì ë¦°í¸ ë£°ë¡ íííë©´ ìëì ê°ë¤.\n\n```jsx\n\"rules\": {\n \"import/no-restricted-paths\": [\n \"error\",\n {\n \"zones\": [\n {\n \"target\": \"src/core\",\n \"from\": \"src/components\"\n },\n {\n \"target\": \"src/core\",\n \"from\": \"src/lib\"\n },\n {\n \"target\": \"src/core\",\n \"from\": \"src/pages\"\n },\n {\n \"target\": \"src/lib\",\n \"from\": \"src/pages\"\n },\n {\n \"target\": \"src/components\",\n \"from\": \"src/pages\"\n }\n ]\n }\n ]\n },\n \"settings\": {\n \"import/resolver\": {\n \"typescript\": {\n \"project\": \".\"\n }\n }\n }\n```\n\níì
ì¤í¬ë¦½í¸ë¥¼ ì¬ì©íë íë¡ì í¸ë¼ë©´ ìë [import/resolver](https://github.com/import-js/eslint-plugin-import#typescript)ì ì¤ì ì´ ì¶ê°ë¡ íìíë¤.\n\n### ì¤ë¥ íë©´\n\n룰ì ì§í¤ì§ ììì ê²½ì° IDEìì ìëì ê°ì 모ìµë¤ì ë³¼ ì ìë¤.\u003cbr/\u003e\nëí, ì ë ê²½ë¡, ìë ê²½ë¡, ë³ì¹ ê²½ë¡ ë± ëª¨ë ì¸ìì´ ê°ë¥íë¤.\n\n\u003cbr/\u003e\n\n\nì½ë í¸ì§ê¸°ìì ë³´ì¬ì£¼ë ì¤ë¥ë¥¼ ìì íë©´ì¼ë¡ ë¤ìì§ë§, ë¹ì°íê²ë ë¦°í¸ ëª
ë ¹ì´ë¡ë ê·ì¹ì ëí ê²ì¦ì í ì ìë¤.\n\n### ì¤ë¥ ë©ìì§ ì¶ê°\n\në¦°í¸ ê·ì¹ì ìëì ê°ì ë©ìì§ë¥¼ ì¶ê°íì¬ ëë£ìê² ì¡°ê¸ ë ê°ë° ì¹íì ì¸ ì¤ë¥ë¥¼ ìë´í´ ì¤ ìë ìë¤.\n\n```rust\n\"rules\": {\n \"import/no-restricted-paths\": [\n \"error\",\n {\n \"zones\": [\n ....\n {\n \"target\": \"src/core\",\n \"from\": \"src/lib\",\n\t\t\t\t\t\t\"message\": \"\\nìì¡´ì± ê·ì¹ì ì´ê¸ëë 참조ì
ëë¤.\"\n },\n ....\n ]\n }\n ]\n },\n```\n\n\n\n### ì¸ë¶ 모ë ìì¡´ì± ì ì´\n\nìì ì¤ëª
í ê²ì²ë¼, core ê³ì¸µì API íµì ì ìí 구íì²´ê° ìì¼ë©° `axios`를 ì¬ì©íë¤ê³ ê°ì í ë¤, ìëì ìì¹ì ë°íì¼ë¡ ë¦°í¸ ê·ì¹ ì¤ì ì í´ ë³´ì.\n\n1. `axios`ë core ê³ì¸µì í¹ì í API 모ë 구íì²´ììë§ ì¡´ì¬ë¥¼ ìê³ ìë¤.\n2. í¹ì 구íì²´ë ì¶ìíë ì¸í°íì´ì¤ë¥¼ 구ííê³ ì´ë¥¼ ë¤ë¥¸ 모ëë¤ì´ ì¬ì©í ì ìê² íë¤.\n3. ë¤ë¥¸ 모ëë¤ì `axios`를 ìì§ë 못íê³ ì°¸ì¡°í ì ìì¼ë©°, ì¤ì§ í¹ì 구íì²´ê° ì ê³µíë ì¸í°íì´ì¤ë§ ì ììë¤.\n\n```tsx\n\"rules\": {\n\t\"no-restricted-imports\": [\n\t\t\"error\",\n\t\t{\n\t \"paths\": [{\n\t \"name\": \"axios\",\n\t\t \"message\"
16: \"\\naxiosë @core/utils/ApiUtil.tsììë§ ì°¸ì¡°ê° ê°ë¥í©ëë¤.\"\n\t\t\t}]\n\t\t}\n\t],\n\t\"import/no-restricted-paths\": [\n\t\t\"error\",\n\t\t{\n\t \"zones\": [\n\t\t\t\t....\n\t\t\t]\n\t\t}\n\t],\n\n\t....\n\n\"overrides\": [\n\t{\n\t\t\"files\": [\"src/core/utils/ApiUtil.ts\"],\n\t\t\"rules\": {\n\t\t\t\"no-restricted-imports\": \"off\"\n\t\t}\n\t}\n],\n\n....\n```\n\n### ì¤ë¥ íë©´ê³¼ ì¶ê°ë ë©ìì§\n\ní¹ì 구íì²´ ì¸ìì axios 참조 ì ìëì ê°ì ì¤ë¥ê° ë°ìíë¤.\u003cbr/\u003e\nëí, ì¹íì ì¸ ì¤ë¥ ë©ìì§ë¥¼ ì¶ê°í ì ìë¤.\n\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n\nììì ê°ì´ ì¸ë¶ 모ëì ìì¡´ì±ì ì ì´íê³ ì½ë를 ì ì§í´ ëê° ì ìë¤ë©´,\u003cbr/\u003e\nì¸ë¶ 모ëì ë²ì ë ëì, 모ë êµì²´ì ê°ì ë³íê° ì길 ì **ìµìì ë
¸ë ¥ì¼ë¡ ìµëì í¨ì¨**ì ë¼ ì ìì ê²ì´ë¤.\n\n## ë§ì¹ë©°\n\n모ë 문ì í´ê²°ì ëí ì ëµì´ ì í´ì ¸ìì§ ìì ê²ì²ë¼, ìí¤í
ì²ì ê´í ì ê·¼ë ë§ì°¬ê°ì§ì´ë¤.\u003cbr/\u003e\n**ì´ ê¸ìì ë§íë ë´ì©ì 모ë í경과 ìí©ì ë§ì¡±ìí¤ë ì ëµì´ ìëë¤.**\u003cbr/\u003e\n\níì§ë§, ìëì ê°ì ìí©ì ëì¬ìë¤ë©´ íë² ì¦ìì ê³ ë ¤í´ ë³¼ ë§í ë´ì©ì´ ë ì ìì ê² ê°ë¤.\n\n- _ë¨ì¼ ìì¤ ìì¤ì 모ë
¸ë¦¬ì¤ ìí¤í
ì²ë¡ íë¡ì í¸ê° ê´ë¦¬ëê³ ìì ê²½ì°._\n- _ìí°íë¼ì´ì¦ê¸ í¹ì ì´ë ì ë ê·ëª¨ ìë ì¹ ì í리ì¼ì´ì
._\n- _í
ì¤í¸í기 ì¬ì´ ì í리ì¼ì´ì
ì ë§ë¤ê³ ì¶ì ê²½ì°._\n- _ê³ì¸µ ê°ì ìì¡´ì± ê·ì¹ì ê°ë°ì£¼ê¸°ì ìì°ì¤ë í¬í¨ìí¤ê³ ì¶ì ê²½ì°._\n\në, **ì´ ê¸ì ë´ì©ì íµí´ ê³ì¸µ ê°ì ê²½ê³ë ëª
íí´ì¡ì§ë§, ì´ ì¸ìë ì ê²½ ì¨ì¼ í ê²ì´ ë§ë¤.**\u003cbr/\u003e\n**ëë©ì¸ ê°ì ê²½ê³ë¥¼ ì´ë»ê² ë¤ë¤ì¼ í ì§, ì´ë¤ ì¸ë¶ 모ëì ì¶ìíìí¤ê³ 기ì¤ì ì´ë»ê² ì¸ì¸ ê²ì¸ì§, í
ì¤í¸ ê²½ê³ë ì´ë»ê² ë¤ë£°ì§ ë±.**\u003cbr/\u003e\nê¸ì ì 목ìì ë³¼ ì ìë¯ì´, ì¬ê¸°ìë ë¨ì§ **첫걸ì**ì ë´ëìì ë¿ì´ë¤.\u003cbr/\u003e\n\nì¤ìí ì¬ì¤ì **ìí¤í
ì²ë ì§ìì ì¼ë¡ ìí©ì ë§ê² ì±ì¥í´ì¼ íë©°, ì´ë¥¼ ìí´ ê°ë°ìë¤ì ë¶ë¨í ë
¸ë ¥ì´ íìíë¤ë ê²ì´ë¤.**\n\n## ì°¸ê³ \n\n- [http://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html](http://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)\n- [https://github.com/vercel/next.js/tree/canary/examples](https://github.com/vercel/next.js/tree/canary/examples)\n- [https://eslint.org/docs/rules/no-restricted-imports](https://eslint.org/docs/rules/no-restricted-imports)\n- [https://github.com/import-js/eslint-plugin-import](https://github.com/import-js/eslint-plugin-import)\n- [https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-restricted-paths.md](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-restricted-paths.md)\n- [https://github.com/import-js/eslint-plugin-import#typescript](https://github.com/import-js/eslint-plugin-import#typescript)\n- [https://www.npmjs.com/package/eslint-config-react-app](https://www.npmjs.com/package/eslint-config-react-app)\n- [https://www.npmjs.com/package/next](https://www.npmjs.com/package/next)\n","data":{"id":"clean frontend architecture","title":"í´ë¦°í íë¡ í¸ìë ìí¤í
ì²ë¥¼ í¥í 첫 걸ì","description":"í´ë¦°í íë¡ í¸ìë ìí¤í
ì²ë¥¼ í¥í 첫 걸ì","preview":"ë³ê²½ì ì ì°í íë¡ í¸ìë ìí¤í
ì²ë¥¼ 구ì±íë íëì ë°©ë²ê³¼ ë°©ë²ì 근거, ê·¸ë¦¬ê³ ì´ë¥¼ ì ì´í´ ì¤ ì ìë ESLintì ê·ì¹ê¹ì§ ìê°íê³ ì í©ëë¤.","keywords":"react, next, create-react-app, clean architecture, architecture","slug":"clean-frontend-architecture","createdAt":"2022.05.19","published":true},"filePath":"clean-frontend-architecture.mdx"},{"content":"\nìë°ì¤í¬ë¦½í¸ë **ëì¨í íì
(loosely typed)ì ëì (dynamic) ì¸ì´**
16ì´ë¤.\u003cbr/\u003e\nì¸ì´ìì ì¬ì©í ì ìë ë°ì´í° íì
ì ì¢
ë¥ì ëªê°ì§ í¹ì§ë¤ì ììë³´ì.\n\n## ë°ì´í° íì
ì¢
ë¥\n\nìë°ì¤í¬ë¦½í¸ì ë°ì´í° íì
ì í¬ê² 2ê°ì§ë¡ ëë ì ìë¤.\n\n- **ììí íì
(Primitive type)**\n- **참조í íì
(Reference type)**\n\nìì 2ê°ì§ë¥¼ ëëë 기ì¤ì **í ë¹ì´ë ì°ì°ì ê°ì ë³µì íë í¹ì 참조íë**ë¼ê³ ë³¼ ì ìê² ë¤.\u003cbr/\u003e\nì격íê² ë§íë©´ ì¬ì¤ ë ë¤ ë³µì 를 íì§ë§, ë³µì 를 íë ëìì´ ë¤ë¥´ë¤.\u003cbr/\u003e\nì´ë ìëìì ì¡°ê¸ì© ë ë¤ë¤ë³´ëë¡ íê² ë¤.\n\n### ììí\n\nììíì¼ë¡ ë¤ë¤ì§ë íì
ë¤ì ìëì ê°ë¤.\u003cbr/\u003e\n`Number`, `String`, `Boolean`, `null`, `undefined`, `Symbol`, `BigInt`\u003cbr/\u003e\nì´ë¤ì ì¼ë°ì ì¼ë¡ **ë¶ë³ì±**ì ê°ì§ë ë°ì´í° íì
ì´ë¼ê³ ííëë¤.\u003cbr/\u003e\n\nììí íì
ì ëª ê°ì§ì í¹ì§ì ì´í´ë³´ì.\n\n#### í¹ì§\n\n- ê° ìì²´ë **ë¶ë³**íë©° ë³íì´ ë¶ê°ë¥ íë¤.\n- ê°ì ê³ ì ë í¬ê¸°ë¡ ë©ëª¨ë¦¬ì ì ì¥ëë¤. (ex) ì«ìì ê²½ì° 64ë¹í¸)\n- ê°ì ê°ì ì¬ì©íë¤ë©´ íëì ë©ëª¨ë¦¬ë¥¼ ì¬ì©íë¤.\n\n#### ììí íì
ê³¼ ë©ëª¨ë¦¬\n\nììí íì
ë³ìì í ë¹ê³¼ ì°ì°ì, ë©ëª¨ë¦¬ì ë³í를 íì
í´ë³´ì.\n\n```js\nlet name = 'ê¹ëí'; // ë³ì ì ì¸ê³¼ ê° í ë¹\nname = 'kimcoder'; // ë³ì ê° ì¬í ë¹\n```\n\nìì ì½ëìì `name`ì´ë¼ë ë³ì ì ì¸ììë ë©ëª¨ë¦¬ìì 2ê°ì 주ì를 í ë¹íë¤.\u003cbr/\u003e\níëë **ë³ì ìë³ì(ë³ìëª
)**ì ìí ê²ì´ê³ , íëë **ë³ì ê°(ë°ì´í°)**를 ìí ê²ì´ë¤.\n\n\u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ë³ì ìì\n \u003c/th\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1002\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1003\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1004\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦ : name\n \u003cbr /\u003e ê°: @5003\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ë°ì´í° ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300 '\u003e5004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e'ê¹ëí'\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n\u003c/table\u003e\n\n1003ì ìë³ìë `name`ì´ê³ , ë°ì´í°ë `ê¹ëí`ì´ë¼ë ê°ì ë©ëª¨ë¦¬ ì 주ì(`@5003`)ì´ë¤.\u003cbr/\u003e\u003cbr/\u003e\nì´ì , ë³ì ê°ì `kimcoder`ë¡ ì¬í ë¹ì ë³í를 íì¸í´ ë³´ì.\n\n\u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}
16\u003e\n ë³ì ìì\n \u003c/th\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1002\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1003\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1004\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300 bg-yellow-50'\u003e\n ì´ë¦ : name\n \u003cbr /\u003e ê°: @5004\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ë°ì´í° ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300 bg-yellow-50'\u003e5004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e'ê¹ëí'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300 bg-yellow-50'\u003e'kimcoder'\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n\u003c/table\u003e\n\n`console.log(name)`ì¼ë¡ íì¸í´ë³´ë©´ `kimcoder`ê° ì¶ë ¥ëë¯ë¡ ìëíëë¡ ë³ì ê°ì ë³íê° ëìë¤ê³ ë³´ì¸ë¤!\u003cbr/\u003e\níì§ë§ ì¤ì `@5003`ì ì ì¥ë 문ìì´ ê°ì ë³íë ì¼ì´ëì§ ììë¤. ë¨ì§ ë³ì `name`ì ê°(ë©ëª¨ë¦¬ 주ì)ì´ `@5003` ìì `@5004`ì¼ë¡ ë³í ê²ì´ë¤.\n`name`ì, `kimcoder`ë¼ë ê°ì í ë¹í기 ì ì ì´ë¯¸ `kimcoder`ë¼ë ê°ì ì¬ì©íì¬ì ë©ëª¨ë¦¬ì ì ì¥ì´ ëì´ìë ìí©ì´ë¼ë©´ ê·¸ 주ìë¡ ë³íê² ëë¤.\n\në§ì½, `ê¹ëí`ì´ë ê°ì ë ì´ì ì¬ì©íì§ ìê²ëë©´, ê°ë°ì§ ì½ë ì
ì ëìì´ ëë¤.\n\n### 참조í\n\n참조íì í¬ê´ì ì¼ë¡ ë³´ìë©´ 모ë `Object`ë¼ê³ ë³¼ ì ìëë°,\u003cbr/\u003e\nì¬ê¸°ìë `Array`, `Function`, `Date`, `RegExp`, `Map`, `WeakMap`, `Set`, `WeakSet` ë±ì´ ìë¤.\u003cbr/\u003e\nììíì´ ìë íì
ë¤ì 모ë 참조íì´ë¼ê³ ìê°íì¬ë ì¢ë¤.\u003cbr/\u003e\n\n#### í¹ì§\n\n- 참조í(ê°ì²´)ë í¤ì ê°ì¼ë¡ 구ì±ë íë¡í¼í°ë¤ì ì§í©ì´ë¤.\n - íë¡í¼í° ê°ì¼ë¡ë ìë°ì¤í¬ë¦½í¸ì 모ë ê°ì ì¬ì©í ì ìë¤.\n- ë³ìì ê°ì í ë¹í ë, ê°ì´ ìë ë°ì´í° ê°ì²´ì 주ì를 ì ì¥íë¤.\n- ê³ ì ë í¬ê¸°ì ë©ëª¨ë¦¬ë¥¼ ì¬ì©íì§ ìëë¤.\n\n#### 참조í íì
ë³ìì ë©ëª¨ë¦¬ 구조\n\n참조íë ë°ì´í°ë¥¼ ë³ìì í ë¹íë ê³¼ì ì´ ë©ëª¨ë¦¬ììì ì´ë»ê² ì²ë¦¬ëëì§ íì¸í´ë³´ì.\n\n```js\nlet data = {\n name: 'kimcoder',\n nation: 'korea',\n};\n```\n\n\u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}
16\u003e\n ë³ì ìì\n \u003c/th\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1002\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1003\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1004\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1005\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦ : data\n \u003cbr /\u003e ê°: @5002\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ë°ì´í° ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5005\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e@7002 ~ ?\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e'kimcoder'\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e'korea'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ê°ì²´ @5002ì ë³ì ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7005\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦: name\n \u003cbr /\u003e\n ê°: @5004\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦: nation\n \u003cbr /\u003e\n ê°: @5005\n \u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n\u003c/table\u003e\n\nììí ë°ì´í°ìì ì°¨ì´ë `ê°ì²´ì ë³ì(íë¡í¼í°) ìì`ì´ ë³ëë¡ ì¡´ì¬íë¤ë ê²ì´ë¤. ê°ì²´ê° ë³ëë¡ í ì í ììì ë³ì ììì¼ ë¿ `ë°ì´í° ìì`ì 기존ì ë©ëª¨ë¦¬ ê³µê°ì ê·¸ëë¡ íì© íê³ ìë¤.\nëí, ë°ì´í° ììì ì ì¥ë ê°ì 모ë ë¶ë³ê°ì´ë¤(=ììí).\u003cbr/\u003e\nê·¸ë¬ë ë³ììë ë¤ë¥¸ ê°ì ì
16¼ë§ë ì§ ëì
í ì ìì¼ë©°, ì´ë¬í ì±ì§ ë문ì íí 참조íì ë¶ë³íì§ ìë¤ë¼ê³ íííë ê²ì´ë¤.\n\nê°ì²´ ë´ ììì ê° ë³ê²½ì ì´ë¤ ë³íê° ì¼ì´ëëì§ë íì¸í´ ë³´ì.\n\n```js\nlet data = {\n name: 'kimcoder',\n nation: 'korea',\n};\n\ndata.name = 'ê¹ëí';\n```\n\n\u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ë³ì ìì\n \u003c/th\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1002\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1003\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1004\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1005\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦ : data\n \u003cbr /\u003e ê°: @5002\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ë°ì´í° ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300 bg-yellow-50'\u003e5003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5005\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e@7002 ~ ?\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300 bg-yellow-50'\u003e'ê¹ëí'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e'kimcoder'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e'korea'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ê°ì²´ @5002ì ë³ì ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7005\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300 bg-yellow-50'\u003e\n ì´ë¦: name\n \u003cbr /\u003e\n ê°: @5003\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦: nation\n \u003cbr /\u003e\n ê°: @5005\n \u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n\u003c/table\u003e\n\në³íë ììì ì´í´ë³´ì. ë³ì `data`ê° ë°ë¼ë³´ê³ ìë 주ìë `@5002`ë¡ ë³íì§ ììë¤. ë¤ë§, ê°ì²´ ë´ë¶ ììì ê°ë§ ë³ê²½ì´ ëìë¤.\u003cbr/\u003e\n**ê°ì²´ ë´ë¶ì ììë ì¶ê° ë° ìì , ìì ì´ ê°ë¥í기 ë문ì 참조í íì
ì ê°ë³ê°ì´ë¼ê³ íí**íë¤.\n\n#### 참조í ê°ì²´ ë³µì¬\n\n```js\nlet otherData = data;\n```\n\nìì ê°ì ì½ëê° ìë¤ê³ ìê°í´ë³´ì\n\n\u003ctable\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}
16\u003e\n ë³ì ìì\n \u003c/th\u003e\n \u003cth className='w-28 p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1002\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1003\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1004\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e1005\u003c/td\u003e\n \u003ctd className='w-28 p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦ : data\n \u003cbr /\u003e ê°: @5002\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300 bg-yellow-50'\u003e\n ì´ë¦ : otherData\n \u003cbr /\u003e ê°: @5002\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ë°ì´í° ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e5005\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e@7002 ~ ?\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e'ê¹ëí'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e'kimcoder'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e'korea'\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 text-center border border-gray-500 bg-gray-300' rowSpan={2}\u003e\n ê°ì²´ @5002ì ë³ì ìì\n \u003c/th\u003e\n \u003cth className='p-1.5 text-center border border-gray-300 bg-gray-100'\u003e주ì\u003c/th\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7002\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7003\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7004\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e7005\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e...\u003c/td\u003e\n \u003c/tr\u003e\n \u003ctr\u003e\n \u003cth className='p-1.5 border border-gray-300 bg-gray-100'\u003eë°ì´í°\u003c/th\u003e\n \u003ctd className='p-1.5 border border-gray-300 '\u003e\n ì´ë¦: name\n \u003cbr /\u003e\n ê°: @5003\n \u003c/td\u003e\n \u003ctd className='p-1.5 border border-gray-300'\u003e\n ì´ë¦: nation\n \u003cbr /\u003e\n ê°: @5005\n \u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003ctd className='p-1.5 text-center border border-gray-300'\u003e\u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n\u003c/table\u003e\n\n`otherData`를 ìí´ ë³ì ììì ì¶ê°ë¡ ê³µê°ì´ í ë¹ëìê³ , ë°ì´í°ë ê·¸ëë¡ `@5002 ê°ì²´`를 ë°ë¼ë³´ê³ ìë¤.\u003cbr/\u003e\në°ë¼ì ì본 `data`ì `name` ìì± ê°ì ë³ê²½íë©´ `otherData`ì `name` ìì± ê°ë ê°ì´ ë³íê² ëë¤.\n\nìì ê°ì ì±ì§ë¡ ì¸í´ 참조í ë°ì´í°ë¥¼ ì¬ì©í ë, ë¶ë³ì±ì ì ì§íê³ ì ì¶ê°ì ì¸ ì²ë¦¬ë¥¼ í´ì£¼ë ê²ì´ë¤.\n\n\u003e ëíì ì¸ ììì ìí©ì¼ë¡ í¨ì ì¸ìë¡ ì ë¬íê³ ì°¸ì¡°ì, ì본 ë°ì´í°ì ê° ë³ê²½ì ë§ê¸° ìí´ ì¶ê° ì²ë¦¬ë¥¼ íë¤.\n\n```js\nlet data = {\n name: 'kimcoder',\n};\n\ndata = {\n age: '12',\n};\n```\n\nìì ê°ì´ ê°ì²´ì íë¡í¼í°ê° ë³ê²½ëë ê²ì´ ìëë¼ ë³ìì ë°ì´í° ìì²´ê° ë³ê²½ëë ê²½ì°ìë í´ë¹ëì§ ìëë¤.\n\n## ë§ì¹ë©°\n\n**ììí íì
ì ê°ì ë³ê²½í ë ê° ìì²´ê° ë³ê²½ëëê² ìë ë³ìììì ë©ëª¨ë¦¬ê° ë³ê²½ëë ê²**ì´ë¤.\u003cbr/\u003e\n**참조í íì
**ì ììí íì
ê³¼ ë¬ë¦¬ ë³ìì **ë°ì´í°ê° íë¡í¼í°ì ì§í©ì¼ë¡ 구ì±**ëì´ ìë¤.\u003cbr/\u003e\në´ë¶ íë¡í¼í°ì ê°ì ë³ê²½ì´ ì¼ì´ë ë°ì´í° ê°ì²´ë ë³ê²½ëì§ ìì ìíë¡ ë´ë¶ íë¡í¼í°ë§ ë³ê²½ëë¤.\u003cbr/\u003e\nì¬ì©í ëë ë³ëì ë¶ë³ì± ì²ë¦¬ë¥¼ ìí ì½ë를 ìì±í´ì¼ íë ê²ì´ ì¢ë¤.\u003cbr/\u003e\n\n## References\n\n- https://developer.mozilla.org/ko/docs/Web/JavaScript/Data_structures\n","data":{"id":"ìë°ì¤í¬ë¦½í¸ì ë°ì´í° íì
ê³¼ ë©ëª¨ë¦¬","title":"ìë°ì¤í¬ë¦½í¸ì ë°ì´í° íì
ê³¼ ë©ëª¨ë¦¬","description":"ìë°ì¤í¬ë¦½í¸ìì ì¬ì©í ì ìë ë°ì´í° íì
ì ì¢
ë¥ì ëªê°ì§ í¹ì§ë¤ì ììë´
ëë¤.","preview":"ìë°ì¤í¬ë¦½í¸ìì ì¬ì©í ì ìë ë°ì´í° íì
ì ì¢
ë¥ì ëªê°ì§ í¹ì§ë¤ì ììë´
ëë¤.","keywords":"javascript, data type, primitive type, reference type, memory","slug":"javascript-data-types","createdAt":"2022.02.19","published":true},"filePath":"javascript-data-types.mdx"},{"content":"\nìë°ì¤í¬ë¦½í¸ ê°ë°ì íë ë§ì ì¡°ì§ê³¼ íë¤ì´ ì½ë ì ì ë¶ì ëêµ¬ë¡ `eslint`를 ì¬ì© ì¤ì ìì ê²ì´ë¤.\u003cbr/\u003e\nëí, ì¬ë¬ ì½ë 컨벤ì
ì ë§ë¤ê³ ì´ë¥¼ ì¤ìíê³ ì ë§ì ë
¸ë ¥ë¤ì íê³ ììê±°ë¼ê³ ìê°íë¤.\u003cbr/\u003e\nì½ë ì ì ë¶ìì´ CI/CD ë¨ê³ì ìëíëì´ ìì°ì¤ë½ê² ë
¹ììì¼ë©´ ëí ëì ìì´ ì¢ì ê²ì´ë¤.\u003cbr/\u003e\nì¬ë¬ 컨벤ì
ì¤ììë **`import`구문ì ì ë ¬** ê·ì¹ ì ì©ì ì´ì ì ëí´ ìê°í´ë³´ê³ ì íë¤.\n\n## import rule?\n\n`import` 구문ì **ì ë ¬ ê·ì¹**ì ëí ì¡°ê±´ë¤ì ìë ë´ì©ë¤ì ì ì´íë¤.\n\n- ìí¬í¸ 구문ë¤ì ëí´ ìì ì ì©ì í ê²ì´ë.\n- ìí¬í¸ 구문ì ë©¤ë² ë³ìë¤ì ëí´ ìì ì ì©ì í ê²ì´ë.\n- ìí¬í¸ 구문 그룹ì ëí ììì ì´ë¥¼ 공백ì íµí´ ë¶ë¦¬í ê²ì´ë.\n - 그룹íì ì¤ì ì `eslint`ì 기본 ê·ì¹, íë¬ê·¸ì¸ë§ë¤ ë¤ë¥´ë¤.\
16n\nì¬ê¸°ì ììë `alphabetize` ëë ê²ì ë§íë©°, [eslintì 기본 ê·ì¹ì¸ sort-imports](https://eslint.org/docs/rules/sort-imports) ì¸ì ì ë ¬ì ê´ë ¨ë ì¬ë¬ íë¬ê·¸ì¸ë¤ì ì ì´ ì¡°ê±´ë¤ë ì ì¬íë¤.\n\n## 컨벤ì
ê³¼ ì ì©\n\níë´ì ìëì ê°ì 컨벤ì
ì´ ìë¤ê³ ê°ì í´ ë³´ì.\n\n### 컨벤ì
\n\n| ì°ì ìì | ìí¬í¸ 그룹 | ë¹ê³ |\n| -------- | --------------------------------------------- | ------------------------------------------------------------- |\n| 1 | react, next.jsì ê°ì ë©ì¸ íë ììí¬ ëª¨ë | react-routerì ê°ì reactì ìì¡´ì´ ìë ì¸ë¶ 모ëë í¬í¨íë¤. |\n| 2 | node_modulesì ìë ì¸ë¶ 모ë | |\n| 3 | node_modulesì ìì§ë§ íìì ê°ë°í ì¸ë¶ 모ë | ex) ëìì¸ìì¤í
, íë«í¼ ê´ë ¨ 모ë |\n| 4 | ì ë ê²½ë¡ë¡ ìí¬í¸í íë¡ì í¸ ë´ ëª¨ë | |\n| 5 | ìë ê²½ë¡ë¡ ìí¬í¸í íë¡ì í¸ ë´ ëª¨ë | ex) ì´ë¯¸ì§, CSS |\n\n- ìì ê°ì´ ìí¬í¸ 구문ë¤ì 그룹ííê³ ì°ì ììëë¡ ì ë ¬íë¤.\n- ê° ê·¸ë£¹ ì¬ì´ìë ê°í 문ì를 ë£ëë¤.\u003cbr/\u003e\n\nì½ëë¡ ííë 모ìµì ìëì ê°ì ê²ì´ë¤.\n\n```js\nimport { useEffect } from 'react';\nimport { Link } from 'react-router-dom';\n\nimport A from 'moduleA';\nimport B from 'moduleB';\n\nimport { Button, ButtonProps } from '@MyDesignSystem/Button';\n\nimport Thumbnail from 'src/components/Thumbnail';\n\nimport image from './a.png';\nimport style from './style.module.css';\n```\n\nìì ê°ì 컨벤ì
ì 그룹í를 커ì¤í°ë§ì´ì¦í ì ìë íë¬ê·¸ì¸ì ì¶ê°ë¡ ì¤ì¹í´ì¼ íë¤.\u003cbr/\u003e\nì´ ê¸ììë [eslint-plugin-import](https://www.npmjs.com/package/eslint-plugin-import)를 ììë¡ íê² ë¤.\n\n### ì ì©\n\nìëì ê°ì´ `import` 컨벤ì
ì ëí ë´ì©ì `eslint` ì¤ì ì ì¶ê°íë¤.\u003cbr/\u003e\nì¤ì ì ëí ìì¸í ë´ì©ì [import/orderì 문ì](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md)ìì 참조í ì ìë¤.\n\n```js title=\".eslintrc\"\n{\n // ...\n \"plugins\": [ /*... ,*/ \"import\"],\n \"rules\": {\n \"sort-imports\": [\n \"error\",\n {\n \"ignoreCase\": true,\n \"ignoreDeclarationSort\": true,\n \"ignoreMemberSort\": false,\n \"allowSeparatedGroups\": true\n }\n ],\n \"import/order\": [\n \"error\",\n {\n \"newlines-between\": \"always\",\n \"groups\": [[\"builtin\", \"external\"], \"internal\", \"parent\", \"sibling\", \"index\"],\n \"pathGroups\": [\n {\n \"pattern\": \"next\",\n \"group\": \"builtin\"\n },\n {\n \"pattern\": \"react\",\n \"group\": \"builtin\"\n },\n {\n \"pattern\": \"@MyDesignSystem/**\",\n \"group\": \"internal\"\n },\n {\n \"pattern\": \"src/**\",\n \"group\": \"internal\"\n },\n ],\n \"pathGroupsExcludedImportTypes\": [\"src/**\", \"@MyDesignSystem/**\"],\n \"alphabetize\": {\n \"order\": \"asc\",\n \"caseInsensitive\": true\n }\n }\n ]\n }\n}\n```\n\n### ì ì©ì ì´ì \n\níìê° ìê°íë 컨벤ì
ì ì©ì ì´ì ì **ì½ë 리뷰ì diffê° ë°ìíì§ ìëë¤**ë ì ì´ë¤.\u003cbr/\u003e\në¬¼ë¡ , `import 구문`ì´ ì ë§ë¡ ë³ê²½ë ê²ì´ë¼ë©´ í©ë¹í diffê° ë°ìíë ê²ì´ ë§ê² ì§ë§,\u003cbr/\u003e\nì¬ë¬ëª
ê³¼ íì
íë ê²½ì°ìë ê°ì¸ë§ë¤ ì¬ì©íë IDEë ë¤ë¥´ê³ , ì¤ì ê°ë¤ì´ ë¤ ë¤ë¥¼ ì ìë¤.\u003cbr/\u003e\n**ì´ë¡ì¸í´ ì½ë리뷰ì ìëì¹ ìì diff를 ë³´ì¬ì£¼ê³ ë ë´ì¼í ì ìë ìí©ì´ ë°ìí ì ìë¤.**\u003cbr/\u003e\n\nìë ì½ë리뷰 ì´ë¯¸ì§ë¥¼ íì¸í´ë³´ì.\n\n\u003cimg src='/assets/images/eslint-import-example.png' alt='컨벤ì
ë£°ì´ ì ì© ì ë ì½ë 리뷰 ìì ' /\u003e\n\u003cbr /\u003e\nê°ë°ì Aê° ìëì ê°ì ììë¡ ìì
ì íìë¤ê³ ê°ì í´ ë³´ì.\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n1. ì»¤ë° 1ìì `useCallback`ì ì¬ì©ì íì§ ìê² ëì´, í´ë¹ import member ìì .\n2. ì»¤ë° 3ìì ë¤ì `useCallback`를 ì¬ì©íê² ë¨.\n3. ì ë ¬ëì§ ìì ì± import memberê° ì¶ê° ë¨.\n4. importí 멤ë²ë¤ì ë³í¨ì´ ìë ìíì´ì§ë§ ì ë ¬ì´ ë°ëìë¤ë ì´ì ë¡ **ë¶íìí diff ë°ì**.\n5. ( ImagePreLoaderë ë¹ì·í ë§¥ë½ìì ììê° ë³ê²½ ë¨. )\n\n\u003cbr /\u003e\nìì를 ìí´ ê·¹ë¨ì ì¸ ìí©ì ë§ë ê²ì¼ë¡ ë³´ì¼ ìë ìì¼ë,\n\u003cbr /\u003e\në¨ìí ê°ì¸ IDE ì¤ì ê°ì´ ì¤íëì´ ì ë ¬ ì
16ìê° ì¸ì ë ë°ë ì ìë ìí©ë ìë¤.\n\u003cbr /\u003e\n\n## ë§ì¹ë©°\n\nì¬ì¤, `import` 구문 ììê° ë¹ì§ëì¤ ë¡ì§ì ìí¥ì ë¼ì¹ë¤ê±°ë ìê¸°ì¹ ëª»í ìí©ì ë°ììí¬ ì¼ì ìë¤ê³ ìê°íë¤.\u003cbr/\u003e\nììë ì¤ìíì§ ìë¤.\u003cbr /\u003e\nìì°ì±ì´ ì¢ì ê°ë° 문í를 ì§í¥íë¤ë©´, `import` 구문 ì ë ¬ì ëí ê·ì¹ë lintí ì ìëë¡ íì!\n\n## References\n\n- https://eslint.org/docs/rules/sort-imports\n- https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md\n","data":{"id":"eslint import/order","title":"eslint import rule ì¤ì ì ì´ì ","description":"import구문ì ì ë ¬ ê·ì¹ ì ì©ì ì´ì ì ëí´ ìê°í©ëë¤.","preview":"import구문ì ì ë ¬ ê·ì¹ ì ì©ì ì´ì ì ëí´ ìê°í©ëë¤.","keywords":"javascript, eslint, import rule, eslint-plugin-import","slug":"eslint-import-order","createdAt":"2022.02.07","published":true},"filePath":"eslint-import-order.mdx"},{"content":"\n`enum`ì ìë°ì¤í¬ë¦½í¸ì íì
ë 벨ììë ì¡´ì¬íì§ ìì§ë§ íì
ì¤í¬ë¦½í¸ììë ì¡´ì¬íë ëª ìëë ê¸°ë¥ ì¤ íëì´ë¤.\níí íë¡ê·¸ëë° ì¤ ì°ê´ë ììë¤ì 묶ìë ì´ê±°íì´ë¼ê³ ë¶ë¦¬ì°ë `enum`ì íµí´ íííê³ íë¤.\n\n```ts\nenum Direction {\n Up,\n Down,\n Left,\n Right,\n}\n\nfunction moveTo(direction: Direciton) {\n if (direction === Direciton.UP) {\n // Do something..\n }\n\n // Do something..\n}\n```\n\níì
ì¤í¬ë¦½í¸ë¡ ê°ë°ì íë¤ë³´ë©´ ìì ê°ì ì½ë를 íí ìì±íê² ëë¤.\u003cbr/\u003e\nìì ë§íê² ì²ë¼, `enum`ì ìë°ì¤í¬ë¦½í¸ììë ì¡´ì¬íì§ ì기 ë문ì íì
ì¤í¬ë¦½í¸ë¡ `enum`ì ì¬ì©íì ë, ì´ ì½ëê° ì»´íì¼ì´ ë í ìë°ì¤í¬ë¦½í¸ììë ì´ë¤ìì¼ë¡ ííì´ ëëì§ ê³ ì°°ì í´ë³´ê³ ì¬ì©íë ê²ì´ ì¢ê² ë¤.\n\n## Enumì í¹ì§ê³¼ ë¶ë¥\n\n- Enumì ê°ì¼ë¡ ìëì ê°ì ê°ë¤ì ê°ì§ ì ìë¤.\n - 문ìì´ ë¦¬í°ë´ ( e.g. `'hello'`, `'a'`, `'bye'` )\n - ì«ì 리í°ë´ ( e.g. `0`, `1`, `0.2`, `1000` )\n - ë¶í¸ê° ìë ì«ì( ìì ) 리í°ë´ ( e.g. `-1`, `-0.2`, `-1000` )\n- ì´ ê°ë¤ì ëí, 모ë ê³ì°ëì´ì§ ê°ë¤ì´ì´ì¼ íë¤.\n\n### Numeric enums\n\n- `numeric enum`ì 멤ë²ë ì´ê¸°ê°ì í ë¹í´ ì£¼ì§ ìì¼ë©´, 기본ì ì¼ë¡ **ê·¸ ì ì 멤ë²ë¡ë¶í° 1ì© ì¦ê°ëë ì«ìê° ê°ì¼ë¡ í ë¹**ëë¤.\n- 첫 멤ë²ê° ê°ì í ë¹ë°ì§ ììë¤ë©´ `0`ì ê°ì¼ë¡ ê°ì§ê² ëë¤.\n\nìë ì½ë를 ë³´ë©´ íì¤íê² ì´í´í ì ìë¤.\n\n```ts\nenum Direction {\n Up, // 0\n Down, // 1\n Left, // 2\n Right, // 3\n}\n\nenum Speed {\n VeryLow = -1, // -1\n Low, // 0\n Normal = -0.2, // -0.2\n Fast, // 0.8\n VeryFast // 1.8\n SuperFast = 100, // 100\n UltraFast // 101\n}\n```\n\n**`numeric enum`ì ì»´íì¼ ì, `reverse mapping`ì´ ëë¤.**\n\n#### after compile\n\n```ts\n// before compile\nenum Direction {\n Up,\n Down,\n Left,\n Right,\n}\n\nlet up = Direction.Up; // 0\nlet nameOfUp = Direction[up]; // 'Up'\n\n// after compile\nvar Direction;\n(function (Direction) {\n Direction[(Direction['Up'] = 0)] = 'Up';\n Direction[(Direction['Down'] = 1)] = 'Down';\n Direction[(Direction['Left'] = 2)] = 'Left';\n Direction[(Direction['Right'] = 3)] = 'Right';\n})(Direction || (Direction = {}));\n```\n\n```ts\nconsole.log(Direciton);\n\n{0: 'Up', 1: 'Down', 2: 'Left', 3: 'Right', Up: 0, Down: 1, Left: 2, Right: 3}\n```\n\n- reverse mappingì´ ë íì ì¤ì `Direction`ì ìì ê°ì íí를 ì´ë£¬ë¤.\n- **ì«ì를 ê°ì¼ë¡ ê°ì§ë enumì 멤ë²ë¤ì 모ë `reverse mapping`ì´ ëë¤.**\n\n### String enums\n\n- `string enum`ì 멤ë²ë¤ì 모ë ì´ê¸° ê°ì í ë¹ ë°ìì¼ íë¤.\n- `numeric enum`ì²ë¼ ìë ì¦ê°ëë ê°ì ê°ì§ì§ ìì§ë§, ì§ë ¬íê° ì ëë¤ë ì¥ì ì´ ìë¤.\n - 멤ë²ì ì´ë¦ì ê´ê³ ìì´, **ì½ë ëìì ì미 ìê³ ì½ì ì ìë ê°ì ì ê³µí ì ìë¤.**\n\n```ts\nenum Direction {\n Up = 'UP',\n Down = 'Down',\n Left = 'Left',\n Right = 'Right',\n}\n```\n\n#### after compile\n\n```ts\nvar Direction;\n(function (Direction) {\n Direction['Up'] = 'UP';\n Direction['Down'] = 'Down';\n Direction['Left'] = 'Left';\n Direction['Right'] = 'Right';\n})(Direction || (Direction = {}));\n```\n\n### Heterogeneous enums\n\n- 기ì ì ì¼ë¡ `enum`ì `string enum`ê³¼ `numeric enum`ì 멤ë²ê° í¼í©ì´ ë ì ìì§ë§, 목ì ì´ ë¶ë¶ëª
í ì½ëê° ë ì ìë¤.\n- ìë°ì¤í¬ë¦½í¸ ë°íìì ëìì ì리í ë°©ë²ì¼ë¡ íì©íë ì´ì ê° ìëë¼ë©´ **ì¬ì©íì§ ìë ê²ì ê¶ì¥íë¤.**\n- í¼í©íì¬ ì¬ì©í ëë ë§ì°¬ê°ì§ë¡ `numeric enum`ì ìë ì¦ê°ëë ê° í ë¹, `reverse mapping` ë±ì í¹ì§ì ëì¼íë¤.\n\n```ts\nenum Direction {\n Up,\n Down = 'Down',\n Left = 1,\n Right,\n}\n```\n\n#### after compile\n\n```ts\nvar Direction;\n(function (Direction) {\n Direction[(Direction['Up'] = 0)] = 'Up';\n Direction['Down'] = 'Down';\n Direction[(Direction['Left'] = 1)] = 'Left';\n Direction[(Direction['Right'] = 2)] = 'Right';\n})(Direction || (Direction = {}));\n```\n\n### Declaration Merging\n\n- `enum`ë **declaration merging(ì ì¸ ë³í©)**ì ëìì´ ëë¤.\n- `numeric enum`ì ì ì¸ ë³í©ì, 2ë²ì§¸ enumì ì´ê¸° ê°ì íì ê°ì ¸ì¼ íë¤.\n\n```ts\nenum Direction {\n Up,\n Down,\n Left,\n}\n\nenum Direciton {\n Right = 4,\n}\n```\n\n#### after compile\n\n```ts\nvar Direction;\n(function (Direction) {\n Direction[(Direction['Up'] = 0)] = 'Up';\n Direction[(Direction['Down'] = 1)] = 'Down';\n Direction[(Direction['Left'] = 2)] = 'Left';\n})(Direction || (Direction = {}));\n(function (Direction) {\n Direction[(Direction['Right'] = 4)] = 'Right';\n})(Direction || (Direction = {}));\n\nconsole.log(Direciton);\n\n{0: 'Up', 1: 'Down', 2: 'Left', 3: 'Right', Up: 0, Down: 1, Left: 2, Right: 3}\n```\n\n### Immediately invoked function expression\n\n- 모ë `enum`ì ì»´íì¼ í **ì¦ìì¤í í¨ì ííì(IIFE)**ì íìì¼ë¡ ì½ëê° ë³íëë¤.\n- rollupê³¼ ê°ì ë²ë¤ë¬ë IIFEì ì¬ì© ì¬ë¶ë¥¼ íë¨í ì ì기 ë문ì, Tree-shaking ëì§ ìëë¤.\n - `enum`ì´ ì£½ì ì½ëê° ëëë¼ë ì»´íì¼ë ì½ëì ë²ë¤ìë ì¡´ì¬íê² ëë¤.\n - [ì¬ê¸°ì](https://rollupjs.org/repl/?version=2.26.11\u0026shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMCU3QkRpcmVjdGlvbiU3RCUyMGZyb20lMjAnLiUyRmVudW0uanMnJTVDbmltcG9ydCUyMCU3QmhlbGxvJTdEJTIwZnJvbSUyMCcuJTJGdHJlZXNoYWtlZCclNUNuaW1wb3J0JTIwJTdCaGklN0QlMjBmcm9tJTIwJy4lMkZub3RUcmVlc2hha2VkJyU1Q24lNUNuY29uc29sZS5sb2coaGVsbG8pJTVDbiUyMiUyQyUyMmlzRW50cnklMjIlM0F0cnVlJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMmVudW0uanMlMjIlMkMlMjJjb2RlJTIyJTNBJTIyJ3VzZSUyMHN0cmljdCclNUNuZXhwb3J0JTIwdmFyJTIwRGlyZWN0aW9uJTVDbiUzQi
16hmdW5jdGlvbiUyMChEaXJlY3Rpb24pJTIwJTdCJTVDbiUyMCUyMERpcmVjdGlvbiU1QidVcCclNUQlMjAlM0QlMjAnVVAnJTVDbiUyMCUyMERpcmVjdGlvbiU1QidEb3duJyU1RCUyMCUzRCUyMCdET1dOJyU1Q24lMjAlMjBEaXJlY3Rpb24lNUInTGVmdCclNUQlMjAlM0QlMjAnTEVGVCclNUNuJTIwJTIwRGlyZWN0aW9uJTVCJ1JpZ2h0JyU1RCUyMCUzRCUyMCdSSUdIVCclNUNuJTdEKShEaXJlY3Rpb24lMjAlN0MlN0MlMjAoRGlyZWN0aW9uJTIwJTNEJTIwJTdCJTdEKSklMjIlN0QlMkMlN0IlMjJuYW1lJTIyJTNBJTIydHJlZXNoYWtlZC5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJleHBvcnQlMjB2YXIlMjBoZWxsbyUyMCUzRCUyMCdoZWxsbyclMjIlN0QlMkMlN0IlMjJuYW1lJTIyJTNBJTIybm90VHJlZXNoYWtlZC5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJleHBvcnQlMjB2YXIlMjBoaSUyMCUzRCUyMCdoaSclMjIlN0QlNUQlMkMlMjJvcHRpb25zJTIyJTNBJTdCJTIyZm9ybWF0JTIyJTNBJTIyZXMlMjIlMkMlMjJuYW1lJTIyJTNBJTIybXlCdW5kbGUlMjIlMkMlMjJhbWQlMjIlM0ElN0IlMjJpZCUyMiUzQSUyMiUyMiU3RCUyQyUyMmdsb2JhbHMlMjIlM0ElN0IlN0QlN0QlMkMlMjJleGFtcGxlJTIyJTNBbnVsbCU3RA==) ì§ì íì¸í ì ìë¤.\n\n## const enum\n\n- `enum`ì ì¶ê° ì½ë ìì±ê³¼ ê°ì 참조 ì½ë를 í¼íê³ ì¶ì¼ë©´ `const enum`ì ì¬ì©íëê² ë°©ìì´ ë ì ìë¤.\n- `const enum`ì ì»´íì¼ ì¤ì ìì í ì ê±°ëê³ , 참조íë ì½ëìììì ê°ë§ ì¸ë¼ì¸ëì´ì§ë¤.\n\n```ts\nconst enum Direction {\n Up,\n Down,\n Left,\n Right,\n}\n\nconsole.log(Direction.Up);\n```\n\nìì ê°ì ì½ëê° ì»´íì¼ì´ ëë©´, ìëì ê°ì´ ì¸ë¼ì¸ë ì½ëë§ ë¨ê² ëë¤.\n\n```ts\nconsole.log(0 /* Up */);\n```\n\n기본 `enum`ê³¼ ë¹êµíì ë, ì»´íì¼ íìë ë§ì ì°¨ì´ê° ì기ë ê²ì¼ë¡ ë³¼ ì ìë¤.\u003cbr/\u003e\në¶íìí ì½ëë¤ì´ ìì±ëì§ ìì, ë©ëª¨ë¦¬ì ë²ë¤ë§ ë ì½ëì ì¬ì´ì¦ê° ì¡°ê¸ ë ì¤ì´ë ë¤ë ì´ì ì´ ìë¤.\u003cbr/\u003e\níì§ë§ `d.ts` íì¼ì ìì±í´ì¼íê±°ë, ë¼ì´ë¸ë¬ë¦¬ë¡ì¨ ì ê³µí´ì¼ ë ê²½ì°ìë íì
ì¶ë¡ ì´ ë¶ê°íë¤ë ë¨ì ë ìë¤.\u003cbr/\u003e\nì´ë´ ê²½ì°ì, `tsconfig`ì [preserveConstEnums](https://www.typescriptlang.org/tsconfig#preserveConstEnums) ìµì
ì `true`ë¡ ì¤ì íì¬ í´ê²°í ì ìë¤.\u003cbr/\u003e\u003cbr/\u003e\n\në, `tsconfig`ì [isolatedModules](https://www.typescriptlang.org/tsconfig#isolatedModules) ìµì
ì `true`ë¡ ì¤ì íê³ \n`cosnt enum`ì ì¬ì©íë©´ ì»´íì¼ì ì¤ë¥ê° ëê² ëë, ì¬ì© ì ì ì´ë¬í ë¶ë¶ì ê¼ ìì§íì¬ì¼ íë¤.\n\n## Object Literal const assertions\n\níì
ì¤í¬ë¦½í¸ 3.4 ë²ì ì ëì¨ **const assertions**ì ì¬ì©íë©´ `enum`ì ì¬ì©íì§ ììë ëì¼íê² ììë¤ì ì´ê±°íë ííì ì½ê² í ì ìë¤.\n\n```ts\nconst Direction = {\n Up: 'Up',\n Down: 'Down',\n Left: 'Left',\n Right: 'Right',\n} as const;\n\ntype EnumerateDirection = typeof Direction[keyof typeof Direction];\n// EnumerateDirection = 'Up' | 'Down' | 'Left' | 'Right'\n\nfunction moveTo(direction: EnumerateDirection) {\n if (direction === 'Up') {\n // Do something..\n }\n}\n```\n\nìì ì½ëì ê°ì´ íì
ì ì¶ë¡ í기 ìí´ type aliasingì í ë² í´ì£¼ì´ì¼íë ë²ê±°ë¡ìì´ ìì§ë§, `enum`ì¼ë¡ë¶í° ì»ì ì ìë ëª ê°ì§ì ì¥ì ì´ ì¡´ì¬íë¤.\n\n1. ì»´íì¼ì
16 íë©´ íì
ì¤í¬ë¦½í¸ìì ìì±í íìì´ ì ì§ë ì±ë¡ ìë°ì¤í¬ë¦½í¸ë¡ ë³íëë¤.\n2. Tree-shakingì´ ì ì©ëë¤.\n3. (ìëíì§ ìì)ì ì¸ ë³í©ì ëìì´ ëì§ ìëë¤.\n\n#### after compile\n\n```ts\nconst Direction = {\n Up: 'Up',\n Down: 'Down',\n Left: 'Left',\n Right: 'Right',\n};\n\n// EnumerateDirection = 'Up' | 'Down' | 'Left' | 'Right'\nfunction moveTo(direction) {\n if (direction === 'Up') {\n // Do something..\n }\n}\n```\n\n## ë§ì¹ë©°\n\nìì ë´ì©ì ìì½íìë©´,\n\n1. `enum` 멤ë²ë¤ì ê°ì ê³ì°ë 문ìì´ í¹ì ì«ìë§ í ë¹ë ì ìë¤.\n2. `enum`ë ì ì¸ ë³í©ì´ ê°ë¥íë¤.\n3. `numeric enum`ì ì»´íì¼ í `reverse mapping`ì´ ëë¤.\n4. `enum`ì IIFEë¡ ë³íë기 ë문ì Tree-shakingì´ ëì§ ìëë¤.\n5. `const enum`ì í´ë¹ ê°ì 참조íë ë¶ë¶ì ì½ëë§ ì¸ë¼ì¸ëë¤.\n6. TS 3.4 ì´ìì ë²ì ì ê°ì²´ 리í°ë´ì `const assertions` í´ì£¼ë ê²ì¼ë¡ ììì ì´ê±°ë¥¼ ííí ì ìë¤.\n\n## References\n\n- https://www.typescriptlang.org/docs/handbook/enums.html\n- https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions\n","data":{"id":"enum","title":"Enumì ëí ê³ ì°°","description":"Typescriptì Enumì ëí´ ììë´
ëë¤.","preview":"Typescriptì Enumì ëí´ ììë´
ëë¤.","keywords":"typescript, javascript, enum, reverse mapping","slug":"enum","createdAt":"2022.01.21","published":true},"filePath":"enum.mdx"},{"content":"\n\u003e **Kent C. Dodds**ì [JavaScript Pass By Value Function Parameters](https://kentcdodds.com/blog/javascript-pass-by-value-function-parameters) ê¸ì ë²ìíììµëë¤.\n\nì ìë ì½ëê° ëìíì§ ììê¹ì?\n\n````js\nfunction getLogger(arg) {\n function logger() {\n console.log(arg);\n }\n return logger;\n}\n\nlet fruit = 'raspberry';\nconst logFruit = getLogger(fruit);\n\nlogFruit(); // \"raspberry\"\nfruit = 'peach';\nlogFruit(); // \"raspberry\" Wait what!? Why is this not \"peach\"?```\n````\n\nì¬ê¸°ì ì¼ì´ëê³ ìë ì¼ì ì´ì¼ê¸°í기 ìí´, ëë fruitì´ë¼ë ë³ì를 ìì±íê³ ë¬¸ìì´ raspberry를 í ë¹íë¤.\nê·¸ë° ë¤ì, ëë í¸ì¶ëìì ë fruit를 ì¶ë ¥íë loggerë¼ê³ ë¶ë¦¬ë í¨ì를 ìì±íê³ ë°íí´ì£¼ë í¨ìì fruit를 ì ë¬íë¤.\ní¨ì를 í¸ì¶íì ë, ììëë¡ raspberry를 console.log ì¶ë ¥ ê°ì¼ë¡ ë°ëë¤.\u003cbr/\u003e\n\níì§ë§, ëë fruitì peach를 ì¬í ë¹íê³ logger를 ë¤ì í¸ì¶íë¤. fruitì ìë¡ì´ ê°ì console.logì ì¶ë ¥ì¼ë¡ ì»ë ê² ëì ì, fruitì ì´ì ê°ì ì»ìë¤!\ngetLogger를 ë¤ì í¸ì¶íì¬ ìë¡ì´ logger를 ì»ë ê²ì¼ë¡ ì´ê²ì í¼í ì ìë¤.\n\n```js\nconst logFruit2 = getLogger(fruit);\nlogFruit2(); // \"peach\" what a relief...\n```\n\níì§ë§ ì ë¨ìí ë³ìì ê°ì ë°ê¾¸ê³ , loggerê° ë§ì§ë§ ê°ì ê°ì ¸ì¬ ì ìë ì´ì ê° ëê¹?\u003cbr/\u003e\n\nì ëµì ìë°ì¤í¬ë¦½í¸ ìì ìë¤. í¨ì를 ì¸ìì í¨ê» í¸ì¶í ë, ì¸ìë ì°¸ì¡°ê° ìë ê°ì¼ë¡ ì ë¬ëë¤ë ê²ì´ë¤. ì¬ê¸°ì ë¬´ì¨ ì¼ì´ ì¼ì´ëëì§ ê°ë¨íê² ì¤ëª
íê² ë¤.\n\n````js\nfunction getLogger(arg) {\n function logger() {\n console.log(arg);\n }\n return logger;\n}\n\n// side-note, this could be written like this too\n// and it wouldn't make any difference whatsoever:\n// const getLogger = arg =\u003e () =\u003e console.log(arg)\n// I just decided to go more verbose to keep it simple```\n````\n\ngetLoggerê° í¸ì¶ë ë, logger í¨ìë ìì±ëë¤. ì´ê²ì ìë¡ì´ í¨ìì´ë¤. ìë¡ì´ í¨ìê° ìì±ë ë, ì´ê²ì ì ê·¼ì´ ê°ë¥í 모ë ë³ì를 ëë¬ë³´ê³ , closureë¼ê³ ë¶ë¦¬ì°ë ííë¡ ë«íì§ë¤. ì´ê²ì ì´ logger í¨ìê° ì¡´ì¬íëëì, ë¤ë¥¸ 모ë ë 벨ì ë³ìë¤ê³¼ ë¶ëª¨ì í¨ì ìì ìë ë³ìë¤ì ì ê·¼ì´ ê°ë¥íë¤ë ê²ì ì미íë¤.\u003cbr/\u003e\n\nê·¸ëì loggerê° ìì±ë ë, ì ê·¼ì´ ê°ë¥í ë³ìê° ë¬´ìì¼ê¹? ìì ì½ë를 ë¤ì ë³´ì. ì´ê²ì fruit, getLogger, arg, logger(ì기 ìì )ì ì ê·¼í ì ìë¤. 목ë¡ì ë¤ì íì¸í´ë¼. ìëíë©´ ì½ëê° ëìíë ë°©ë²ì ë§¤ì° ì¤ìí기 ë문ì´ë¤. ëê° ëì¹ì±ì
¨ëì? fruitì argê³¼ 모ë ëì¼í ê°ììë ë¶êµ¬íê³ ë ë¤ ëì´ëìë¤!\u003cbr/\u003e\n\në¨ì§ ë ê°ì ë³ìë ê°ì ê°ì´ í ë¹ ëìì§, ê°ì ë³ì를 ì미íë ê²ì ìëë¤. ì´ ì»¨ì
ì ê°ë¨í ìì ê° ì¬ê¸° ìë¤:\n\n```js\nlet a = 1;\nlet b = a;\n\nconsole.log(a, b); // 1, 1\n\na = 2;\nconsole.log(a, b); // 2, 1 â¼ï¸\n```\n\nbê° ë³ì aì ê°ì ê°ë¦¬í¤ê² ë§ë¤ìììë ë¶êµ¬íê³ ë³ì aì ê°ì ë°ê¿ ì ììê³ , bê° ê°ë¦¬í¤ê³ ìë ê°ì ë³í
16ì§ ìììì 주ìí´ë¼. ì´ê²ì b를 ê·¸ ìì²´ë¡ ê°ë¦¬í¤ì§ ìì기 ë문ì´ë¤. ì°ë¦¬ë ê·¸ ë¹ìì aê° ê°ë¦¬ì¼°ë ê°ì bê° ê°ë¦¬í¤ëë¡ íìë¤!\u003cbr/\u003e\n\nëë ë³ìë¤ì ì»´í¨í°ì ë©ëª¨ë¦¬ì ìë ê³µê°ì ê°ë¦¬í¤ë ìì íì´íë¡ ìê°íë ê²ì ì¢ìíë¤. ê·¸ëì let a = 1ë¼ê³ ë§íë©´, ì°ë¦¬ë \"ìë°ì¤í¬ë¦½í¸ ìì§ì, ëë ë©ëª¨ë¦¬ì ê°ì´ 1ì¸ ì¥ì를 ë§ë¤ê³ , ë©ëª¨ë¦¬ì í´ë¹ ì¥ì를 기리í¤ë aë¼ê³ ë¶ë¥´ë íì´í를 ìì±í기를 ìí´.\"ë¼ê³ ë§íë¤.\u003cbr/\u003e\n\nê°ì ë°©ë²ì¼ë¡, ì°ë¦¬ê° í¨ì를 í¸ì¶í ë ìë°ì¤í¬ë¦½í¸ ìì§ì í¨ì ì¸ì를 ìí´ ìë¡ì´ ë³ì를 ìì±íë¤. ì°ë¦¬ì ê²½ì°ì, getLogger(fruit)를 í¸ì¶íê³ ìë°ì¤í¬ë¦½í¸ ìì§ì 기본ì ì¼ë¡ ì´ê²ì ìííë¤:\n\n```js\nlet arg = fruit;\n```\n\nê·¸ëì ëì¤ì fruit = 'peach'를 ìíí ë, argë fruitê³¼ë ìì í ë¤ë¥¸ ë³ìì´ê¸° ë문ì ìí¥ì 미ì¹ì§ ìëë¤.\u003cbr/\u003e\n\nì´ê²ì íê³ë¡ ìê°íë 기ë¥ì¼ë¡ ìê°íë , ì¬ì¤ì ì´ê²ì´ ëìíë ë°©ìì´ë¼ë ê²ì´ë¤. ë§ì½, 2ê°ì ë³ì를 ê°ì ìµì ì¼ë¡ ì ì§íê³ ì¶ë¤ë©´, ê·¸ë ê² íë ë°©ë²ì´ ìë¤! ì. ìì´ëì´ë ì´ì ê°ë¤: íì´íê° ê°ë¦¬í¤ë ìì¹ë¥¼ ë°ê¾¸ë ê² ëì ì ê°ë¥´í¤ë ê²ì ë°ê¿ ì ìë¤! ì를 ë¤ì´:\u003cbr/\u003e\n\n```js\nlet a = { current: 1 };\nlet b = a;\n\nconsole.log(a.current, b.current); // 1, 1\n\na.current = 2;\nconsole.log(a.current, b.current); // 2, 2 ð\n```\n\nì´ ê²½ì°ìë, a를 ì¬í ë¹íë ê²ì ì´ë리, ê°ë¦¬í¤ê³ ìë ê°ì ë³ê²½íìë¤. ê·¸ë¦¬ê³ bë ê°ì ê°ì ê°ë¦¬í¤ê³ ì기 ë문ì, ë ë¤ ì
ë°ì´í¸ëìë¤.\n\nê·¸ë¼, ì°ë¦¬ì logger 문ì 를 ìí´ ì´ í´ê²°ì±
ì ì ì©í´ë³´ì:\n\n```js\nfunction getLatestLogger(argRef) {\n function logger() {\n console.log(argRef.current);\n }\n return logger;\n}\n\nconst fruitRef = { current: 'raspberry' };\n\nconst latestLogger = getLatestLogger(fruitRef);\n\nlatestLogger(); // \"raspberry\"\nfruitRef.current = 'peach';\nlatestLogger(); // \"peach\" ð\n```\n\n## ê²°ë¡ \n\nRef ì 미ì¬ë ë³ìê° ê°ë¦¬í¤ê³ ìë ê°ì´ ë¨ìí ë¤ë¥¸ ê°ì 참조íëë° ì¬ì©ë¨ì ë§í´ì£¼ë referenceì ì¤ìë§ì´ë¤. ( ì¬ê¸°ìë ì¤ë¸ì í¸ì current ìì± ê°ì´ë¤. )\u003cbr/\u003e\n\nì´ê²ì ìì°ì¤ë½ê² ì ì¶©ì ì´ ìì§ë§, ëë ìë°ì¤í¬ë¦½í¸ ëª
ì¸ê° í¨ìì ì¸ìë¤ì ì°¸ì¡°ê° ìë ê°ì¼ë¡ ì ë¬íì¬ í¸ì¶íë ê²ì ë§ì¡±íë¤.\nê·¸ë¦¬ê³ í´ê²°ë°©ë²ì íìí ë í° ë¬¸ì ê° ëì§ ìëë¤. (ê°ë³ì±ì íë¡ê·¸ë¨ì ë³´íµ ë ì´í´í기 ì´ë µê² ë§ë¤ê¸° ë문ì ë§¤ì° ë물ë¤.) ëìì´ ëì기를 ë°ëë¤! 굿 ë!\n\n## References\n\n- https://kentcdodds.com/blog/javascript-pass-by-value-function-parameters\n","data":{"id":"JavaScript Pass By Value Function Parameters","title":"JavaScript Pass By Value Function Parameters","description":"Kent C. Doddsì JavaScript Pass By Value Function Parameters ê¸ì ë²ìíììµëë¤.","preview":"Kent C. Doddsì JavaScript Pass By Value Function Parameters ê¸ì ë²ìíììµëë¤.","keywords":"javascript, kent.c.dodds, translate, pass by value","slug":"javascript-pass-by-value-function-parameters","createdAt":"2022.01.18","published":true},"filePath":"javascript-pass-by-value-function-parameters.mdx"},{"content":"\níì
ì¤í¬ë¦½í¸ììë ìë 2ê°ì§ ë°©ìì¼ë¡ íì
ì ì를 í ì ìë¤.\u003cbr/\u003e\n\n- **Interface**\n- **Type Aliases**\n\níì
ì ì를 íê³ ì¶ë¡ íëë°ì ìì´ ì´ë¤ ë°©ìì ì¬ì©í´ë ê¸°ë¥ êµ¬íì 문ì ê° ììí
ì§ë§,\u003cbr/\u003e\nì´ ë°©ìë¤ì´ ì´ë¤ í¹ì§ì ê°ì§ê³ ìê³ ë°©ìê° ì°¨ì´ì ì´ ë¬´ìì¸ì§ ììë³´ì.\n\n## Interfaces\n\n- **Interface ì ì¸ì Object Typeì ì´ë¦ì ì§ì íë ë ë¤ë¥¸ ë°©ìì´ë¤.**\n \u003e ì´ë Object Typeì¼ë¡ íí ê°ë¥í íì
ì ëí´ìë§ interfaceë¡ì ì ì¸ì´ ê°ë¥íë¤ë ê²ì ì미íë¤.\n\n```ts\nfunction track(point: { x: number; y: number }) {\n // ..\n}\n\ninterface Point {\n x: number;\n y: number;\n}\n\nfunction track(point: Point) {\n // ..\n}\n```\n\nìì ìì ììì ê°ì´ `{ x: number, y: number }`를 `interface Point`ë¡ ì ì¸íì¬ ëì²´í ì ìë¤.\n\n### Extending\n\n- `interface`ë `extends` í¤ìë를 íµí´ **íì
ì íì¥**ì´ ê°ë¥íë¤.\n\n```ts\ninterface Point {\n x: number;\n y: number;\n}\n\ninterface Point3D extends Point {\n z: number;\n}\n\n// ì ì¸ë interfaceë classê° êµ¬íí´ì¼ í ì¸í°íì´ì¤ í¹ì ê°ì²´ì íì
ì¼ë¡ ì¬ì©ì´ ê°ë¥íë¤.\nclass Pointer implements Point {\n x = 0;\n y = 1;\n\n //...\n}\n\nconst pointB: Point3D = {\n x: 0,\n y: 1,\n z: 2,\n};\n\nfunction getPointer({ x, y }: Point) {\n return new Pointer({ x, y });\n}\n```\n\n### Declaration Merging\n\n- `interface`ë ëì¼í ì´ë¦ì¼ë¡ ì¶ê° ì ì¸ì
16 íµí´ **ë³í©**ì´ ê°ë¥íë¤.\n - ì¬ê¸°ì ëì¼í ì´ë¦ì ì ì¸í `interface` ê°¯ìë ì¤ìíì§ ìë¤. 모ë ë³í©ì´ ëë¤.\n\n```ts\ninterface Point {\n x: number;\n y: number;\n}\n\ninterface Point {\n z: number;\n}\n\nconst pointA: Point = {\n x: 0,\n y: 1,\n z: 3,\n};\n```\n\nì´ë¥¼ **ì ì¸ ë³í©(Declaration Merging)**ì´ë¼ê³ íë¤.\u003cbr/\u003e\n\n\u003e ì ì¸ ë³í©ì interface ë¿ë§ìëë¼ namespace, enumë ê°ì ë°©ìì¼ë¡ ì ì¸ ë³í©ì´ ëë¤.\u003cbr/\u003e\u003cbr/\u003e\n\u003e\n\u003e namespaceë class, function, enum, interface, type aliasingê³¼ë ì´ë¦ì´ ê°ë¤ë©´ ì ì¸ ë³í©ì´ ëë¤.\n\n```ts\ninterface Point {\n x: number;\n y: number;\n getDistance: (x: number) =\u003e number;\n}\n\n// Error: Property 'x' must be of type 'number';\ninterface Point {\n x: string;\n}\n```\n\nì ì¸ ë³í©ì, ê°ì ì´ë¦ì¼ë¡ ëì´ìë ìì± ì¤ë³µëë¤ë©´, íì
ì´ ë³í´ìë ìëë¤.\u003cbr/\u003e\n[ê°ë°© íì ìì¹](https://ko.wikipedia.org/wiki/%EA%B0%9C%EB%B0%A9-%ED%8F%90%EC%87%84_%EC%9B%90%EC%B9%99)ì ì¤ìí ê²ì´ë¼ê³ ìê°í´ë ì¢ì ê² ê°ë¤.\n\n```ts\ninterface Point {\n x: number;\n y: number;\n equal(x: number, y: number): number;\n}\n\ninterface Point {\n equal({ x, y }: { x: number; y: number }): number;\n}\n```\n\nëí, ì ì¸ ë³í©ì, [í¨ì ì¤ë²ë¡ë](https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads)ë ìì ê°ì´ ê°ë¥íë¤.\n\n## Type Aliases\n\n- **Type Aliasingì í¹ì íì
ì ëí´ ë¤ë¥¸ ì´ë¦ì ì§ì´ì£¼ë ê²ì´ë¤.**\n- íì
ì¢
ë¥ì ëí ì ì½ì ìë¤.\n\n```ts\ntype Point = {\n x: number;\n y: number;\n};\n\ntype Name = string;\n\ntype ID = string | number;\n\ntype SomeFunction = () =\u003e any;\n```\n\nìì ê°ì´ `string`ê³¼ ê°ì´ ìë°ì¤í¬ë¦½í¸ì ììíì
ì ëí´ ë³ì¹ì í ì ìì¼ë©°, `Object Type`, `Union Type`ì ëí´ìë ë³ì¹ì´ ê°ë¥íë¤.\n\n\u003e Union Typeì 2ê°ì§ ì´ìì ë¤ë¥¸ íì
ì¼ë¡ 구ì±ë íì
ì ë§íë¤.\n\n- **Type Aliasingì ë¨ì§ ë¤ë¥¸ ì´ë¦ì¼ ë¿ì´ë¤.**\n\n```ts\ntype UserInputSanitizedString = string;\n\nfunction sanitizeInput(str: string): UserInputSanitizedString {\n return sanitize(str);\n}\n\nlet userInput = sanitizeInput(getInput());\n\n// 문ìì´ í ë¹\nuserInput = 'new input';\n```\n\n\u003e `UserInputSanitizedString`ë `string`ì ë¤ë¥¸ ì´ë¦ì´ê¸° ë문ì ê²°ê³¼ì ì¼ë¡ë `string`ê³¼ ëì¼í íì
ì¼ë¡ ì¶ë¡ ì´ ëì´,\u003cbr/\u003e\n\u003e ìì ê°ì´ `UserInputSanitizedString`ì íì
ì¼ë¡ ì¶ë¡ ëë ë³ìì ë¤ë¥¸ 문ìì´ì í ë¹ì´ ê°ë¥íë¤.\n\n### Extending\n\n- `Type Aliasing`ë `intersection`ì íµí´ **íì
ì íì¥**ì´ ê°ë¥íë¤.\n\n```ts\ntype Animal = {\n name: string;\n};\n\ntype Bear = Animal \u0026 {\n honey: boolean;\n};\n\nconst bear = getBear();\nbear.name;\nbear.honey;\n```\n\n- `Type Aliasing`ì ì ì¸ ë³í©(Declaration Merging)ì´ ëì§ ìëë¤.\n - ë°ë¼ì, ëì¼í ì´ë¦ì `Type`ì ìë¡ì´ ìì±ì ì¶ê° í ì ìë¤.\n - ì´ë `interface`ì ê°ì¥ í° ì°¨ì´ë¼ê³ ë³¼ ì ìë¤.\n\n```ts\ntype Window = {\n title: string;\n};\n\ntype Window = {\n ts: TypeScriptAPI;\n};\n// Error: Duplicate identifier 'Window'.\n```\n\n### Use with extends, implements\n\n- `Type Aliasing`ì Object Typeì¼ ê²½ì°ì `Extends`, `implements` í¤ìëìë ê°ì´ ì¬ì©ì´ ê°ë¥íë¤.\n\n```ts\ntype Point = {\n x: number;\n y: number;\n};\n\ninterface Point3D extends Point {\n z: number;\n}\n\nclass Pointer implements Point {\n x = 0;\n y = 1;\n\n //...\n}\n```\n\n## ë§ì¹ë©°\n\níì
ì ìíëë° 2ê°ì§ì ë°©ë²ê³¼ ê° í¹ì§ë¤ì ëí´ ììë³´ìë¤.\u003cbr/\u003e\nê°ì¥ 주ë ì°¨ì´ì ì **ì´ë¤ íì
ì ì ìí ì ìëê°**ì **ì ì¸ ë³í©ì´ ëëê°**ë¼ê³ ìê°íë¤.\u003cbr/\u003e\níì
ì¤í¬ë¦½í¸ ê³µì 문ììë ë ì¤ íëì **ì íì ê°ì¸ì ì·¨í¥ì´ê³ , ì§ì ì ì¸ ê²½íì íµí´ íë¨íê³ ì íë¤ë©´, `type`ì 기ë¥ì ëí íìì±ì ëë¼ê¸° ì ê¹ì§ 먼ì `interface`를 ì¬ì©**íë¼ê
16³ íë¤.\n\n## References\n\n- https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#interfaces\n- https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-aliases\n- https://www.typescriptlang.org/docs/handbook/declaration-merging.html\n","data":{"id":"Interfaces vs Type Aliases","title":"Interfaces vs Type Aliases","description":"Typescriptì Interfaceì Type Aliasingì ëí´ ììë´
ëë¤.","preview":"Typescriptì Interfaceì Type Aliasingì ëí´ ììë´
ëë¤.","keywords":"typescript, javascript, interface, type aliasing","slug":"interface-vs-type","createdAt":"2022.01.03","published":true},"filePath":"interface-vs-type.mdx"},{"content":"\nì¹ íì´ì§ ì±ë¥ í¥ì ë°©ë² ì¤ íëì¸ ì´ë¯¸ì§ ìµì í.\u003cbr/\u003e\nì¹ìì ì주 ì¬ì©ëì´ì§ë ì´ë¯¸ì§ì ëí´ ììë³´ê³ , ìµì í ì리ì ë°©ìì ëí´ ììë³´ì.\n\n## Image\n\nì´ë¯¸ì§ íì¼ íìì **ëì§í¸ ì´ë¯¸ì§ë¥¼ 구ì±íê³ ì ì¥íë íì¤ì ì¸ ë°©ë²**ì ì미íë¤.\u003cbr/\u003e\në°ë¼ì, ì´ë¯¸ì§ íì¼ì 모ëí°ë í린í°ë¡ **ë ì¤í°í**í ì ìë **ë°ì´í°ì 모ì**ì´ë¼ê³ ìê°íë©´ ëë¤.\u003cbr/\u003e\n\n\u003e ëì¤í°í(Rasterization)ë, ë²¡í° ê·¸ëí½ì¼ë¡ ì¤ëª
ë ì´ë¯¸ì§ë¥¼ ëì¤í°ì´ë¯¸ì§(=ë¹í¸ë§µì´ë¯¸ì§)ë¡ ë³ííë ìì
.\n\nì´ë¯¸ì§(ë°ì´í°ì 모ì)ë ì¼ë°ì ì¼ë¡ ìëì ê°ì í¬ë§·ì¼ë¡ ì ì¥í ì ìë¤.\n\n- Raster formats\n - ë°ì´í°ë¥¼ ì¬ê°í 그리ë(í´ìë) ìì ê° í½ì
ì ê°ì ì¸ì½ë©íì¬ ì ì¥.\n - ì¸ì½ë©ì, ìì¶ or 무ìì¶ ì²ë¦¬ê° ëë¤. (ìì¶ì ë°ì´í° ìì¤ì´ ë°ìí ì ìì.)\n - í´ìëê° í¬ê³ , ê° í½ì
ì íííë ìì ì ë³´ê° ë§ì ìë¡ ìë¡ ë°ì´í°ì í¬ê¸°ê° 커ì§ë¤.\n- Vector formats\n - ë°ì´í°ë¥¼ ì , ì , ëíì¼ë¡ ì ì¥.\n\n### file types\n\n2ê°ì§ í¬ë§·ì¼ë¡ ëì´ ìë ë§ì ì´ë¯¸ì§ íì¼ë¤ì´ ìì§ë§, ì¹ìì íí ì¬ì©ëì´ì§ë ì´ë¯¸ì§ íì¼ íì
ë¤ì ëí´ìë§ ììë³´ì.\n\n| type | File format | MIME type | File extension(s) | Summary |\n| ---- | ------------------------------------- | ------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| GIF | Graphics Interchange Format | image/gif | .gif | ëì¤í° í¬ë§·, 무ìì¤ ìì¶\u003cbr/\u003e8ë¹í¸ 256ììê³¼ ë¨ì¼ í¬ëª
ì ì§ì\u003cbr/\u003eì¬ë¬ íë ìì ë°ì´í°ë¡ ê°ì§ ì ìì(ì ëë©ì´ì
ê°ë¥) |\n| JPEG | Joint Photographic Expert Group image | image/jpeg | .jpg, .jpeg, .jfif, .pjpeg, .pjp | ëì¤í° í¬ë§·, ìì¤ ìì¶\u003cbr/\u003eìì¶ë¥ ì´ ëì ê²½ì°, ì´ë¯¸ì§ ìì¤ ë°ì\u003cbr/\u003eëì¼í ì´ë¯¸ì§ë¥¼ ì¬ë¬ë² í¸ì§/ì ì¥ì ì ì íë¦¬í° ì í\u003cbr/\u003eê°ì¥ ë§ì´ ì¬ì©ëë í¬ë§· |\n| PNG | Portable Network Graphics | image/png | .png | ëì¤í° í¬ë§·, 무ìì¤ ìì¶\u003cbr/\u003eGIF를 ëì²´í기 ìí´ ë§ë¤ì´ì§\u003cbr/\u003e8ë¹í¸(í¬ëª
ë ìµì
ì¡´ì¬), 24ë¹í¸ í¸ë£¨ì»¬ë¬(1600ë§ ì), 48ë¹í¸ í¸ë£¨ì»¬ë¬, ìíì±ë(ìµì
ë) ì§ì\u003cbr/\u003eì ëë©ì´ì
ì APNG í¬ë§·ì¼ë¡ ê°ë¥ |\n| SVG | Scalable Vector Graphics | image/svg+xml | .svg | ë²¡í° í¬ë§·\u003cbr/\u003exml íìì¼ë¡ ë°ì´í° ì ì¥. |\n\n\u003e [MDN](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types)ììë ëªê°ì§ì íì
(WebP, AVIF, APNG)ì ëí´ ë ì¤ëª
í´ ì£¼ê³ ìì§ë§, ì´ ê¸ììë ë¸ë¼ì°ì í¸íì±ì ê³ ë ¤íì¬(IE..) ìì±íìë¤.\n\n## Optimize\n\nì´ë¯¸ì§ë ëì²´ë¡ ì¹ íì´ì§ì HTML, CSS, Javascript ë±ì 리ìì¤ë³´ë¤ ë§ì ë°ì´í¸ë¥¼ íìë¡ íë¤.\u003cbr/\u003e\nê°ì¥ ì¢ì ìµì í ì ëµì ì´ë¯¸ì§ë¥¼ ëì²´í ì ìë ë°©ì(ex. css íí, ì¹í°í¸ ì¬ì© ë±)를 íì©íì¬ ì¬ì©ììê² ì»¨í
ì¸ ë¥¼ ì ë¬íë ê²ì´ê² ì§ë§ ì´ë¯¸ì§ ëí ì¢ì íí ìë¨ì´ë¯ë¡\nì¬ë°ë¥¸ í¬ë§·ì ì ííë 기ì¤, ìµì í를 íë ë°©ì/ë°©ë²ì ëí´ ììë³´ì.\u003cbr/\u003e\n\n\u003e í¬ë§·ì ì ííëë°ì ìì´, ì ëµì ìì§ë§, ìµ
16ì ì ë
¸ë ¥ì ì¡´ì¬íë¤.\n\n### svg\n\n**ë¡ê³ , í
ì¤í¸, ìì´ì½ê³¼ ê°ì 기ííì ì¸ ëª¨ì**ì¼ë¡ 구ì±ë ì´ë¯¸ì§\u003cbr/\u003e\nëí, í´ìë ë° ë°°ì¨ì ë
립ì ì´ë¯ë¡ ë¤ìí í¬ê¸°ë¡ ííí´ì¼íë ê²½ì°ìë ì¢ë¤.\u003cbr/\u003e\u003cbr/\u003e\nì´ë¯¸ì§ê° ë³µì¡íì¬ svg ë§í¬ì
ìì´ ë§ìì§ë ê²½ì°ìë ì¬ì©íë©´ ì¢ì§ ìë¤.\n\n**ìµì í**\n\n- svg를 ìë¹í´ 주ë ìë²ìì svgì ëí gzip ì¤ì .\n- xmlë´ ë¶íìí ììë¤ ì ê±° / xml node 구조 ë³ê²½.\n - íë¬ê·¸ì¸ ìí¤í
ì²ë¡ ì´ë£¨ì´ì§ [SVGO](https://github.com/svg/svgo)(SVG Optimizer)ì íë¬ê·¸ì¸ 리ì¤í¸ë¤ì íì¸íë©´ ì´ë¤ í목ë¤ì ìµì íìí¬ ì ìëì§ ì ì ìë¤.\n\n```\nremoveDoctype\nremoveXMLProcInst\nremoveComments\nremoveMetadata\nremoveEditorsNSData\ncleanupAttrs\nmergeStyles\ninlineStyles\nminifyStyles\ncleanupIDs\nremoveUselessDefs\ncleanupNumericValues\nconvertColors\nremoveUnknownsAndDefaults\nremoveNonInheritableGroupAttrs\nremoveUselessStrokeAndFill\nremoveViewBox\ncleanupEnableBackground\nremoveHiddenElems\nremoveEmptyText\nconvertShapeToPath\nconvertEllipseToCircle\nmoveElemsAttrsToGroup\nmoveGroupAttrsToElems\ncollapseGroups\nconvertPathData\nconvertTransform\nremoveEmptyAttrs\nremoveEmptyContainers\nmergePaths\nremoveUnusedNS\nsortDefsChildren\nremoveTitle\nremoveDesc\n```\n\n### gif\n\n**ê°ë¨í ëí, ë¡ê³ , ë§í 그림ì²ë¼ ìì´ ë³ë¡ íì ìë ì´ë¯¸ì§ì ì ëë©ì´ì
ì íííê³ ì í ë**\u003cbr/\u003e\nì ëë©ì´ì
ííì loop, delayì ëí ì¤ì ì´ ì´ë¯¸ì§ ë´ì ì ì¥ë기 ë문ì ì¬ë¬ íê²½ìì í¸ë¦¬íê² ì¬ì©í ì ìë¤.\u003cbr/\u003e\u003cbr/\u003e\n무ìì¤ ìì¶ì í기 ë문ì íë ìì´ ë§ìì§ë©´ ì©ëë ë§¤ì° ë¹ëí´ì§ë¯ë¡, ì´ë´ ë ë¤ë¥¸ ë°©ìì íì©íëê² ì¢ë¤.\u003cbr/\u003e\nì¹ íì´ì§ê° 모ë ë¸ë¼ì°ì ë§ ì§ìí´ë ëë¤ë©´, `APNG`, `AVIF`를 ì¬ì©íëê² í¨ì¬ ì¢ì ì ìë¤.\u003cbr/\u003e\n(avifë edgeì safariììë ì§ìëì§ ìëë¤..)\n\n**ìµì í**\n\ngif를 ìµì í를 í ì ìë ë°©ë²ì.. **í´ìë ì¤ì´ê¸°, ì¬ì© ìì ì¤ì´ê¸°, ì ëë©ì´ì
íë ì ì¤ì´ê¸°**ì ê°ì ìì´ì ì¸ íì ë°ì ìëë°,\u003cbr/\u003e\nì´ë ì´ë¯¸ì§ì ííì ìëíëë¡ ì¬ì©ììê² ì ë¬í ì ìë ë°©ë²ì´ ìëë¤.\u003cbr/\u003e\n\n### jpeg\n\n**ì¬ì§ê³¼ ê°ì´ ë³µì¡í í¨í´ê³¼ ììì ê°ë ì´ë¯¸ì§**\u003cbr/\u003e\n**ì¹ íì´ì§ ì 체를 ë¤ë®ë ë°°ê²½ ì´ë¯¸ì§**\u003cbr/\u003e\nPC ì¹ì ë°°ê²½ ì´ë¯¸ì§ë ëë¶ë¶ ê³ í´ìëë¡ ëì´ ìëë° ì´ëì ë ì´ë¯¸ì§ ìì¤ì ê°ìíëë¼ë ì±ë¥ì ìí´ jpeg를 ì¬ì©íë ê²ì´ ì¢ë¤.\u003cbr/\u003e\u003cbr/\u003e\nê³ ì£¼í ì±ë¶ì´ ë§ì 문ì, ì , 격ì ë± ë¨ìì´ë ëë ·í ì¤ê³½ì ì ê°ì§ë ì´ë¯¸ì§ììë íì§ ì í(ëê°ì§, ë
¸ì´ì¦)ê° ë¤ì ëë ·íê²\në³´ì´ë íìì´ ìë¤. ì´ë¬í ì´ë¯¸ì§ë PNGì ê°ì ë¤ë¥¸ íìì ì¬ì©íì.\
16n\n\u003e 주íìë ì ì기íì 주íì를 ë§íë ê²ì´ ìëë¼, ë°ì´í°ë¥¼ 격ì ìì ëì´ ëìì ëì ê³µê°ì ì¸ ë³í를 ë§íë ê²\n\n**ìµì í**\n\n- ë¶íìí ë©íë°ì´í° ì ê±°.\n - **EX**changable **I**mage **F**ile, Adobe's **E**xtensible **M**etadata **P**latform ë±\n- jpeg í리í°ë¥¼ (ì ë¹í)ë®ì ê°ì¼ë¡ ì¤ì .\n - í리í°ê° ë®ìì§ë©´ ìì¤ì¨ì´ ì¬ë¼ê°ê¸° ë문ì ì ì¶©ì ì ì°¾ì ì¬ë¬ íì§ë¡ ìëíì.\n\n**ìì**\n\nìì ìµì í ë°©ë²ì´ ì ì©ë [tinyjpg](https://tinyjpg.com/)를 íµí ë¹êµìì\n\n| | orginal | compressed |\n| ----- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| Image | \u003cimg src=\"https://tinyjpg.com/images/jpg/example-original.jpg\" alt=\"https://tinyjpg.com/images/jpg/example-original.jpg\"/\u003e | \u003cimg src=\"https://tinyjpg.com/images/jpg/example-compressed.jpg\" alt=\"https://tinyjpg.com/images/jpg/example-compressed.jpg\"/\u003e |\n| Size | 614KB | 162KB |\n| ì¶ì² | https://tinyjpg.com/ |\n\n### png\n\n**문ì, ì , 격ì ë± ë¨ìì´ë ëë ·í ì¤ê³½ì ì ê°ì§ë ì´ë¯¸ì§**\u003cbr/\u003e\n**ìí ì±ëì ííí´ì¼ëë ì´ë¯¸ì§**\u003cbr/\u003e\n무ìì¤ ìì¶ì í기 ë문ì ì¹ììì ì´ë¯¸ì§ê° ì¶ê°ì ì¼ë¡ í¸ì§/ì ì¥ë ê°ë¥ì±ì´ ìì ê²½ì°ì ì¬ì©í´ë ì¢ë¤.\u003cbr/\u003e\nì ëë©ì´ì
ì ííí´ì¼ íë¤ë©´ íì¥ í¬ë§·ì¸ APNG íìì ì¬ì©í ìë ìë¤.\u003cbr/\u003e\u003cbr/\u003e\nì´ë¯¸ì§ì ì¬ì©ëì´ì§ë ììì´ ë§ì ê²½ì°, pngì ì©ëì´ ë¹ëí´ì§ ì ìì¼ë¯ë¡ ë¤ë¥¸ íìì ì¬ì©íì.\
16n\n**ìµì í**\n\n- ë¶íìí ë©íë°ì´í° ì ê±°.\n- ê° í½ì
ì íííë `color depth`(ì ì¬ë)를 8-bit indexed colorë¡ ì¤ì .\n\n**ìì**\n\nìì ìµì í ë°©ë²ì´ ì ì©ë [tinypng](https://tinypng.com/)를 íµí ë¹êµìì\n\n| | orginal | compressed |\n| ----- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |\n| Image | \u003cimg src=\"https://tinypng.com/images/example-orig.png\" alt=\"https://tinypng.com/images/example-orig.png\"/\u003e | \u003cimg src=\"https://tinypng.com/images/example-shrunk.png\" alt=\"https://tinypng.com/images/example-shrunk.png\"/\u003e |\n| Size | 57KB | 15KB |\n| ì¶ì² | https://tinypng.com/ |\n\n`color depth`(ì ì¬ë)ì ë°ë¥¸ ë¹êµìì\n\n| | 24 bit | 8 bit |\n| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |\n| Image | \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/9/9f/24_bit.png\" alt=\"https://upload.wikimedia.org/wikipedia/commons/9/9f/24_bit.png\"/\u003e | \u003cimg src=\"https://upload.wikimedia.org/wikipedia/commons/f/ff/8_bit.png\" alt=\"https://upload.wikimedia.org/wikipedia/commons/f/ff/8_bit.png\"/\u003e |\n| Size | 98KB | 37KB(-62%) |\n| ì¶ì² | https://en.wikipedia.org/wiki/Color_depth |\n\n## ë§ì¹ë©°\n\n1. ì´ë¯¸ì§ë¥¼ ì¬ì©íì§ ììë ëë ìí©ì´ë¼ë©´ ì¬ì© X.\n2. íííë 컨í
ì¸ ì ì í©í ìµì ì ì´ë¯¸ì§ íì ì í.\n3. ê° ì´ë¯¸ì§ íì
ì ë§ë ìµì í ì ì©.\n4. ì¹ íì´ì§ìì ë³´ì¬ì£¼ë ì´ë¯¸ì§ì í´ìëì ìµëí ëì¼í í´ìë를 ê°ì§ ë ì¤í° ì´ë¯¸ì§ ì ê³µ.\u003cbr/\u003e\n ê°ë¥íë¤ë©´ `srcSet`, `sizes` ìì±ì íµíì¬ ë°ìí ì´ë¯¸ì§ ì ê³µ.\n\n## References\n\n- https://en.wikipedia.org/wiki/Image_file_format\n- https://en.wikipedia.org/wiki/Rasterisation\n- https://en.wikipedia.org/wiki/Color_depth\n- https://web.dev/fast/#optimize-your-images\n- https://developer.mozilla.org/ko/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images\n","data":{"id":"image optimize","title":"ì´ë¯¸ì§ íì¼ ìµì í를 íµí ì¹ ì±ë¥ í¥ì","description":"ì¹ìì ì주 ì¬ì©ëì´ì§ë ì´ë¯¸ì§ì ëí´ ììë³´ê³ , ìµì í ì리ì ë°©ìì ëí´ ììë´
ëë¤.","preview":"ì¹ìì ì주 ì¬ì©ëì´ì§ë ì´ë¯¸ì§ì ëí´ ììë³´ê³ , ìµì í ì리ì ë°©ìì ëí´ ììë´
ëë¤.","keywords":"web, image, optimize, jpeg, jpg, png, gif, svg","slug":"image-optimize","createdAt":"2021.12.12","published":true},"filePath":"image-optimize.mdx"},{"content":"\nì»´í¬ëí¸ ì ìì ë§ì§ë§ì¸ ì´ë² í¬ì¤í
ì,\nnpmì publishíë ê³¼ì ê³¼ ê´ë¦¬ì ëí´ ë¤ë£¨ê³ ì íë¤.\n\n[react-simple-image-slider](https://github.com/kimcoder/react-simple-image-slider)를 ì ìíë©´ì ì°ë í¬ì¤í
.\n\n## npm\n\nnpmì 먼ì ë°°í¬ë¥¼ íê³ ìíë ¤ë©´ ê³ì ì´ ìì´ì¼ íë¤.\u003cbr/\u003e\n[npm](https://www.npmjs.com)ì 방문íì¬ ê°ì
ì 먼ì íì.\u003cbr/\u003e\nê·¸ë¦¬ê³ ìëì ê°ì ë¨ê³ë¥¼ ê±°ì¹ë©´ ìì½ê² ë°°í¬í ì ìë¤.\n\n### npm init\n\nìë ëª
ë ¹ì´ë¥¼ íµí´ package.jsonì 기본 ì ë³´ë¤ì ì´ê¸°íí ì ìë¤.\u003cbr/\u003e\nì´ë¯¸ npm packageê° ì¡´ì¬íë ëë í 리ììë ì¤íì´ ê°ë¥íë©°,\u003cbr/\u003e\në¹ì´ìë ëë í 리ìì ëª
ë ¹ì´ë¥¼ ì¤íí´ë ê°ë¥íë¤.\u003cbr/\u003e\n( ë¨, ì´ë¯¸ package.jsonì´ ì¡´ì¬íë¤ë©´ ì
ë ¥ë°ë ì ë³´ë¤ì overwrite íê² ëë¤. )\n\n```js\nnpm init\n```\n\nìì í°ë¯¸ëì ëª
ë ¹ì´ë¥¼ ì
ë ¥íë©´, ìëì ê°ì ìì¼ë¡ ë°ì´í° ì
ë ¥ì ë°ëë¤.\u003cbr/\u003e\n\n- package name\n- ver
16sion\n- description\n- git repository\n- keywords\n- author\n- license\n\nì¬ê¸°ì ê°ë°í ì»´í¬ëí¸ì package.jsonì ììë¡ íì¸í´ë³´ì.\n\n```js\n{\n \"name\": \"react-simple-image-slider\",\n \"version\": \"1.0.2\",\n \"description\": \"simple image slider component for react\",\n \"main\": \"dist/ImageSlider.js\",\n \"scripts\": {\n \"example\": \"webpack-dev-server --inline --mode development\",\n \"build\": \"rollup -c\",\n \"build:watch\": \"rollup -c --watch\"\n },\n \"keywords\": [\n \"reactjs\",\n \"react\",\n \"react-component\",\n \"react gallery\",\n \"react slider\",\n \"image gallery\",\n \"image slider\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/kimcoder/react-simple-image-slider.git\"\n },\n \"author\": {\n \"name\": \"kimcoder\",\n \"email\": \"[email protected]\"\n },\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/kimcoder/react-simple-image-slider/issues\"\n },\
16n \"homepage\": \"https://github.com/kimcoder/react-simple-image-slider#readme\",\n \"dependencies\": {\n ...\n },\n \"devDependencies\": {\n ...\n }\n}\n```\n\nì¬ê¸°ì í¬ê² ë¶ê°ì ì¸ ì¤ëª
ì´ íìí ê² ê°ì§ ìì§ë§ ì¡°ê¸ ì ê²½ì¨ì¼ í ë¶ë¶ì´ ìë¤ë©´,\u003cbr/\u003e\nì»´í¬ëí¸ ì ìì `dependencies`ì `devDependencies`를 ì 구ë¶íì¬ ëª¨ëì ì¤ì¹íê³ ìì
ì í´ì¼íë¤.\u003cbr/\u003e\në°°í¬ê° ë íìê° ìê³ ì»´í¬ëí¸ ê°ë°ìë§ íìí 모ëë¤ì `devDependencies`ë¡ ì¤ì¹ë¥¼ í´ì£¼ì´ì¼ íë¤.\u003cbr/\u003e\n\n### npm ignore\n\ngitê³¼ ë§ì°¬ê°ì§ë¡ npmìë í¹ì ëë í 리, íì¼ë¤ì ignore í ì ìë¤.\u003cbr/\u003e\n\n```js\n.DS_Store\n.vscode\n.git*\n\nexample\nnode_modules\nnpm-debug.log\nyarn-debug.log\nyarn-error.log\n```\n\nì´ê²ì ìì íê²½ì ë°ë¼ ë¤ë¥´ê² ì§ë§, 기본ì ì¼ë¡ ì»´í¬ëí¸ ì¬ì©ììë§ íìí íì¼ë¤ì 기ì¤ì¼ë¡ ë°°í¬íì.\u003cbr/\u003e\nê°ë°ì ì¬ì©íìë í
ì¤í¸ë ìì , 모ëë¤, ë¡ê·¸ ë±ì íì¼ë¤ì íìê° ìì¼ë ì¶ê°í´ì£¼ì.\n\n### npm adduser\n\në°°í¬ ì , ìëì ê°ì npm cli를 íµí´ ë¡ê·¸ì¸ì í´ì£¼ëë¡ íì.\n\n```js\nnpm adduser\n```\n\në¡ê·¸ì¸ì´ ìë£ëë©´ ìëì ê°ì´ **Logged in as ì ì **ë¼ë ë©ìì§ë¥¼ ë³¼ ì ìì ê²ì´ë¤.\u003cbr/\u003e\u003cbr/\u003e\n\n\u003cimg src='/assets/images/react-component-3-adduser.png' alt='npm adduser' /\u003e\n\n### test for npm publish\n\ní
ì¤í¸ë ì¤ì npm installì íµíì¬ íë ê²ì´ ì¢ë¤.\u003cbr/\u003e\në¬¼ë¡ , ìì§ ë°°í¬ë¥¼ íì§ ìì기 ë문ì ìëì ê°ì´ ì»´í¬ëí¸ì 루í¸ëë í 리 ê²½ë¡ë¥¼ íµí´ ì¤ì¹í´ë³´ì.\u003cbr/\u003e\n\n```\nnpm install /Users/KIMCODER/Documents/react-simple-image-slider/\nor\nnpm install ../react-simple-image-slider/\n```\n\nì¤ì ì»´í¬ëí¸ë¥¼ ì¬ì©íë íê²½ìì importíì¬ ì ìì ì¼ë¡ ì¬ì©ì´ ê°ë¥íë¤ë©´, ë°°í¬í´ë ì¢ì ê²ì´ë¤.\u003cbr/\u003e\n\n#### npm publish\n\në°°í¬ë¥¼ ìí ëª
ë ¹ì´ë ìëì ê°ë¤.\n\n```\nnpm publish\n```\n\npackage.jsonì versionì ë°ë¼ ë°°í¬ê° ëë©°, ë§ì½ ìµì´ë°°í¬ê° ìë ê²½ì°ë versionì ì
ê·¸ë ì´ëíì¬ publish를 íë©´ ëë¤.\u003cbr/\u003e\në°°í¬ê° ì ìì ì¼ë¡ ìë£ê° ëë©´, `https://www.npmjs.com/package/ì´ë¦`ì URLìì íì¸í ì ìë¤.\u003cbr/\u003e\nëë, `https://www.npmjs.com/settings/${ê³ì ìì´ë}/packages`ììë íì¸ì´ ê°ë¥íë¤.\u003cbr/\u003e\u003cbr/\u003e\nnpmì 모ë ë°°í¬ë¥¼ ì§ì í ë² ê²½í
16ì í´ë³´ë©´ ì´ë µì§ìë¤ë ê²ì ëë ì ìë¤.\u003cbr/\u003e\n\n### Git\n\nì¶ê°ì ì¼ë¡ npm ì¸ì git ê´ë ¨ ë´ì©ë ì¡°ê¸ ë¤ë£¨ì´ë³´ì.\u003cbr/\u003e\nnpmê³¼ gitì ìì¤ë 기본ì ì¼ë¡ ëì¼í ë²ì ì¼ë¡ ê´ë¦¬ê° ëì´ì¼ íë¤.\u003cbr/\u003e\níì§ë§, gitìì ignore ëìì ì¡°ê¸ ë¤ë¥¼ ì ìë¤.\u003cbr/\u003e\nnpmììë ì¬ì©ëë ì¤ì¬ì¼ë¡ ìì¤ê° ë°°í¬ëì´ì¼ íë¤ë©´, gitì ì»´í¬ëí¸ ê°ë°ì¤ì¬ì ìì¤ê° ë°°í¬íëë¡ íì.\u003cbr/\u003e\nnpmê³¼ githubì ìí ì ëí´ ìê°íë©´ ì¶©ë¶í ë©ëì´ ê°ë¥íë¦¬ë¼ ììíë¤.\u003cbr/\u003e\n\n[CHANGELOG.md](https://github.com/kimcoder/react-simple-image-slider/blob/master/CHANGELOG.md)를 ìì±íì¬ ë²ì ë³ë¡ ì´ë¤ ê²ë¤ì´ ë°ëëì§ì ëí´ ê¸°ë¡íë©´ ì¢ì ê² ê°ë¤.\n\n## ë§ì¹ë©°\n\nì»´í¬ëí¸ ì ìì 결과물ì [Git repository](https://github.com/kimcoder/react-simple-image-slider)ìì íì¸í ì ìì¼ë©° [NPM Package](https://www.npmjs.com/package/react-simple-image-slider)ììë ë³¼ ì ìë¤.\u003cbr/\u003e\nê±°ì°½í 모ë, ì»´í¬ëí¸ê° ìëëë¼ë ê°ë°ìë¤ì´ ê¼ í ë²ì¯¤ì ê²½ííë©´ ì¢ì ê² ê°ë¤ :)\n\n## References\n\n- https://www.npmjs.com/\n- https://docs.npmjs.com/getting-started/publishing-npm-packages\n- https://docs.npmjs.com/cli/publish\n- https://github.com/kimcoder/react-simple-image-slider\n- https://www.npmjs.com/package/react-simple-image-slider\n","data":{"id":"react-simple-image-slider-3","title":"React ì»´í¬ëí¸ ì ì기 3 / 3","description":"react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.","preview":"react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.","keywords":"react, component, react carousel, image slider, npm","slug":"react-simple-image-slider-3","createdAt":"2018.10.11","published":true},"filePath":"react-simple-image-slider-3.mdx"},{"content":"\nì´ë² í¬ì¤í
ì ë´ì©ì ë¹êµì ê°ë¨íë¤.\n\nì»´í¬ëí¸ë¥¼ ì ìì ì¤ì ë¡ ê³ ë ¤í´ì¼ ëë ë¶ë¶ë¤ì ëíì¬ ì°ê³ ì íë¤.\n[react-simple-image-slider](https://github.com/kimcoder/react-simple-image-slider)를 ì ìíë©´ì ì°ë í¬ì¤í
.\n\n## ì»´í¬ëí¸ ì ìì ê³ ë ¤í ì¬í\n\n1. ì¬ì©ëª©ì ì ë§ë ë¤ìí íê²½ììì ì ê·¼ì±ì ê³ ë ¤.\n2. 캡ìí ë° ì¤ì ê°ë° ì½ëìììì ì¬ì©ì± ê³ ë ¤.\n3. ì¸ë¶ì ì¸ ìì¸ì ìí ë¶ìì© ë°©ì§.\n\nì»´í¬ëí¸ê° ì´ë¤ ì¢
ë¥ì ê²ì¸ì§, ì´ë¤ í¹ì§ë¤ì´ ìëì§ì ëí´ ë¨¼ì ìê°í´ ë³´ìì¼íë©°,\u003cbr/\u003e\nì´ ì»´í¬ëí¸ë¥¼ ì¤ì ì¬ì©íë ì¬ë¬ ê°ë°ìë¤ì ê°ë° íê²½ì ê³ ë ¤í´ì£¼ì´ì¼ íë¤.\u003cbr/\u003e\nì¬ê¸°ìë React ì»´í¬ëí¸ë¥¼ ì ì í 기ë¡íë í¬ì¤í
ì´ê¸° ë문ì, ì´ë¯¸ 모ë ê³ ë ¤ëë¶ë¶ì´ë¼ í ì ìê² ë¤.\u003cbr/\u003e\në, ì»´í¬ëí¸ ìì¤ì 캡ìíê° ì ëì´ìì´, ë
립ì ì¼ë¡ í¹ì 기ë¥ë¤ì´ ì¤íëëì§, ì¸ë¶ìì¸ì ìí¥ì ë°ê±°ë ë¼ì¹ë ë±ì ë¶ìì©ì ë°©ì§íëì§, ë¤ë¥¸ ê°ë°ìë¤ìê² í¸ë¦¬í ì¸í°íì´ì¤ê° ì ê³µëëì§ ë±ì ìê°í´ë³´ìì¼ íë¤.\u003cbr/\u003e\n\në¬¼ë¡ , ì»´í¬ëí¸ì ì±ê²©ì´ë ì¢
ë¥ì ë°ë¼ ì°¨ì´ê° ìê² ì§ë§, ìë§ ëë¶ë¶ ìì ì¬íë¤ì ê³ ë ¤í´ì¼íì§ ììê¹ ì¶ë¤.\n\n## ì»´í¬ëí¸ ê¸°ë¥ ì ì\n\në´ê° ì¬ê¸°ì ë§ë¤ê³ ìíìë ê²ì \u003cb\u003eì´ë¯¸ì§ì¬ë¼ì´ë\u003c/b\u003eìë¤.\u003cbr/\u003e\n\nì¬ì¤ íë¡ í¸ìëê°ë°ìë¼ë©´ ì´ë¯¸ì§ì¬ë¼ì´ëë ë§¤ì° ë§ì´ ì í´ë³´ìì ê²ì´ê³ , ì¸ë¶ëª¨ëì ê°ì ¸ë¤ì°ê¸°ëíë©°, ì§ì ê°ë°íì¬ ìì
í ì ë ë§ì´ ìì ê²ì´ë¤. ì´ë¯¸ì§ì¬ë¼ì´ë를 ì ìíê³ ì ë§ìì 먹ì ì´ì ë, ì¸ë¶ëª¨ëì ê°ì ¸ë¤ì°ëë° ìì¬ìì´ ìì´ ì¤ì ë¡ ì ìíì¬ ë°°í¬ë¥¼ í´ë³´ë©´ ì¢ì ê² ê°ë¤ê³ ìê°íìë¤.\u003cbr/\u003e\u003cbr/\u003e\në§ë¤ê³ ìí ë, ê°ì¥ ì¼ëì ëìë ì¬íë¤ì ìëì ê°ìë¤.\u003cbr/\u003e\n\n- íì¬ ì¸ë±ì¤ì ë§ê²
16 ë¤ì ì¸ë±ì¤ì ì´ë¯¸ì§ë¥¼ ì¬ì ì ë¡ë.\n- ì¬ë¼ì´ë를 ì ì ì¸ í¬ê¸°ë¡ ì§ì íë©´ ì´ë¯¸ì§ë ë¹ì¨ì ë§ì¶° ì ë³´ì´ëë¡.(ì´ë¯¸ì§ì í¬ê¸°ì ìê´ìì´)\n- 2ê°ì ê°ì²´ë¥¼ íì©íì¬ ì¬ë¼ì´ë ì´ë¯¸ì§ë¤ íí.\n- ê·¸ ì¸ ê¸°ë³¸ì ì¸ ì¬íë¤ ì§ì.\n - ë¤ë¹ê²ì´ì
ì ì 무\n - bullet ë¤ë¹ê²ì´ì
ì ì 무\n - GPU ë ëë§ ì§ì ì 무\n - ì¬ë¼ì´ë© ìë ì¡°ì .\n - ì¬ë¬ ì´ë²¤í¸ì ëí ì½ë°± í¨ì.\n\n## PropsTypes를 íì©íì¬ React Component Prop ì²´í¬\n\nì»´í¬ëí¸ë¥¼ ì ìíê³ ë°°í¬íë ì
ì¥ììë,\u003cbr/\u003e\nì¬ì©íë ê°ë°ìë¤ì´ ì íí ê°ì ì ë¬íëë¡íì¬ ì¤ë¥ìì´ ì»´í¬ëí¸ì 기ë¥ë¤ì ì¬ì©íê²ë í´ì¼íë¤.\u003cbr/\u003e\n\nì´ë `prop-types`를 ì¬ì©íì¬ í´ê²° í ì ìëë°,\u003cbr/\u003e\n`ReactComponent` \u003cb\u003ePropsì ì í¨ì± ê²ì¬ ë° ê¸°ë³¸ ê° ì§ì , íì
ì²´í¬\u003c/b\u003e를 í ì ìê² í´ì¤ë¤.\u003cbr/\u003e\n`prop-types`ë react v15.5ë¶í°ë ë³ëë¡ ì¤ì¹ë¥¼ í´ì£¼ì´ì¼íë¤. ( npm ë±ì íµí´ ì¤ì¹íì )\u003cbr/\u003e\u003cbr/\u003e\nì´ë¤ ê°ë¤ì´ íìì ì¼ë¡ ì ë¬ëì´ì¼ íëì§, ì íì ì¼ë¡ ì ë¬ëì´ì¼ íëì§, ë 기본 ê°ì ìëì§ë¥¼ 구ë¶ì§ì´ë³´ì.\u003cbr/\u003e\nê²°ê³¼ì ì¼ë¡ ìëì ê°ì´ ì»´í¬ëí¸ í´ëì¤ì propTypesì defaultProps ì§ì íë©´ ëë¤.\n\n```js\nimport React from \"react\";\nimport PropTypes from \"prop-types\";\n...\n\nclass SimpleImageSlider extends React.Component {\n ...\n}\n\nSimpleImageSlider.propTypes = {\n // Required\n width: PropTypes.number.isRequired,\n height: PropTypes.number.isRequired,\n images: PropTypes.arrayOf(PropTypes.shape({\n url: PropTypes.string.isRequired,\n })).isRequired,\n\n // Optional\n style: PropTypes.objectOf(PropTypes.string),\n slideDuration: PropTypes.number,\n showNavs: PropTypes.bool,\n showBullets: PropTypes.bool,\n bgColor: PropTypes.string,\n useGPURender: PropTypes.bool,\n onClickNav: PropTypes.func,\n onClickBullets: PropTypes.func,\n onStartSlide: PropTypes.func,\n onCompleteSlide: PropTypes.func,\n\n // Optional, Navigation Arrow Style\n navStyle: (props, propName, componentName) =\u003e {\n if (!isValidNavStyle(props[propName])) {\n return new Error(`Invalid prop ${propName} supplied to ${componentName}. Validation failed.`);\n }\n return null;\n }\n};\n\nSimpleImageSlider.defaultProps = {\n slideDuration: 0.5,\n showNavs: true,\n showBullets: true,\n bgColor: \"#000000\",\n useGPURender: true,\n navStyle: 1\n};\n```\n\nì´ì ìì ë´ì©ì readme í¹ì ë¤ë¥¸ 문ìì ìëì ê°ì´ ì ì를 í´ì£¼ì.\u003cbr/\u003e\nì´ë¬í ìì
ë¤ì ì»´í¬ëí¸ë¥¼ ì¬ì©í ê°ë°ìë¤ìê² ì¢ì ì¬ì©ì±ì ì ê³µí´ì¤ ê²ì´ë¤.\u003cbr/\u003e\në, ê³ íì§ì ì»´í¬ëí¸ì ì¡°ê±´ ì¤ ì¼ë¶ë¼ê³ ìê°íë¤.\u003cbr/\u003e\n\n| Name | Type | Required | Description | Default |\n| ------------------- | ---------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |\n| **width** | `Number` | `Required` | Image Slider Width | |\n| **height** | `Number` | `Required` | Image Slider Height | |\n| **images** | `Array` | `Required` | Images,\u003cbr/\u003eArray Elements should be like this structure,\u003cbr/\u003e{ url: \"\" } | |\n| **style** | `String` | `Optional` | css object | |\n| **slideDuration** | `Number` | `Optional` | css transition-duration property | `0.5` |\n| **navStyle** | `Number` | `Optional` | Arrow Navgation Style,\u003cbr/\u003e1 or 2 | `1` |\n| **showNavs** | `Boolean` | `Optional` | Toggle Arrow Navgation | `true` |\n| **showBullets** | `Boolean` | `Optional` | Toggle Bullets | `true` |\n| **useGPURender** | `Boolean` | `Optional` | Toggle GPU Render | `true` |\n| **bgColor** | `String` | `Optional` | slider container's css background-color property | `#000000` |\n| **onClickNav** | `Function` | `Optional` | Arrow Navigation Callback function,\u003cbr/\u003e`onClickNav = (toRight) =\u003e { }`\u003cbr/\u003etoRight : Boolean : slide direction | |\n| **onClickBullets** | `Function` | `Optional` | Bullets Callback function,\u003cbr/\u003e`onClickBullets = (idx) =\u003e { }`\u003cbr/\u003eidx : Number : clicked bullet index (begin from 0) | |\n| **onStartSlide** | `Function` | `Optional` | Slide Transition Start function,\u003cbr/\u003e`onStartSlide = (idx, length) =\u003e { }`\u003cbr/\u003eidx : Number : start index (begin from 1)\u003cbr/\u003elength : Number : image length | |\n| **onCompleteSlide** | `Function` | `Optional` | Slide TransitionEnd Callback function,\u003cbr/\u003e`onCompleteSlide = (idx, length) =\u003e { }`\u003cbr/\u003eidx : Number : start index (begin from 1)\u003cbr/\u003elength : Number : image length | |\n\n[Props ì ì Gitubìì 보기](https://github.com/kimcoder/react-simple-image-slider)\n\n## Typescript를 ìí index.d.ts\n\nTypescript ê°ë° íê²½ë ê³ ë ¤íì¬ index.d.tsíì¼ì ì»´í¬ëí¸ ë£¨í¸ ê²½ë¡ì ìì±íì¬ ìëì ê°ì´ ìì±íì.\u003cbr/\u003e\níì¼ëª
ì dë ì¼ë°ì ì¼ë¡ declareì ì½ìë¡ íííì¬ ì¬ì©íê³ , ì´ íì¼ì Typescriptìì\u003cbr/\u003e\ní¹ì 모ë, ì¸í°íì´ì¤, ë³ì ë±ì ëí íì
ì ì¸ì
16 íë ìí ì íë¤.\u003cbr/\u003e\nì»´í¬ëí¸ì ê°ì´ ê°ë°ìê° ì»¤ì¤í
íì¬ ì ìí ì»´í¬ëí¸ í´ëì¤ë Typescriptìì ì¸ìì íì§ ëª»í기 ë문ì,\u003cbr/\u003e\nìëì ê°ì´ index.d.tsë¼ë íì¼ì íµí´ ì ì¸ì í´ì£¼ì´ì¼ íë¤.\n\n```js\nimport * as React from 'react';\n\n// RSIS = React Simple Image Slider\nexport interface RSISImage {\n url: string;\n}\n\nexport interface RSISProps {\n width: number;\n height: number;\n images: RSISImage[];\n\n style?: CSSStyleDeclaration;\n slideDuration?: number;\n showNavs?: boolean;\n showBullets?: boolean;\n bgColor?: string;\n useGPURender?: boolean;\n navStyle?: 1 | 2;\n onClickNav?: (toRight: boolean) =\u003e void;\n onClickBullets?: (idx: number) =\u003e void;\n onStartSlide?: (current: number, length: number) =\u003e void;\n onCompleteSlide?: (current: number, length: number) =\u003e void;\n}\n\ndeclare class ReactSimpleImageSlider extends React.Component\u003cRSISProps\u003e {}\n\nexport default ReactSimpleImageSlider;\n```\n\nindex.d.tsíì¼ì ì»´í¬ëí¸ ëë í 리ì ì¶ê°íì§ ìê³ ë [@types/í¨í¤ì§](https://github.com/DefinitelyTyped/DefinitelyTyped)를 ì¶ê°íì¬ í´ê²°í ìë ìë¤.\u003cbr/\u003e\n( ì´ ê²½ì° ì¬ì©íë ê°ë°ìê° npmìì `@types/í¨í¤ì§`ì ë³ëë¡ ì¤ì¹í´ì£¼ì´ì¼ íë¤. )\n\n## ë§ì¹ë©°\n\nì¬ê¸°ê¹ì§ì ê³¼ì ë¤ì [Git Repository](https://github.com/kimcoder/react-simple-image-slider)ìì íì¸í ì ìë¤.\u003cbr/\u003e\n\nReact ì»´í¬ëí¸ì 구í ìì¤ë ì¬ì¤ React를 ì¡°ê¸ ë¤ë£¨ì´ë³´ìë¤ë©´ í¬ê² ì´ë ¤ì´ ë¶ë¶ì ìëë¤.\u003cbr/\u003e\nê·¸ë¬íì¬ í¬ì¤í
ì 주ë ë´ì©ì ì´ë¤ ê²ë¤ì ê³ ë ¤í´ì ê°ë°í´ì¼ íëì§, ì¢ì ì¬ì©ì±ê³¼ ëì íì§ì ì»´í¬ëí¸ë¥¼ ë§ë¤ë ¤ë©´ ì´ë¤ ê²ë¤ì ìê°í´ë³´ìì¼ íëì§ë¡ ì ì íìë¤.\u003cbr/\u003e\nì¬ì¤ ë¶ì¡±í ë¶ë¶ì´ ë§ê² ì§ë§ ì주 ë§ì´ëíê³ ì¬íí ì»´í¬ëí¸ì´ê¸° ë문ì ìµëí ê°ëµí ì 리를 í´ë³´ìë¤.\n\n## References\n\n- https://reactjs.org/docs/typechecking-with-proptypes.html\n- http://definitelytyped.org/\n","data":{"id":"react-simple-image-slider-2","title":"React ì»´í¬ëí¸ ì ì기 2 / 3","description":"react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.","preview":"react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.","keywords":"react, component, react carousel, image slider, npm","slug":"react-simple-image-slider-2","createdAt":"2018.10.08","published":true},"filePath":"react-simple-image-slider-2.mdx"},{"content":"\nreact ì»´í¬ëí¸ ì ìë¶í° ë°°í¬ê¹ì§ì ê³¼ì ì ë¤ë¤ë³´ê³ ì íë¤.\n\nì´ë² í¬ì¤í
ì ì»´í¬ëí¸ ì ìì ìí íê²½ êµ¬ì¶ ê³¼ì ê¹ì§ í ìì ì´ë¤.\n[react-simple-image-slider](https://github.com/kimcoder/react-simple-image-slider)를 ì ìíë©´ì ì°ë í¬ì¤í
.\n\n## React ì»´í¬ëí¸ ì ìì ìí íê²½ 구ì¶\n\nì¸ë¶ì ì¸ ë´ì©ì íì¸í기 ì ì, ëëµì ì¼ë¡ íìí ê²ë¤ì ì 리í´ë³´ì.\n\n1. **React ì»´í¬ëí¸ ëª¨ë ë²ë¤ ë구 ì¤ì **.\n2. jsx, ES6 ì´ìì ë¬¸ë² ë± ëª¨ëí 문ë²ì íµí´ ê°ë°ì í ìì ì´ë¯ë¡, ì´ë¥¼ ìí **babel ì¤ì **.\n3. ìì
íë ì»´í¬ëí¸ ë°°í¬ ì , **ì¤ì í
ì¤í¸ íê²½ ì¤ì **.\n4. ì½ë 컨벤ì
ì ì©ì ìí eslint ì¤ì ë± ê¸°í íì íë¬ê·¸ì¸ë¤ ì¤ì¹.\n\nëëµ ì 리를 í´ë³´ë©´ ìì ê°ì§ë§, ì¬ì¤ ì¤ì í ì¼ë¤ì 그리 ë§ì§ ìë¤.\n\n### 1. rollup\n\nëë ê·¸ëì ê°ë°ì í´ì¤ë©´ì `gulp`ì `webpack` ì´ 2ê°ì§ë¥¼ ì¬ì©í ê²½íì´ ìë¤.\níì§ë§, ì´ë² ì»´í¬ëí¸ ì ìì `rollup`ì´ë¼ë ë²ë¤ ë구를 ì¬ì©í ìì ì´ë¤.\n리ì¡í¸ë¥¼ ì ìí íì´ì¤ë¶ììë rollupì¼ë¡ íì¬ ë¹ë를 íê³ ìê³ ,\n\n[Webpack and Rollup: the same but different](https://medium.com/webpack/webpack-and-rollup-the-same-but-different-a41ad427058c)ë ì 목ì ì¬ë°ë ê¸ì ì½ì ì´ì ë ìë¤.\n\nì´ ê¸ìì `Use webpack for apps, and Rollup for libraries`êµ¬ë¬¸ì´ ëì ë¤ì´ìë¤.\
16n\në, rollupì `react`, `vue`, `ember`, `D3`, `ThreeJs` ë±ììë ì¬ì©íë ëêµ¬ë¡ ìê°ë¥¼\níê³ ìì¼ë, ì´ì ëë©´ í ë² ê²½íí´ ë³¼ ë§í ê°ì¹ë ì¶©ë¶í ê²ì´ë¤.\n\n[Rollup ê³µìííì´ì§](https://rollupjs.org/guide/en#quick-start)ì ìê°ë¥¼ ë³´ë©´, `rollup`ì ìê±°ë í° ë¨ì ì¡°ê°ì ì½ë, í¹ì ë¼ì´ë¸ë¬ë¦¬ë ì í리ì¼ì´ì
ê³¼ ê°ì´ ë ë³µì¡í ì¡°ê°ë¤ì ì½ëë¤ì ì»´íì¼í´ì£¼ë ëêµ¬ë¡ ìê°ëì´ ìë¤. ëí, ES6, CommonJS, AMDì ê°ì ë°©ìë¤ì 모ë ì ì íê²½ì 모ë ì§ìíë¤.\n\n**install**\n\nì ìíê³ ìíë ì»´í¬ëí¸ ëë í 리를 ìì± í, ì¤ì¹ë¥¼ í´ì£¼ì.\n\n```js\nmkdir react-simple-image-slider\ncd react-simple-image-slider\n\n..\n( npm initì íµí´ package.jsonì ìì± )\n..\n\nnpm install rollup rollup-plugin-babel --save-dev\n```\n\nììì ì¤ëª
íëëë¡ babelì ì¬ì©í ìì ì´ë¯ë¡ pluginë ì¤ì¹ë¥¼ ê°ì´ í´ì¤ë¤.\nbabelì ëí ìì¸í ì¤ì ì ìëìì ë¤ì ë¤ë£¨ê² ë¤.\n\n**rollup.config.js**\n\nrollup config íì¼ì ìëì ê°ì´ ìì±íìë¤.\n\n```js\nimport babel from 'rollup-plugin-babel';\nimport pkg from './package.json';\n\nconst external = (id) =\u003e !id.startsWith('/') \u0026\u0026 !id.startsWith('.');\n\nexport default {\n input: './src/ImageSlider.jsx',\n output: {\n file: pkg.main,\n format: 'cjs',\n },\n plugins: [babel({ runtimeHelpers: true })],\n external,\n};\n```\n\n- input : ë²ë¤ë§ í ìì¤ì index íì¼ì path.\n- output : ë²ë¤ë§ 결과물 íì¼ì pathì 모ë ë°©ì. ( cjsë CommonJSë°©ì )\n- plugins : íìí íë¬ê·¸ì¸ë¤ ì§ì . ( ì´ê¸°ìë babel pluginë§ ì¶ê° )\n- external : ìì¤ìì importíë 모ëë¤ì´ ì¸ë¶ ìì¡´ì ì¸ ëª¨ë ì§ì .\n\në§ì½, externalìì ì¸ë¶ ìì¡´ì±ì´ ìë 모ëì´ë¼ë©´ í´ë¹ 모ëì ë²ë¤ë§ì í¬í¨íì§ ìê² ëë¤.\nì를 ë¤ì´ ì§ê¸ì react ì»´í¬ëí¸ë¥¼ ì ìíë ê²ì´ë¯ë¡ reactjsì ê°ì 모ëì npmì¼ë¡ ì¤ì¹íì¬ importíì¬ ì¬ì©ì íê² ë ê²ì´ë¤.\nì¬ê¸°ì ì´ë¬í externalí ì¸ë¶ 모ëë¤ì ë²ë¤ë§ 결과물ì í¬í¨ì´ ëì§ ìëë¤.\n\n```js\nexternal: ['react'];\n```\n\nìì ê°ì´ ì§ì 모ëëª
ì ìì±í´ì£¼ì´ë ëì§ë§, ì¸ë¶ 모ëë¤ì´ ë§ìì§ë©´ ë²ê±°ë¡ê² ë¤ ì§ì í´ì£¼ì´ì¼ í기 ë문ì, í¨ì를 íë ìì±íì¬ ì²ë¦¬í´ì£¼ìë¤.\nìëì ê°ì´ importíë 모ëë¤ì ê²½ë¡ë¥¼ 기ì¤ì¼ë¡ íë¨íë©´ ì½ê² ì¸ë¶ 모ëì¸ì§ íì¸ì´ ê°ë¥íë¤.\n\n```js\nimport React from 'react';\nimport ImageSliderPropTypes from './ImageSliderPropTypes';\nimport ImagePreLoader from './ImageSliderPreLoader';\n```\n\n**package.json**\n\nscriptsì rollup ëª
ë ¹ì´ë¥¼ ìëì ê°ì´ ì¶ê°í´ì¤ë¤.\n\n```js\n{\n \"scripts\": {\n \"build\": \"rollup -c\",\n \"build:watch\": \"rollup -c --watch\"\n }\n}\n```\n\n`-c` flagë `--config`ì ëì¼íë©°, configíì¼ëª
ì´ `rollup.config.js`ì¼ ê²½ì°, íì¼ëª
ì ì ì§ ììë ëë¤.\n`--config` ë¤ì íì¼ëª
ì ì ì´ í¹ì íì¼ì ì¤ì ì 참조í ì ë ìë¤.\në, watch flagì íµí´ ìì¤ ë³ê²½ìë§ë¤ ë²ë¤ë§ì´ ëê² í´ì¤ë¤.\n\n### 2. babel\n\nbabelì ëí´ì ë°ë¡ ì¤ëª
ì íì§ ìê² ì¼ë, ê°ëµíê² ë§íìë©´ ES2015+ ìë°ì¤í¬ë¦½í¸ ì½ë를 구í ë¸ë¼ì°ì , íê²½ìì ì ì©í ì ìê² í´ì£¼ë ì»´íì¼ë¬ì´ë¤.\nbabelì ë²ì ì´ ë°ëë©´ì ì
í
ê°ë¤ì´ ë°ëë ë¶ë¶ì´ ìì¼ë¯ë¡ ê¼ [Babel ê³µìííì´ì§](https://babeljs.io/docs/en/)ìì íìí ë¶ë¶ì íì¸íì.\u003cbr/\u003e\n\n**install**\n\nì¤ì¹í´ì¼ í 리ì¤í¸ë ìëì ê°ë¤.\n\n- @babel/core : babel.\n- @babel/preset-env : babel presetì ì§ì í ì ìê² í´ì£¼ë 모ë. ( babel7ë¶í° ì¬ì© )\n- @babel/preset-react : babel react preset.\n- @babel/plugin-proposal-class-properties : Classìì ë©¤ë² ë³ì ê´ë ¨ 문ë²ì ìí íë¬ê·¸ì¸.\n- @babel/plugin-transform-runtime : ì»´í¬ëí¸ ìì¤ ì¤ íìí ë¶ë¶ë§ polyfill ì ì©ì ìí íë¬ê·¸ì¸.\n- @babel/polyfill : í
ì¤í¸ íê²½ App ë¹ëì ì¬ì© ë polyfill.\n- babel-loader : í
ì¤í¸ íê²½ì ìí webpack ì¤ì ì ì¸ babel loader.\n\nìì 리ì¤í¸ë¤ì 모ë ì¤ì¹í´ì£¼ì.\n\n```js\nnpm install ... --save-dev\n```\n\n**.babelrc**\n\nbabelì ì¤ì ì ìëì ê°ì´ í´ì¤ë¤.\n\n```js\n{\n \"presets\": [\n [\"@babel/preset-env\", {\n \"loose\": true,\n \"modules\": false,\n \"targets\": \"\u003e 0.25%, not dead\"\n }
16],\n \"@babel/preset-react\"\n ],\n \"plugins\": [\n \"@babel/plugin-transform-runtime\",\n \"@babel/plugin-proposal-class-properties\"\n ]\n}\n```\n\nì´ë¤ presetê³¼ pluginë¤ì ì¸ ê²ì¸ì§ ëª
ìë§ í´ì£¼ë©´ ëë¤.\nì ê¹, íì¸í ë¶ë¶ì´ ìë¤ë©´ babel 7.0ììë¶í°ë preset ì¤ì ì´ ì¡°ê¸ ë°ëìë¤ë ê²ì´ë¤.\n기존ì `es-2015`, `stage-0`ê³¼ ê°ì presetë¤ì deprecated ëìê³ ìì²ë¼ targetì ì§ì í´ì£¼ë©´ ëë¤.\u003cbr/\u003e\n`\u003e 0.25%, not dead`ì ì ì ì¨ì´ 0.25%ì¸ ë¸ë¼ì°ì ë¤ì íê²ì¼ë¡ ì»´íì¼ ëë¤ë ì미ì´ë¤.\n( IE10, Blackberryì ê°ì ë³´ìì
ë°ì´í¸ê° ì¤ë¨ë ë¸ë¼ì°ì ë 무ìíë¤ê³ íë¤. )\n\n[Babel ê³µìííì´ì§](https://babeljs.io/docs/en/v7-migration)ìì ë ìì¸í íì¸ í ì ìë¤.\n\n### 3. í
ì¤í¸ ê°ë° íê²½\n\ní
ì¤í¸ ê°ë° íê²½ ì¤ì ì, \u003cb\u003eì¤ì ì ìí ì»´í¬ëí¸ê° react Appìì importíì¬ ì ìëì´ ëëì§\u003c/b\u003e를 ìí ê²ì´ë¤.\n4.xëì ë²ì ì Webpackì¼ë¡ í
ì¤í¸ íê²½ì ì¤ì í ìì ì´ë¤.\nWebpackì ëí ìê°ë ì¤ì ë°©ë² ë±ì ìì¸í ì¤ëª
ì ìëµí ìì ì´ë¤.\n( Webpackì 주목ì ì¼ë¡ ë¤ë£¨ë ë´ì©ì´ ìëë¯ë¡. )\n\n**install**\n\nìëì ê°ì´ ì¤ì¹í´ì¤ë¤.\n\n```js\nnpm install webpack webpack-cli webpack-dev-server --save-dev\n\n// \"webpack\": \"^4.17.2\",\n// \"webpack-cli\": \"^3.1.0\",\n// \"webpack-dev-server\": \"^3.1.7\"\n```\n\nwebpack 4.xë²ì ë¶í°ë webpack-cli를 ê°ì´ ì¤ì¹í´ì¤ì¼ 커맨ëë¼ì¸ìì webpack ëª
ë ¹ì´ë¥¼ ì¬ì©í ì ìë¤.\në, ê°ë°ëª¨ë ì§ìì ìí´ webpack-dev-server를 ì¤ì¹íì.\n\n**webpack.config.js**\n\n```js\nconst path = require('path');\n\nmodule.exports = {\n entry: {\n index: ['@babel/polyfill', './example/App.jsx'],\n },\n output: {\n filename: '[name].js',\n path: path.join(__dirname, 'example'),\n },\n module: {\n rules: [\n {\n test: /\\.jsx$/,\n exclude: /node_modules/,\n use: 'babel-loader',\n },\n ],\n },\n mode: 'production',\n plugins: [],\n devServer: {\n contentBase: './example',\n host: '0.0.0.0',\n },\n};\n```\n\ní
ì¤í¸ Appì ìí Webpack ì¤ì íì¼ì´ë¤.\níì¬ ì»´í¬ëí¸ì ëë í 리ìì í
ì¤í¸ Appì ê²½ë¡ë¥¼ `./example`ë¡ ì¤ì íìê³ ,\n`babel-loader`ì `webpack-dev-server` ê´ë ¨ë ë´ì©ì íì¸í ì ìë¤.\n( babelì presetê³¼ pluginì¸ ì¤ì ë±ì ììì ìì±í .babelrc íì¼ì ë°ë¥¸ë¤. )\nì´ì¸ì 기본ì ì¸ React Appì ë¹ë ì íìí htmlíì¼ê³¼ reactjs ì¤ì¹ ë±ì ìëµíê² ë¤.\n\n**./example/App.jsx**\n\nê°ëµíê² React ìì¤ì indexë¶ë¶ë§ ì ê¹ ì´í´ë³´ì.\n\n```js\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport ImageSlider from '..';\n\nclass App extends React.Component {\n render() {\n return (\n \u003cdiv\u003e\n \u003ch1\u003eImage Slider Example\u003c/h1\u003e\n \u003cImageSlider /\u003e\n \u003c/div\u003e\n );\n }\n}\n\nReactDOM.render(\u003cApp /\u003e, document.getElementById('App'));\n```\n\n`import ImageSlider from \"..\";`를 ë³´ë©´ ìì ëë í 리( =ì»´í¬ëí¸ ë£¨í¸ ëë í 리 )ìì 모ëì importíë ê²ì\níì¸í ì ìë¤.\n( rollupì¼ë¡ ë¹ëí ì»´í¬ëí¸ì ìì¤ê° `package.json`ì `main` ê°ì¼ë¡ ì§ì íì기 ë문 )\n\n**package.json**\n\nscriptsì webpack ëª
ë ¹ì´ë¥¼ ìëì ê°ì´ ì¶ê°í´ì¤ë¤.\n\n```js\n \"scripts\": {\n \"example\": \"webpack-dev-server --mode development\",\n \"build\": \"rollup -c\",\n \"build:watch\": \"rollup -c --watch\"\n },\n```\n\n`npm run example`ì íµí´ webpack-dev-server를 ì¤íìí¤ë©´ ëë¤.\n`--inline`ì´ë `--hot`ê³¼ ê°ì flag를 ì¶ê°íì¬ Live Reloading, Hot Module Reloadingì 기ë¥ì\nì°ë©´ ë í¸ë¦¬í ìë ìë¤.\nLive Reloadingì ì ì²´ íì´ì§ê° 리ë¡ë ëê³ , Hot Module Reloadingì ìì ë ìì¤ì í´ë¹ 모ëë§ ë¦¬ë¡ë©ì´ ëë¤.\n\n### 4. 기í ì¤ì \n\në§ì§ë§ì¼ë¡ eslint ì¤ì , í´ë구조 ë± ì 리를 íìë©´..\n\n**eslint**\n\nìë§ react를 ì¬ì©íê³ babelì ì¬ì©íë¤ë©´ ëë¶ë¶ ë¹ì·í ì¤ì ì´ ë ìë ìê² ì§ë§,\nìì ë¤ì ì½ë©ì»¨ë²¤ì
ì ì ì©íì¬ ì¤ì ì í´ëì.\nëë ì¬ê¸°ì ìëì ê°ì´ ì¤ì íìë¤.\n\n- eslint\n- eslint-config-airbnb\n- eslint-plugin-import\n- eslint-plugin-jsx-a11y\n- eslint-plugin-react\n- babel-eslint\n\n**directory structure**\n\n- dist : rollupì¼ë¡ React ì»´í¬ëí¸ì ìì¤ê° ë¹ëëë ëë í 리. ë°°í¬ë¥¼ ìí ëë í 리.\n- example : ê°ë°í React ì»´í¬ëí¸ë¥¼ webpackì¼ë¡ í
ì¤í¸ì±ì ì ìíì¬ í
ì¤í¸íë ëë í 리.\n- node_modules : ê°ë°ì ì¬ì©ëë 모ëë¤.\n- src : React ì»´í¬ëí¸ì ìì¤ê° ìë ëë í 리.\n\níì¬ ëë í 리ì indexê° ìì§ë§, `package.json`ìì `main` ìì±ì distì ë°°í¬ì© ìì¤ë¡ ì§ì íìë¤.\në°ë¼ì ì¶íì ì»´í¬ëí¸ë¥¼ importí ë index를 못 찾거ë íë 문ì ê° ë°ìíì§ ìëë¤.\n\n## ë§ì¹ë©°\n\nReact ì»´í¬ëí¸ ì ì기를 ì´ 3ë²ì ëë í¬ì¤í
ê³íì ì¸ì ëë°,\n2ë²ì§¸ë ì¤ì React ì»´í¬ëí¸ ìì¤ë¥¼ ê°ë°ê³¼ì ì,\n3ë²ì§¸ë npm, gitì ì
ë¡ëê¹ì§ì ê³¼ì ì ë¤ë£° ìì ì´ë¤.\n\n## References\n\n- https://medium.com/webpack/webpack-and-rollup-the-same-but-different-a41ad427058c\n- https://rollupjs.org/guide/en#quick-start\n- https://rollupjs.org/guide/en#configuration-files\n- https://babeljs.io/docs/en/v7-migration\n- https://webpack.js.org/\n- https://webpack.js.org/concepts/#entry\n","data":{"id":"react-simple-image-slider-1","title":"React ì»´í¬ëí¸ ì ì기 1 / 3","description":"react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.","preview":"react-simple-image-slider ì»´í¬ëí¸ì ê°ë°/ë°°í¬ì ê³¼ì ì ëí ê²½íì ìì í©ëë¤.","keywords":"react, component, react carousel, image slider, npm","slug":"react-simple-image-slider-1","createdAt":"2018.09.21","published":true},"filePath":"react-simple-image-slider-1.mdx"},{"content":"\nì¤ëì TDZ, Temporal Dead Zoneì ëí´ ê¸ì ì°ê³ ì íë¤.\u003cbr/\u003e\nTDZì ëí´ ìë ¤ë©´, í¸ì´ì¤í
ê³¼ let, const, scope ë±ì ëí 기본ì ì¸ ì´í´ê° ìì´ì¼ íë¤.\n\n## Temporal Dead Zone\n\nììì ì´ì¼ê¸°í ê²ì²ë¼ TDZì ëí´ ìë ¤ë©´, `í¸ì´ì¤í
`, `let \u0026 const`ì ëí´ ììì¼ íë¤.\n\n### í¸ì´ì¤í
\n\ní¸ì´ì¤í
ì ì¸í°í리í°ê° ë³ìì í¨ìì ë©ëª¨ë¦¬ ê³µê°ì ì ì¸ ì ì 미리 í ë¹íë ê²ì ì미íë¤.\u003cbr/\u003e\n`var`ë¡ ì ì¸í ë³ìì ê²½ì° í¸ì´ì¤í
ì undefinedë¡ ë³ì를 ì´ê¸°ííê² ëë¤.\n\n### let \u0026 const\n\n`let`ê³¼ `const`ë ES5+ë¶í° ì¬ì©í ì ìê³ block scope 기ë°ì¼ë¡ ëìíë ë³ìíì
ì´ë¤.\u003cbr/\u003e\nìë ì½ë를 ë³´ì.\n\n```js\nconsole.log(x); // undefined\nconsole.log(y); // ReferenceError\n\nvar x = 'x';\nlet y = 'y';
16\n```\n\në³ìì ì ì¸ë¶ë í´ë¹ scopeì ìµìë¨ì¼ë¡ ëì´ì¬ë ¤ì ¸ í´ìëë¤.\u003cbr/\u003e\níì§ë§ ìì ì½ëìì `let`ì¼ë¡ ì ì¸í ë³ì yì ì ê·¼ììë `ReferenceError`를 ë´ë±ëë¤.\u003cbr/\u003e\u003cbr/\u003e\n\nê·¸ë¼ letì í¸ì´ì¤í
ì´ ëì§ ìë ê²ì¸ê°?\u003cbr/\u003e\nê·¸ë ì§ ìë¤. `let`ê³¼ `const`ë ë§ì°¬ê°ì§ë¡ í¸ì´ì¤í
ëì§ë§, ë³ìì ì´ê¸°íê° ì¤íëì§ ìëë¤.\u003cbr/\u003e\n\nìì ì½ëìì letë³ìì ì ê·¼ì´ ë¶ê°ë¥í ì´ì ê° ë°ë¡ **TDZ**ë문ì´ë¤.\u003cbr/\u003e\nMDN문ìì ë´ì©ì ì°¸ê³ íìë©´, ìëì ê°ì´ íë§ëë¡ ì ìí ì ìë¤.\u003cbr/\u003e\n`let`ê³¼ `const`ë ë¸ë¡ì ììë¶í° ì´ê¸°íê° ì¤íë기ì ê¹ì§ TDZì ì¡´ì¬íê² ëë¤ë ê².\u003cbr/\u003e\në°ë¼ì, TDZì ì¡´ì¬íë©´ ìì ê°ì´ ì ê·¼ì í ì ìë¤.\u003cbr/\u003e\n\n### Temporal\n\nDeadZone íì±ì´ **ìê°ì**(Temporal)ì¸ ì´ì ë ì´ì ë\u003cbr/\u003e\nì¬ê°ì§ëê° ì½ëì ìì± ìì(ìì¹)ê° ìëë¼ ì½ëì ì¤í ìì(ìê°)ì ìí´ íì±ë기 ë문ì´ë¤.\n\n```js\n{\n // TDZê° ì¤ì½í 맨 ìììë¶í° ìì\n const func = () =\u003e console.log(letVar); // OK\n\n // TDZ ììì letVarì ì ê·¼íë©´ ReferenceError\n\n let letVar = 3; // letVarì TDZ ì¢
ë£\n func(); // TDZ ë°ìì í¸ì¶í¨\n}\n```\n\nì ì½ëì ê²½ì° let ë³ì ì ì¸ ì½ëê° ê·¸ ë³ìì ì ê·¼íë í¨ìë³´ë¤ ìëì ìì¹íì§ë§, í¨ìì í¸ì¶ ìì ì´ ì¬ê°ì§ë ë°ì´ë¯ë¡ ì ì ëìíë¤.\n\n## ì¬ë¬ê°ì§ ìí©ë¤\n\n### TDZ with Lexical Scope\n\n```js\nfunction test() {\n var foo = 33;\n if (true) {\n let foo = foo + 55; // ReferenceError\n console.log(foo);\n }\n}\ntest();\n```\n\nMDNì ìë ìì ìì¤ì´ë¤.\u003cbr/\u003e\ní¨ì ë´ë¶ì 조건문 blockì ìì¤ìì, foo 참조ì TDZë¡ ì¸í `ReferenceError`ê° ë°ìíë¤.\u003cbr/\u003e\nfooì ì´ê¸°í 구문ìì (foo + 55)ì fooê° TDZì ì기(ìì§ ì´ê¸°íê° ëì§ ìì기) ë문ì´ë¤.\n\n### TDZ with Default Function Parameter\n\n```js\n(function (a = b, b) {})(undefined, 1); // ReferenceError\n```\n\n```js\n(function (a = a) {})(); // ReferenceError\n```\n\nìì 2ê°ì§ ìì ë¤ë ëê°ì´ ìë¬ê° ë°ìíë¤.\u003cbr/\u003e\ní¨ìì ëí´í¸ íë¼ë¯¸í°ê° TDZì ìë(ì´ê¸°íì¤íì´ ëì§ ìì ìíì) ê°ì 참조íê³ ì기 ë문ì´ë¤.\u003cbr/\u003e\nìì ê²½ì°ìì , aê° b를 참조íëë°, bì ì´ê¸°íê° ìì§ ëì§ ìì ìíì´ë¤.\u003cbr/\u003e\n(ëí´í¸ íë¼ë¯¸í°ë ì¼ìª½ìì ì¤ë¥¸ìª½ì¼ë¡ ì¤í)\u003cbr/\u003e\nìëìì , ìì foo ìì ì ê°ì ì¼ì´ì¤ì´ë¤. aì ì´ê¸°í 구문ìì ì ê·¼íë ¤ë aê° TDZì ì기 ë문ì´ë¤.\u003cbr/\u003e\n\n## ë§ì¹ë©°\n\nvarë¡ ë³ì를 ì ì¸íê³ ì¬ì©í ëë ë§ì°¬ê°ì§ì´ì§ë§, ì´ê¸°í í ì¬ì©ì ëí ìì í ë°©ìì ì½ë©ì¤íì¼ì ì§í¥íë ê²ì´ ì¢ë¤.\u003cbr/\u003e\níì¤í ê²ì, `let`ê³¼ `const`를 ì¬ì©íê³ `TDZ`ì ëí ê°ë
ì ì ìê³ ìë¤ë©´, ì¬ë¬ ë¶ìì©ì ë°©ì§í ì ììê²ì´ë¤.\u003cbr/\u003e\n\n## References\n\n- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_Dead_Zone\n- https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Default_parameters\n","data":{"id":"tdz","title":"TDZ(Temporal Dead Zone)","description":"TDZ(Temporal Dead Zone)ì ëí´ ììë´
ëë¤.","preview":"TDZ(Temporal Dead Zone)ì ëí´ ììë´
ëë¤.","keywords":"javascript, es6, temporal dead zone, tdz, hoisting, const, let","slug":"javascript-pass-by-value-function-parameters","createdAt":"2018.09.17","published":true},"filePath":"tdz.mdx"}]},"__N_SSG":true},"page":"/blog","query":{},"buildId":"mYpFDr1DZDEyR2tzQItwY","isFallback":false,"gsp":true,"scriptLoader":[]}</script>
16</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.