๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Next.js

[๋‚ด๋ณด๋‚ด๋ฒˆ] Next.js docs - Dynamic Import

๋‚ด๋ณด๋‚ด๋ฒˆ(๋‚ด๊ฐ€ ๋ณด๋ ค๊ณ  ๋‚ด๊ฐ€ ๋ฒˆ์—ญํ•œ...) Next.js docs

2021๋…„ 8์›” 3์ผ ๊ธฐ์ค€ Next.js ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ–ˆ๋‹ค.

โ€ป ์˜์–ด ์ „๊ณต์ž๋„ ํ•ด์™ธ ์œ ํ•™ํŒŒ๋„ ์•„๋‹ˆ๊ธฐ์— ๋ฒˆ์—ญ์—๋Š” ์˜์—ญ, ์˜ค์—ญ, ๊ตฌ๊ธ€ ๋ฒˆ์—ญ์ด ๋ฌด์ˆ˜ํžˆ ๋งŽ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ˜ผ์ž ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•ด๊ฐ€๋ฉฐ ๋ฒˆ์—ญํ•˜๋‹ค ๋ณด๋‹ˆ ์˜คํƒ€๋„ ๋งŽ์„ ์ˆ˜ ์žˆ๋‹ค. ์ •ํ™•ํ•œ ๋‚ด์šฉ์€ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ง์ ‘ ์‚ดํŽด๋ณด๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์ •๋ณด๋“ค์„ ๋” ์ฐพ์•„๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

(ํ•˜์ง€๋งŒ ๋Œ“๊ธ€ ํ”ผ๋“œ๋ฐฑ๋„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜ƒ )

Next.js ๊ณต์‹๋ฌธ์„œ ํ™•์ธํ•˜๊ธฐ>>

 

Advanced Features: Dynamic Import | Next.js

Dynamically import JavaScript modules and React Components and split your code into manageable chunks.

nextjs.org

Next.js supports ES2020 dynamic import() for JavaScript. With it you can import JavaScript modules dynamically and work with them. They also work with SSR.

In the following example, we implement fuzzy search using fuse.js and only load the module dynamically in the browser after the user types in the search input:

Next.js๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ES2020 dynamic import()๋ฅผ ์ง€์›ํ•œ๋‹ค. ์ด๊ฒƒ์œผ๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ชจ๋“ˆ์„ ๋™์ ์œผ๋กœ ๊ฐ€์ ธ์™€์„œ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค. SSR๊ณผ๋„ ์ž˜ ๋™์ž‘ํ•œ๋‹ค. 

์•„๋ž˜์˜ ์˜ˆ์ œ์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ fuzzy ๊ฒ€์ƒ‰์„ fuse.js๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ด๋†“์•˜๋Š”๋ฐ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•œ ํ›„์—๋งŒ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋™์ ์œผ๋กœ ๋ชจ๋“ˆ์„ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค€๋‹ค.

import { useState } from 'react'

const names = ['Tim', 'Joe', 'Bel', 'Max', 'Lee']

export default function Page() {
  const [results, setResults] = useState()

  return (
    <div>
      <input
        type="text"
        placeholder="Search"
        onChange={async (e) => {
          const { value } = e.currentTarget
          // Dynamically load fuse.js
          const Fuse = (await import('fuse.js')).default
          const fuse = new Fuse(names)

          setResults(fuse.search(value))
        }}
      />
      <pre>Results: {JSON.stringify(results, null, 2)}</pre>
    </div>
  )
}

You can think of dynamic imports as another way to split your code into manageable chunks.

React components can also be imported using dynamic imports, but in this case we use it in conjunction with next/dynamic to make sure it works like any other React Component. Check out the sections below for more details on how it works.

dynamic import๋ฅผ ์ฝ”๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์ข‹์€ ๋ฉ์–ด๋ฆฌ๋กœ ๋‚˜๋ˆ„๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋„ ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค. 

React ์ปดํฌ๋„ŒํŠธ ์—ญ์‹œ dynamic import๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์ง€๋งŒ ์ด ๊ฒฝ์šฐ์— next/dynamic๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ React ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ์ ์€ ์•„๋ž˜ ๋ถ€๋ถ„์„ ํ™•์ธํ•ด๋ณด๋ผ. 

