1. CSR(Client-side Rendering)이란 무엇이며, 그것의 장단점에 대하여 설명해주세요.
2. SPA(Single Page Application)로 구성된 웹 앱에서 SSR(Server-side Rendering)이 필요한 이유에 대하여 설명해주세요.
3. Next.js 프로젝트에서 yarn start(or npm run start) 스크립트를 실행했을 때 실행되는 코드를 Next.js Github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.
https://nextjs.org/docs/getting-started (Next.js 세팅 가이드)
https://github.com/vercel/next.js/ (Next.js Github 레포지토리)
Client Side Rendering , Next.js 에서 CSR 은 기본적으로 Javascript 를 이용해 브라우저에서 페이지를 동적으로 생성하게 됩니다. 이를 통해 웹사이트는 사용자와 상호작용하면서 원활하게 업데이트 될 수 있습니다.
CSR 의 경우 모든 데이터가 로드가 되고 , Javascript 가 실행되어야 페이지가 완전히 렌더링되므로 쵝 로딩 시간이 상대적으로 느릴 수 있습니다. 그리고 검색 엔진 최적화(SEO) 에 있어서는 서버사이드 렌더링(SSR) 이나 정적사이트 생성(SSG) 방식에 비해 불리할 수 있습니다. 왜냐하면 CSR 의 경우 크롤러가 페이지를 인덱싱하기 전에 모든 자바스크립트가 로드 되어야 하기 때문입니다.
따라서, CSR 은 사용자의 인터랙션에 따라 콘텐츠가 자주 바뀌는 웹 사이트나 애플리케이션에 적합합니다.
SPA(single Page Application) 는 모든 콘텐츠를 한 페이지에 로드하여 사용자와 상호작용을 통해 필요한 부분만 업데이트 합니다. 이렇게 되면 , 페이지 전환 없이 빠르고 부드러운 사용자 경험이 가능합니다. 하지만 단점이 존재합니다.
이러한 문제들을 해결하기 위해 Next.js 는 SSR 을 제공합니다. SSR 은 서버에서 페이지를 렌더링 하고 완전히 렌더링 된 페이지를 클라이언트에 전달하는 방식입니다. 이 방식을 사용하면 다음과 같은 이점이 있습니다.
따라서 , SSR 은 SPA 의 SEO 문제와 초기 로딩 시간 문제를 해결해주는 중요한 도구 입니다. 그러나 모든 상황에 SSR 이 필요한 상황은 아니며 , 애플리케이션의 필요에 따라 적절한 렌더링 전략을 잘 선택해야합니다!!
보통은 package.json 파일에
"scripts": {
"dev": "next dev -p 3000",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
yarn dev , yarn start 이전에 프로젝트 사용시 웹팩을 이용해서 https:// 개발환경을 만들면서 script 코드를 수정해본적이 있었지만 start 가 어떻게 실행되는지에 대해서 이번 온보딩 사전 과제를 통해서 공부하는 계기가 되었다.
next.js/packages/next/src/cli/next-start.ts
#!/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',
}
1) validArgs 는 인자들의 이름과 타입 , 그리고 단축키를 정의합니다.
2) arg 함수는 사용자가 입력한 인자를 파싱하고 args 에 저장합니다.
3) 만약 알수 없는 인자가 입력 되면 , 오류를 출력하고 프로그램을 종료합니다.
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)
}
사용자가 "--help' 옵션을 사용해 명령어를 실행했을 때 도움말 메시지를 출력하고 프로그램을 종료하는 역할을 합니다.
'args['--help']' 가 참이면 즉 ,'--help' 옵션이 주어졌다면 , 'console.log' 를 통해 도움말 메시지를 출력합니다. 이 메시지는 'next start' 명령어의 사용 방법과 옵션들에 대한 설명을 제공합니다.
마지막으로 'process.exit(0)' 를 호출하여 프로그램을 종료합니다 '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
1 ) getProjectDir(args.[0] ) 사용자가 제공한 프로젝트 디렉토리를 가져오고 인자로 'args.[0]' 를 사용합니다. 이 위치는 인자가 'next start' 명령어에 전달한 프로젝트 디렉토리 입니다.
2 ) args['--hostname'] : 사용자가 제공한 호스트 이름을 가져옵니다.
3 ) getPort(args) 사용자가 제공한 포트를 가져옵니다.
4 ) keepAliveTimeoutArg : 사용자가 제공한 keep-alive 타임아웃을 가져옵니다. 이 값은 서버가 비활성 연결을 닫기 전에 대기할 최대 시간을 밀리초로 설정합니다. 만약 사용자가 유효하지 않은 값을 제공하면 , 오류 메시지를 출력하고 프로그램을 종료합니다. keepAliveTimeout : keepAliveTimeoutArg 값을 반올림한 결과를 저장합니다. 사용자가 제공하지 않으면 이 값은 undefined 가 나옵니다.
이 코드를 통해 Next.js는 사용자가 제공한 인자를 바탕으로 서버를 설정할 수 있습니다.
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,
})
1) loadConfig : next.js 의 설정을 로드하는 함수 입니다. 첫 번째 인자로 프로덕션 서버의 단계를 나타내는 PHASE_PRODUCTION_SERVER, 를 넘겨줍니다.
두번째 인자는 사용자가 입력한 또는 기본적으로 현재 디렉토리를 나타내고 있는 dir 을 넘겨줍니다. 프로젝트의 설정을 반환!
2 ) startServer 이 함수는 서버를 시작하는 역할을 합니다. 사용자가 입력한 설정들 과 함께 서버를 시작합니다. 개발모드가 아닌 프로덕션 모드를 서버로 시작하고 useWorkers: !!config.experimental.appDir, 설정에 따라 워커를 사용할지 여부를 결정합니다. 간단히 말하면 Next.js 애플리케이션의 설정을 로드하고 , 해당 설정에 따라 서버를 시작하는 작업을 수행합니다.