누군가의 추천으로 말로만 듣던 원티드 프리온보딩 챌린지를 신청하게 되었다.
사실 조금은 가벼운 마음으로 신청했던 것도 있었지만, OT 이후 첫번째 강의를 듣고 나서는
이거 만만치 않은 챌린지가 되겠구나 하는 생각이 들었고, 다시한번 바짝 내 위치에 대해서 경각심을 갖게 됐다.
그래서 사전과제부터 느리지만 빠르게 끌어올려볼까 한다..!
사전과제
이번 프리온보딩에서는 Next.js를 중점적으로 다룬다고 했다.
마침 관심이 있었던 주제고, 회사에서도 Next.js를 이용해서 프로젝트를 진행하고 있으니 많은 도움이 되겠다 싶었는데
사전과제부터 심상치 않았다.
Next.js 프로젝트에서 yarn start(or npm run start) 스크립트를 실행했을 때
실행되는 코드를 Next.js Github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.
그냥 이 과제만 보고 내가 가장 처음 느낀 감정은 다시 처음으로 돌아가는 듯한 느낌을 받았다.
지금까지는 정말 우물안에 우물안 개구리만도 못한 위치였으면서, 1년 반동안 내가 뭘 했지라는 생각도 들었다.
일단 그래도 최대한 우물안에 개구리 발끝이라도 따라가 보자라는 생각으로 시작했다..!
Next의 시작을 찾아서..
나만 그런건지 모르겠는데 npm run start 스크립트를 실행했을 때, 실행되는 코드가 전혀 없었다..... (세상이 나를 억까하는구나..)
그래서 과제에서 가이드 주신대로 Next.js의 Github을 뒤져보기 시작했다.
결국 이 과제는 run start 를 했을 때, 어떤 식으로 next 프로젝트가 동작하는지 그 소스코드를 뜯어보는 과제였는데
next-start 라는 키워드를 가지고 경로를 뒤져봤을 때 이런 경로를 찾을 수 있었다.
next.js/packages/next/src/cli/next-start.ts
해당 파일에서 가장 핵심이 되는 코드를 발견할 수 있었는데 아마 이 함수가 npm run start 를 했을 때, 실행되는 함수가 아닐까 싶었다.
const nextStart = async (argv)=>{
const validArgs = {
// Types
"--help": Boolean,
"--port": Number,
"--hostname": String,
"--keepAliveTimeout": Number,
// Aliases
"-h": "--help",
"-p": "--port",
"-H": "--hostname"
};
우선 함수를 조금씩 뜯어보면 가장 위에 validArgs 라는 객체가 있다.
해당 객체는 스크립트의 옵션을 관리하는 객체라고 보여진다.
const nextStart = async (argv)=>{
...
let args;
try {
args = (0, _index.default)(validArgs, {
argv
});
} catch (error) {
if ((0, _iserror.default)(error) && error.code === "ARG_UNKNOWN_OPTION") {
return (0, _utils.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);
}
그 아래에는 args 라는 변수를 선언하고 해당 변수에 데이터를 넣는 것으로 보인다.
이 과정에서 에러가 발생하면 에러 메세지를 반환하는 것 같다.
만약 args에 --help가 찍히면 help에 관련된 메세지를 출력하는 것으로 보인다.
const nextStart = async (argv)=>{
...
const dir = (0, _getprojectdir.getProjectDir)(args._[0]);
const host = args["--hostname"];
const port = (0, _utils.getPort)(args);
const keepAliveTimeoutArg = args["--keepAliveTimeout"];
if (typeof keepAliveTimeoutArg !== "undefined" && (Number.isNaN(keepAliveTimeoutArg) || !Number.isFinite(keepAliveTimeoutArg) || keepAliveTimeoutArg < 0)) {
(0, _utils.printAndExit)(`Invalid --keepAliveTimeout, expected a non negative number but received "${keepAliveTimeoutArg}"`, 1);
}
const keepAliveTimeout = keepAliveTimeoutArg ? Math.ceil(keepAliveTimeoutArg) : undefined;
const config = await (0, _config.default)(_constants.PHASE_PRODUCTION_SERVER, (0, _path.resolve)(dir || "."), undefined, undefined, true);
await (0, _startserver.startServer)({
dir,
isDev: false,
hostname: host,
port,
keepAliveTimeout,
useWorkers: !!config.experimental.appDir
});
};
마지막 부분에서는 다양한 변수들이 선언 되는데, 서버를 동작하는데 필요한 데이터를 전달하는 것으로 보인다.
그래서 어렵지만 startServer를 조금 더 분석해 보기로 한다.
next.js/packages/next/src/server/lib/start-server.ts
위의 경로에 들어가서 소스코드를 확인해 보니 startServer 라는 함수가 있었다.
export async function startServer({
...
// 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)
}
})
...
}
모든 코드를 해석할 수는 없었지만 특별하게 몇가지 눈에 들어온 함수들이 있었다.
우선 createServer 라는 함수는 이름에서 알 수 있듯, 서버를 생성하는 함수라고 보여진다. (역시 이름의 중요성..)
해당 함수를 server라는 변수에 담고, 여러 상황에 따라서 분기처리가 되도록 구현한 로직도 보였다.
더 아래로 내려가면 이런 함수도 보였다.
const getProxyServer = (pathname)=>{
const targetUrl = `http://${targetHost === "localhost" ? "127.0.0.1" : targetHost}:${routerPort}${pathname}`;
const proxyServer = httpProxy.createProxy({
target: targetUrl,
changeOrigin: false,
ignorePath: true,
xfwd: true,
ws: true,
followRedirects: false
});
proxyServer.on("error", (_err)=>{
// TODO?: enable verbose error logs with --debug flag?
});
return proxyServer;
};
프록시 서버를 여는 함수로 보이는데, 개발환경에서 필요한 부분도 설정해 준 모습을 볼 수 있었다.
더 아래에서는 서버를 끄는 함수도 있었다.
사실 지금 분석한 코드들이 제대로 된 과정을 통해서 분석을 했는지, 올바르게 진행한 과제인지에 대해서는 감이 서질 않지만
이런 과정이 생각없이 그냥 하라는대로 했었던 나한테는 상당한 충격으로 다가왔던 것 같다.
단순 라이브러리를 사용할 때 소스 코드를 분석하는 것 보다 전체적인 구조를 뜯어보는 것은 해본적이 없었던 것 같은데
그냥 쉽게만 하려고 했던 내 자신을 한번 더 반성하는 계기가 됐다.. 흐
레퍼런스
- Next.js Github Page [이동]
- Next.js Github : next-start.ts 경로 [이동]
- Next.js Github : start-server.ts 경로 [이동]
'Develop > Challenge' 카테고리의 다른 글
[원티드] Pre-onboarding Frontend challenge_첫번째 과제 (0) | 2023.07.10 |
---|---|
[RESAT] Farming Challenge 프론트엔드 개발자편_epilogue (0) | 2023.07.05 |
[RESAT] 10일차 미션 : 로그인 UI 만들기 (0) | 2023.06.30 |
[RESAT] 9일차 미션 : 반응형 네비게이션 바 만들기 (0) | 2023.06.30 |
[RESAT] 8일차 미션 - 캐러셀 만들기 (3) (0) | 2023.06.29 |