Basic usage

In the following example, the module ../components/hello will be dynamically loaded by the page:

์•„๋ž˜์˜ ์˜ˆ์ œ์—์„œ๋Š” ../components/hello ๋ชจ๋“ˆ์ด ํŽ˜์ด์ง€์—์„œ ๋™์ ์œผ๋กœ ๋กœ๋“œ๋  ๊ฒƒ์ด๋‹ค. 

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() => import('../components/hello'))

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

DynamicComponent will be the default component returned by ../components/hello. It works like a regular React Component, and you can pass props to it as you normally would.

์˜ˆ์ œ์˜ DynamicComponent๋Š” ../components/hello์—์„œ ๋ฐ˜ํ™˜๋œ default ์ปดํฌ๋„ŒํŠธ์ด๋‹ค. ๋ณดํ†ต์˜ React ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋ฉฐ, ๋ณดํ†ตํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ props์„ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ๋‹ค. 

Note: In import('path/to/component'), the path must be explicitly written. It can't be a template string nor a variable. Furthermore the import() has to be inside the dynamic() call for Next.js to be able to match webpack bundles / module ids to the specific dynamic() call and preload them before rendering. dynamic() can't be used inside of React rendering as it needs to be marked in the top level of the module for preloading to work, similar to React.lazy.

import('path/to/component')์—์„œ ๊ฒฝ๋กœ๋Š” ๋ฐ˜๋“œ์‹œ ๋ช…์‹œ์ ์œผ๋กœ ์ž‘์„ฑ๋˜์–ด์•ผํ•œ๋‹ค. ๊ฒฝ๋กœ๋Š” ํ…œํ”Œ๋ฆฟ ๋ฌธ์ž์—ด์ด๋‚˜ ๋ณ€์ˆ˜์—ฌ์„œ๋Š” ์•ˆ๋œ๋‹ค. ๋˜ํ•œ import()๋Š” Next.js๊ฐ€ ์›นํŒฉ ๋ฒˆ๋“ค/๋ชจ๋“ˆ id๋ฅผ ํŠน์ • dynamic() ํ˜ธ์ถœ๊ณผ ์ผ์น˜์‹œํ‚ค๊ณ  ๋ Œ๋”๋ง ์ „์— ํ”„๋ฆฌ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ dynamic() ํ˜ธ์ถœ ๋‚ด๋ถ€์— ์žˆ์–ด์•ผ๋งŒ ํ•œ๋‹ค. dynamic()์€ React.lazy์™€ ๋น„์Šทํ•˜๊ฒŒ ํ”„๋ฆฌ๋กœ๋“œ๊ฐ€ ๋™์ž‘ํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋“ˆ์˜ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์— ํ‘œ์‹œ๋˜์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— React ๋ Œ๋” ์•ˆ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.  

 

With named exports

If the dynamic component is not the default export, you can use a named export too. Consider the module ../components/hello.js which has a named export Hello:

dynamic ์ปดํฌ๋„ŒํŠธ๊ฐ€ default export๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด named ์ปดํฌ๋„ŒํŠธ ์—ญ์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Hello๋ผ๋Š” named export๊ฐ€ ์žˆ๋Š”  ../component/hello.js ๋ชจ๋“ˆ์„ ์‚ดํŽด๋ณด๋ผ.

export function Hello() {
  return <p>Hello!</p>
}

To dynamically import the Hello component, you can return it from the Promise returned by import(), like so: 

Hello ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋™์ ์œผ๋กœ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ import()์— ์˜ํ•ด์„œ ๋ฐ˜ํ™˜๋œ Promise๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. 

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

 

With custom loading component

An optional loading component can be added to render a loading state while the dynamic component is being loaded. For example:

dynamic ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๋™์•ˆ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋ Œ๋”ํ•˜๋Š” ์„ ํƒ์ ์ธ ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด: 

import dynamic from 'next/dynamic'

const DynamicComponentWithCustomLoading = dynamic(
  () => import('../components/hello'),
  { loading: () => <p>...</p> }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithCustomLoading />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

 

With no SSR

You may not always want to include a module on server-side. For example, when the module includes a library that only works in the browser.

Take a look at the following example:

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

์•„๋ž˜์˜ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๋ผ:

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home