Next.js 프로젝트에서 yarn start 스크립트를 실행했을 때 어떤일이 생길까?

Shin Yeongjae·2023년 7월 5일
0

TIL

목록 보기
21/21

우선 Next.js는 자체 서버 위에서 돌아가니 server와 관련된 폴더에 관련된 코드가 있을 것이라고 생각했다. Next.js 레포를 들어가서 찾아보니 packages/next/src/server/lib/start-server.ts 파일을 발견할 수 있었다. 아래 코드는 start-server.ts의 코드 일부이다.

export async function startServer({
  dir,
  prevDir,
  port,
  isDev,
  hostname,
  useWorkers,
  allowRetry,
  keepAliveTimeout,
  onStdout,
  onStderr,
}: StartServerOptions): Promise<TeardownServer> {
  ...
  // setup server listener as fast as possible
  const server = http.createServer(async (req, res) => {
    try {
      if (handlersPromise) {
        await handlersPromise
        handlersPromise = undefined
      }
      sockets.add(res)
      res.on('close', () => sockets.delete(res))
      await requestHandler(req, res)
    } catch (err) {
      res.statusCode = 500
      res.end('Internal Server Error')
      Log.error(`Failed to handle request for ${req.url}`)
      console.error(err)
    }
  })
  ...
  server.on('error', (err: NodeJS.ErrnoException) => {
    if (
      allowRetry &&
      port &&
      isDev &&
      err.code === 'EADDRINUSE' &&
      portRetryCount < 10
    ) {
      Log.warn(`Port ${port} is in use, trying ${port + 1} instead.`)
      port += 1
      portRetryCount += 1
      server.listen(port, hostname)
    } else {
      Log.error(`Failed to start server`)
      console.error(err)
      process.exit(1)
    }
  })
  
  await new Promise<void>((resolve) => {
    server.on('listening', () => {
      const addr = server.address()
      port = typeof addr === 'object' ? addr?.port || port : port

      let host = !hostname || hostname === '0.0.0.0' ? 'localhost' : hostname

      let normalizedHostname = hostname || '0.0.0.0'

      if (isIPv6(hostname)) {
        host = host === '::' ? '[::1]' : `[${host}]`
        normalizedHostname = `[${hostname}]`
      }
      targetHost = host

      const appUrl = `http://${host}:${port}`

      if (isNodeDebugging) {
        const debugPort = getDebugPort()
        Log.info(
          `the --inspect${
            isNodeDebugging === 'brk' ? '-brk' : ''
          } option was detected, the Next.js proxy server should be inspected at port ${debugPort}.`
        )
      }

      Log.ready(
        `started server on ${normalizedHostname}${
          (port + '').startsWith(':') ? '' : ':'
        }${port}, url: ${appUrl}`
      )
      resolve()
    })
    server.listen(port, hostname)
  })
}

위 형태로 구성된 함수인데, 위에 적어놓은 코드가 startServer 함수의 핵심이라는 생각이 들었다. Node.js 내장 모듈 http를 통해 서버를 생성하는 부분을 확인할 수 있었다. socket이 있는걸로 봐서, HMR을 소켓을 통해 구현했구나 생각이 들었다. 그 외 server.on('error') 부분에서 우리가 실수로 3000번 포트를 사용하는 프로젝트의 서버를 두 개 열었을 때 볼 수 있는 에러 메세지를 확인할 수 있었다.

server.on('listening') 부분에서 우리가 next.js 프로젝트를 정상적으로 시작했을 때 우리를 반겨주는 콘솔을 볼 수 있었다.

몰랐던 부분도 있었는데, internal server를 디버깅할 수 있는 옵션이 있는 것을 확인할 수 있었다. 내부 에러가 생겼을 경우에 확인하기 힘든 경우가 있었는데, 이 옵션을 통해 디버깅을 할 수 있을 것 같다.

그리고 normalizeRepeatedSlashes 라는 유틸함수를 통해 인코딩 되지 않은 백슬래시를 포워드슬래시로 치환하여 정상적인 URL의 형태로 변환하는 부분도 확인할 수 있었다.

profile
문과생의 개발자 도전기

0개의 댓글