Next.js 프로젝트에서
yarn start
혹은npm run start
스크립트를 실행했을 때 실행되는 코드(파일)과, 해당 파일에 대한 간단한 설명을 첨부해주세요.
#!/usr/bin/env node
import arg from 'next/dist/compiled/arg/index.js'
import { startServer } from '../server/lib/start-server'
import { getPort, printAndExit } from '../server/lib/utils'
import isError from '../lib/is-error'
import { getProjectDir } from '../lib/get-project-dir'
import { CliCommand } from '../lib/commands'
import { resolve } from 'path'
import { PHASE_PRODUCTION_SERVER } from '../shared/lib/constants'
import loadConfig from '../server/config'
const nextStart: CliCommand = async (argv) => {
const validArgs: arg.Spec = {
// Types
'--help': Boolean,
'--port': Number,
'--hostname': String,
'--keepAliveTimeout': Number,
// Aliases
'-h': '--help',
'-p': '--port',
'-H': '--hostname',
}
let args: arg.Result<arg.Spec>
try {
args = arg(validArgs, { argv })
} catch (error) {
if (isError(error) && error.code === 'ARG_UNKNOWN_OPTION') {
return printAndExit(error.message, 1)
}
throw error
}
if (args['--help']) {
console.log(`
Description
Starts the application in production mode.
The application should be compiled with \`next build\` first.
Usage
$ next start <dir> -p <port>
<dir> represents the directory of the Next.js application.
If no directory is provided, the current directory will be used.
Options
--port, -p A port number on which to start the application
--hostname, -H Hostname on which to start the application (default: 0.0.0.0)
--keepAliveTimeout Max milliseconds to wait before closing inactive connections
--help, -h Displays this message
`)
process.exit(0)
}
const dir = getProjectDir(args._[0])
const host = args['--hostname']
const port = getPort(args)
const keepAliveTimeoutArg: number | undefined = args['--keepAliveTimeout']
if (
typeof keepAliveTimeoutArg !== 'undefined' &&
(Number.isNaN(keepAliveTimeoutArg) ||
!Number.isFinite(keepAliveTimeoutArg) ||
keepAliveTimeoutArg < 0)
) {
printAndExit(
`Invalid --keepAliveTimeout, expected a non negative number but received "${keepAliveTimeoutArg}"`,
1
)
}
const keepAliveTimeout = keepAliveTimeoutArg
? Math.ceil(keepAliveTimeoutArg)
: undefined
const config = await loadConfig(
PHASE_PRODUCTION_SERVER,
resolve(dir || '.'),
undefined,
undefined,
true
)
await startServer({
dir,
isDev: false,
hostname: host,
port,
keepAliveTimeout,
useWorkers: !!config.experimental.appDir,
})
}
export { nextStart }
코드가 기므로 하나하나씩 쪼개서 분석해보자
const validArgs: arg.Spec = {
// Types
'--help': Boolean,
'--port': Number,
'--hostname': String,
'--keepAliveTimeout': Number,
// Aliases
'-h': '--help',
'-p': '--port',
'-H': '--hostname',
}
먼저 딕셔너리를 하나 생성한다. npx next start
뒤에 무슨 옵션들이 붙을 수 있는지를 정의한다.
나중에 저 키워드들을 이용해서 아래와 같이 활용할 수 있다.
npm next start my-app -p 8080 --hostname localhost
npm next start --keepAliveTimeout 10s
10초 동안 클라한테 소식 없으면 그냥 끊어버려라
웹 서버는 일정 시간 동안 클라로부터 요청이 없을 경우, 서버 측에서 자동으로 연결을 끊는 기능을 가지고 있다. 기본 값은 10초인데, 이것보다 더 짧게 or 길게 설정하고 싶을 때 --keepAliveTimeout
옵션을 사용한다.
시간을 너무 길게 설정하면 쓸데없는 연결까지도 계속 유지되어 메모리 사용량이 증가하고, 복수의 요청에 병목 현상이 발생할 수 있다. 반대로 시간을 너무 짧게 설정하면 클라-서버 간 '끊기고-연결하고-끊기고-연결하고'가 계속 반복되기 때문에 (마찬가지로) 메모리 사용량이 증가하고, 로딩/버퍼링 및 네트워크 오류가 발생할 확률이 높아진다.
let args: arg.Result<arg.Spec>
try {
args = arg(validArgs, { argv })
} catch (error) {
if (isError(error) && error.code === 'ARG_UNKNOWN_OPTION') {
return printAndExit(error.message, 1)
}
throw error
}
npm next start my-app -p 8080 --hostname localhost
에서 -p 8080 --hostname localhost
가 argv에 해당하는 부분이다.
여기서 --asdfjkslf 같은 잘못된 키워드를 사용하면 catch로 넘어간다.
if (args['--help']) {
console.log(`
Description
Starts the application in production mode.
The application should be compiled with \`next build\` first.
Usage
$ next start <dir> -p <port>
<dir> represents the directory of the Next.js application.
If no directory is provided, the current directory will be used.
Options
--port, -p A port number on which to start the application
--hostname, -H Hostname on which to start the application (default: 0.0.0.0)
--keepAliveTimeout Max milliseconds to wait before closing inactive connections
--help, -h Displays this message
`)
process.exit(0)
}
npm next start --help
라고 입력했다면 console.log가 실행되고 코드가 종료된다.
const dir = getProjectDir(args._[0])
const host = args['--hostname']
const port = getPort(args)
const keepAliveTimeoutArg: number | undefined = args['--keepAliveTimeout']
if (
typeof keepAliveTimeoutArg !== 'undefined' &&
(Number.isNaN(keepAliveTimeoutArg) ||
!Number.isFinite(keepAliveTimeoutArg) ||
keepAliveTimeoutArg < 0)
) {
printAndExit(
`Invalid --keepAliveTimeout, expected a non negative number but received "${keepAliveTimeoutArg}"`,
1
)
}
if문 부분이 좀 난잡하게 되어 있는데, 이를 보기 쉽게 풀어 쓰면 다음과 같다.
const 값이_존재함 = (typeof keepAliveTimeoutArg) !== 'undefined';
const 값이_NaN임 = Number.isNaN(keepAliveTimeoutArg);
const 값이_무한대임 = !Number.isFinite(keepAliveTimeoutArg);
const 값이_음수임 = keepAliveTimeoutArg < 0;
const 잘못된_값임 = 값이_존재함 && (값이_NaN임 || 값이_무한대임 || 값이_음수임);
if (잘못된_값임) {
printAndExit(
`Invalid --keepAliveTimeout, expected a non negative number but received "${keepAliveTimeoutArg}"`,
1
)
}
한마디로 --keepAliveTimeout
뒤에 말도 안 되는 값 들어오면 에러 메시지 내뿜고 코드 종료하라는 것.
const keepAliveTimeout = keepAliveTimeoutArg
? Math.ceil(keepAliveTimeoutArg)
: undefined
제대로 된 값이 들어왔으니까 1의 자리에서 올린다. (예: 3.1 → 4)
--keepAliveTimeout
을 애당초 설정 안 했으면 undefined이기 때문에, 그냥 undefined로 둔다.
const config = await loadConfig(
PHASE_PRODUCTION_SERVER,
resolve(dir || '.'),
undefined,
undefined,
true
)
await startServer({
dir,
isDev: false,
hostname: host,
port,
keepAliveTimeout,
useWorkers: !!config.experimental.appDir,
})
(4번 항목에서 선언했던 4개의 변수들과 더불어) 서버의 Config 설정을 불러오고, 그걸 startServer()
에 적용하여 본격적으로 서버를 실행한다.
export { nextStart }
마지막으로 1~7까지의 작업을 수행하는 nextStart()
를 다른 파일에서 사용할 수 있도록 내보내기를 허용한다.
next-start.ts
코드는 크게 2가지의 일을 담당한다.
npx next start
뒤에 붙는 --help
, --port
, --hostname
, --keepAliveTimeout
옵션의 정의. 그리고 무결성 체크