NEXT를 3개월 배우고, 쓰기 시작한지 4개월이 다 되어가는 지금, 매일 넥스트의 인사를 몇 번이고 받는 나지만.... !!
이번 10월 챌린지를 통해 NEXT의 작동원리와 개발환경에서 무심코 넘어갔던 것들을 정확히 파악하고자! 챌린지를 시작한다 !
리액트가 그렇게 좋은데, 왜 굳이 NEXT를 쓸까? 🧐
잘 생각해보면 이 질문에 대한 대답들이 이번 프리온보딩 챌린지 블로깅 과제였다!
```
-
- CSR(Client-side Rendering)이란 무엇이며, 그것의 장단점에 대하여 설명해주세요.
- SPA(Single Page Application)로 구성된 웹 앱에서 SSR(Server-side Rendering)이 필요한 이유에 대하여 설명해주세요.
- Next.js 프로젝트를 세팅한 뒤 yarn start 스크립트를 실행했을 때 실행되는 코드를 nextjs github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.
- https://nextjs.org/docs/getting-started (Next.js 세팅 가이드)
- https://github.com/vercel/next.js/ (Next.js Github 레포지토리)
```
질문을 보자마자 너무너무 설레었고,
개발하면서 1,2번의 개념과 + diffing, hydration의 원리가 생각보다 브라우저에 나타낼때 아주중요함을 깨달은 적이 많았기에..!
확실하게 알고 제대로 넘어가고 싶었다....!!!
NEXT는 장단점이 극명하지만, 프론트엔드 개발자에게는 아주 중요한 포인트들이 많아서, 어물쩡하게 개념을 잡고 넘어가면 안된다 !
제대로 공부할 준비를 해보자 ! 😆💛
1. CSR(Client- Side- Rendering)이란 무엇이며, 그것의 장단점을 설명하세요
- CSR이란?
Client - Side - Rendering 의 줄임말 이다!
즉, 클라이언트 쪽에서 렌더링을 한다! 는 말로 간단히 이해하면 쉽다.
서버에 요청이 들어오면, 서버는 JSON 데이터만 넘겨주고 클라이언트에서 (즉, 브라우저에서)
HTML 생성부터 CSS, JS파일을 가지고 뼈대를 만들고,
트리구조를 만들며 보여지는 화면을 브라우저에서 만들고 완성하게 된다!
* 반대개념 SSR : Server-Side-Rendering의 약자로, 서버에서 모든 렌더링 과정을 마치고 클라이언트에 보내주는것을 의미한다. 따라서 요청시 마다 새로고침이 일어나며 서버에서는 계속 새로운 페이지에대한 요청을 받게 된다.
- CSR의 단점
크게 두가지 단점을 들 수 있다.
1. 첫 로딩시간이 오래걸린다.
2. SEO(Serch Engine OPtiization)에 취약하다.
1번의 이유는, 클라이언트에서 준 JSON형태의 데이터를 가지고,
HTML을 그리는 작업부터 브라우저 렌더링작업 , 즉 돔트리구조 형성까지 브라우저에서 이루어저야 하기때문에,
서버에서 렌더링을 다 마치고 보내주는 SSR에 비해 초기 로딩속도가 느리다는 단점이 있다.
(컴퓨터 사양에 따라 예외인 경우도 존재한다.)
2번의 이유를 이해하기 위해서는 SEO의 개념을 알아야 한다.
* SEO란 ? 검색엔진최적화로, 웹사이트가 검색결과에 더 잘 노출되도록 최적화하는 과정이다.
쉽게 이야기하면,
CSR은 방식은 서버에서 클라이언트로 보내줄때 가공되지 않은 JSON데이터만 보내주기 때문에 검색엔진에 걸려서
다양한 웹사이트에서 보여지도록 노출되는 키워드들을 크롤링봇이 인지하지 못한다.
하지만 SSR은 서버에서 렌더링이 다 되어 , 중요한 노출 키워드나 핵심 마케팅 단어들이 크롤링봇들이 인식이 가능하고,
해당 페이지는 다양한 사이트에서 노출될 확률이 훨씬 높다.
따라서 광고나 마케팅이 매출에 큰영향을 끼치는 페이지는 당연히.. SSR을...!!
- CSR의 장점
클라이언트에서 렌더링을 하기 때문에,
CSR은 최초 요청시 서버에서 모든 페이지에 대한 JSON 정보를 다 불러오게 된다.
그러므로
1. 후속페이지의 로딩시간이 확연히 빠르다. 는 장점이 있다. 또한 당연히 2. 새로고침이 일어나지 않는다.
모든 페이지가 최초로 한번 데이터를 받아 로딩이 되기 때문에 당연히 다시 데이터를 받아올일이 없는것이다.
새로고침이 일어나는 페이지와 일어나지 않는 페이지를 비교해본다면 이 장점이 얼마나 매력적인지 알 수 있다.
2. SPA로 구성된 웹 앱에서 SSR이 필요한 이유에 대하여 설명해주세요.
이를 이해하기 위해서는 당연히 SPA의 개념과 MPA의 개념을 알아야하지.. !!
MPA (MultiPageApplication)
- 클릭 시 마다 새롭게 페이지를 만들어 보내주는 것. (따라서 SSR방식이지!)
매번 새로고침이 되어 렌더링이 새로 이루어지며, 싱글로 존재하는 여러개의 페이지들이 있다.
SPA(SinglePageApplication)
- 한개로 구성된 단일한 페이지이다. 전체 페이지를 통으로 하나의 페이지로서 받아온다고 생각하면 된다 !
따라서 CSR방식이며, 최초로딩시에만 리소스를 로딩한다. 필요한 데이터가 있을때에만 서버에서 데이터를 받아오게 된다.
-> 그럼 이 방식에서 SSR이 왜 필요할까 ?
위에서 언급한 CSR의 단점 때문이다.
그 중 검색엔진 최적화 즉, SEO를 용이하게 하기 위해 특정 페이지만 SSR처리를 해줄수 있다.
예를들어, SPA를 사용하고 있는 한 회사의 홈페이지에서 노출이 많이 되어야 매출이 올라가는
광고,마케팅이 중요한 특정 페이지가 있을것이다.
그렇다면 그 페이지 때문에 MPA방식으로 바꿀것인가 ? 아니다 !
특정 페이지만 SSR처리를 해주면, 검색엔진봇이 크롤링을 통하여 SEO최적화에 용이하도록 작업할 수 있다.!
본인 또한, 넥스트를 사용하면서 getServerSideProps를 활용하여 특정페이지를 SSR방식으로 바꾸어준적이 있는데,
생각보다 어렵지 않았다!
간단하게 설명하면, 넥스트는 특정페이지의 SSR을 지원하기 때문에
Browser에 화면을 그려주기전에 프론트 서버에서 한번 프리렌더링을 하게 된다.
따라서 서버에서 프리렌더링을 할때 필요한 데이터와 정보들을 페이지에 넣어주면 되고 ,
해당 데이터들이 검색봇에 노출이 잘 되도록 개발해주면 된다 !
3. Next.js 프로젝트를 세팅한 뒤 yarn start 스크립트를 실행했을 때 실행되는 코드를 nextjs github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.
이 질문은 보고 약간 의아했는데, 살짝 이해할수록 점점 설레였다! ..
헉 설마 넥스트 작동로직을 파고 들어가서 나의 로컬호스트가 어떠한 코드로 돌아가고 있는지 찾아보라는건가?!
라는 마음이 들어서 설레였고, 아예 모르는 언어일텐데 어떻게 찾고 어떤 이유를 붙일수 있지?..라는 걱정도 있었지만..
매일 Next를 쓰면서도 막상 넥스트 레포를 들어가서 뜯어본적은 없기에 굉장히 신선한 과제라고 생각했다.!
1. 일단 늘 그렇듯 npx c-n-a를 통해 앱 하나 생성했다!
2. yarn start를 하기위해서는 yarn build를 통해 production의 사용이 가능한 앱을 먼저 빌드해주고,
("next build" - Runs to build the application for production usage)
*출처 : NEXT.js docs https://nextjs.org/docs/getting-started
3. 그리고 yarn start를 하면 nextjs의 프로덕션 서버가 시작된다 !
("next start" - Runs to start a Next.js production server)
*출처 : NEXT.js docs https://nextjs.org/docs/getting-started
그러면 이제 내 next앱의 프로덕션이 만들어지고 서버가 열렸는데..
이것이 어떠한 코드를 통해 프로덕션 서버가 열리고,, 작동을 하는지 next 레포를 들어가봤다!
처음보는 넥스트의 구성파일들을 봐서 약간 당황스러웠지만..
사실 갓 깃 헙 ! 커밋메시지 보면서 이 폴더가 뭐하는곳인지 약간씩 유추가 가능했다 !!
4. test/의 production을 들어가 보았더니 뭔가 폴더명들이..
하나 하나의 기능들이 작동하는 원리들이 모여있는 느낌이었다... !
5. 게다가 pages폴더를 들어갔더니.. 세상에! 우리가 사용하는 많은 기능들과 익숙한 말들이 있어서..
아 여기는 테스트를 진행하고 여기서 디버깅이 완료되면 프로덕션으로 가는구나! 라고 생각했다.
6. 따라서 레포의 메인에서 우리는 yarn start를 통해 script를 실행시켰으니, 스크립트 폴더를 들어가 보았다.
그리고 그 안에서 하나의 독립적으로 존재하는 파일들을 따라 들어가보니, main.rs라는 파일을 만나게 되었는데....!
정말 모르는 말 투성이었다.. .rs가 궁금하여 찾아보았는데,
러스트프로그래밍 ( Rust는 현대적인 시스템 프로그래밍 언어로,
C/C++와 동등한 수준의 속도를 달성하면서 안전성, 동시성을 목표로 함)
이라는 언어로 작성이 되어있었다. 따라서 코드를 좀 더 뜯어보았다.
use reqwest::blocking::Client;
use serde_json::{Map, Number, Value};
use std::env::args;
use std::fs::File;
use std::io::{self, BufRead};
use std::path::Path;
/// Read individual lines from a file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
/// Log the url to view the trace in the browser.
fn log_web_url(jaeger_web_ui_url: &str, trace_id: &str) {
println!(
"Jaeger trace will be available on {}/trace/{}",
jaeger_web_ui_url.to_string(),
trace_id.to_string()
)
}
/// Send trace JSON to Jaeger using ZipKin API.
fn send_json_to_zipkin(zipkin_api: &str, value: String) {
let client = Client::new();
let res = client
.post(zipkin_api)
.header("Content-Type", "application/json")
.body(value)
.send()
.expect("Failed to send request");
println!("body = {:?}", res.text());
}
// function to append zero to a number until 16 characters
fn pad_zeros(num: u64) -> String {
let mut num_str = num.to_string();
while num_str.len() < 16 {
num_str = format!("0{}", num_str);
}
num_str
}
fn main() {
let service_name = "nextjs";
let ipv4 = "127.0.0.1";
let port = 9411;
let zipkin_url = format!("http://{}:{}", ipv4, port);
let jaeger_web_ui_url = format!("http://{}:16686", ipv4);
let zipkin_api = format!("{}/api/v2/spans", zipkin_url);
let mut logged_url = false;
let mut local_endpoint = Map::new();
local_endpoint.insert(
"serviceName".to_string(),
Value::String(service_name.to_string()),
);
local_endpoint.insert("ipv4".to_string(), Value::String(ipv4.to_string()));
local_endpoint.insert("port".to_string(), Value::Number(Number::from(port)));
let first_arg = args().nth(1).expect("Please provide a file name");
if let Ok(lines) = read_lines(first_arg) {
for line in lines {
if let Ok(json_to_parse) = line {
let v = match serde_json::from_str::<Vec<Value>>(&json_to_parse) {
Ok(v) => v
.into_iter()
.map(|mut data| {
if !logged_url {
log_web_url(&jaeger_web_ui_url, &data["traceId"].as_str().unwrap());
logged_url = true;
}
data["localEndpoint"] = Value::Object(local_endpoint.clone());
data["id"] = Value::String(pad_zeros(data["id"].as_u64().unwrap()));
if data["parentId"] != Value::Null {
data["parentId"] =
Value::String(pad_zeros(data["parentId"].as_u64().unwrap()));
}
data
})
.collect::<Value>(),
Err(e) => {
println!("{}", e);
continue;
}
};
let json_map = serde_json::to_string(&v).expect("Failed to serialize");
// println!("{:}", json_map);
send_json_to_zipkin(&zipkin_api, json_map);
}
}
}
}
첫째줄부터 쭉 보아하니!!
use reqwest::blocking::Client;
Client라는 단어를 봐서, 클라이언트 즉 우리의 vscode속의 next에서 요청을 받고, 또 어떠한 로직으로 실행을 시켜준 다음에..
fn log_web_url(jaeger_web_ui_url: ~~
jaeger단어가 궁금해서 찾아보니,
Jaeger Agent는 사용자 데이터그램 프로토콜 (User Datagram Protocol)을 통해 전송된 스팬을 수신하는 네트워크 데몬
이라는 너무 반가운.... 설명이 나왔고 따라서 next 사용자가 데이터 통신이 가능한 포트 접속이 가능한 Url을 열어준다는 의미같았다 !!
.
.
.
이러한 방식으로 이 파일을 쭉 내려가다보니, 포트를 열지 못했을때 반환해주는 에러메시지도 존재했고..
따라서 나는
next.js/scripts/send-trace-to-jaeger/src/main.rs
이 폴더 루트 기반에 있는 파일들을 토대로 우리의 yarn start가 실행이 된다고 생각한다 !
'나의 개발자 기록 > 개발자 취업' 카테고리의 다른 글
프론트엔드 전반 면접 단골 질문 정리 (+ 리액트 핵심 용어) (0) | 2022.12.19 |
---|---|
자바스크립트 핵심 용어정리! (프론트엔드 단골 면접 질문 모음) (1) | 2022.12.19 |
Package Manager, Localhost, GitHub 관련 간단 개념 & 용어정리 (0) | 2022.11.01 |