[엘리스 sw 엔지니어 트랙] 26일차 npm, 모듈, CSR, SSR

오경찬·2022년 5월 17일
0

수업 26일차

드디어 오늘은 백엔드의 기초를 배우는 날이다. 엘리스 코딩캠프를 시작하기 전에는 프론트엔드, 백엔드의 의미도 모르고 있었는데 프론트엔드 맛보고 벌써 백엔드를 맛보는 날이다. 수업을 들으면서 이게뭐지 저게뭐지 생소한게 많았던 날이였던거 같다.

이론

  • npm: 패키지 관리 도구, 패키지 저장소 이름, 오픈소스 패키지가 저장되어 있음
    npm install [package]: node_modules 폴더 내에 패키지가 저장
    npm i [package]: install 축약형
    npm install --save-dev [package]: jest 같은 테스트 패키지를 저장할 때 사용
    dependencies: 프로젝트의 의존성 패키지 목록 및 버전을 명시
    devDependencies : 개발 및 테스트에만 필요한 의존성 패키지 목록 및 버전을 명시
    package-lock.json: 자동으로 생선되는 파일, 의존성 트리에 대한 정보, git에 업로드시 같이 올려야함
    package.json: scripts - npm run 명령어로 실행할 스크립트 작성
    npx : 패키지를 손 쉽게 실행하기 위한 명령어
    모듈 : 어플리케이션을 구성하는 개별적 요소
    process.version: node.js의 버전
    process.execPath: node.js의 경로
    process.env: 실행되는 환경변수
    process.argv: 실행될 떄 넘겨받는 매개변수
    process.cwd(): 프로그램 실행위치
    process.uptime(): 프로그램이 실행된 시간
    process.exit(): 프로그램 종료
    server side rendering: 서버에서 랜더링을 하여 처리후 넘겨줌
    client side rendering:
    라우팅: 엔드포인트에 따라 응답을 매칭 해주는것
    프레임워크: 프로젝트의 전체적인 틀
    express: Node.js를 통해서 서버를 손 쉽게 만들기 위한 프레임워크
    express 쓰는 이유
    단순함: 다른 프레임워크에 비해서 매우 심플하다.
    미들웨어: 요청이 들어오고, 응답되기 전 사이를 다룰 수 있다.
    라우팅: 정말 단순한 코드로 라우팅을 다룰수 있다.
    커뮤니티: 압도적인 점유율로 사용되고 있어서, 참고할 자료가 많다.
    nodemon: 편리한 개발 환경을 위한 도구

npm

npm은 명령어 집합이라고 생각하시면됩니다. npm을 통해서 자바스크립트 라이브러리를 설치하고 관리합니다.

node 설치로 npm을 사용할 수 있습니다.

package.json

npm init

{
  "name": "npmtest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "fdsa09876",
  "license": "MIT"
}

기본적으로 생성되는 파일입니다. 나머지는 명령어 과정에서 생성하지만 scripts는 알아서 생성됩니다. scripts는 터미널에 치는 명령어의 별칭 모임입니다. 터미널에 명령어를 실행하면 Error: no test specified\" && exit 1에러를 발생합니다.

npm run test

run은 생략가능합니다. 보통 scripts에 start: index로 수정해서
npm start로 실행합니다.

package.json은 프로젝트의 전반에 대한 정보와, npm을 활용하기 위한 정보가 모여있는 파일입니다.

일반적으로 루트 디렉토리에 위치하기 때문에 npm을 통해 만들어지는 node-modules 파일과 헷갈리면 안됩니다.

npm로 라이브러리를 다운받으면 node-modules에 저장되고 package를 통해 정보를 알려준다고 생각하시면 됩니다.

node-modules vs package.json

node-modules은 실제 프로그램을 실행시키기 위한 모듈이 저장되어 있습니다. package.json은 말했듯이 정보를 모아놓은 파일입니다.

package.json을 설명드린 이유는 npm을 사용하면 package.json는 자동 생성되기 때문입니다.

package파일이 필요한 이유는 다양합니다. 대표적인 이유는 프로젝트 사용 및 배포할 때 패키지를 참고해서 어떤 라이브러리가 필요한지 확인할 수 있습니다.

정보만 공유하면되니까 사용자는 선택적으로 라이브러리를 사용할 수있고, 배포 속도는 빨라질 것입니다. 팀 프로젝트라면 더욱 필요성이 높을 것입니다.

배포할 때 node-modules은 빼고 package.json만 배포합니다.

npm i

이후 npm i를 통해 package에 있는 라이브러리를 다운받습니다.

배포뿐만 아니라 init가 아니고 직접 package를 작성했더라도 npm i를 통해서 모듈과 lock 파일을 다운받아야 합니다.

package파일을 사용하지 않는다면 일일이 script를 통해서 라이브러리를 사용해야 하므로 불편합니다.

devDependencies와 dependencies

package.json 파일 목록에 대한 명세는 방대하고 선택적임으로 링크를 참고해서 파악하시는 게 좋을 듯 합니다.

package.json 관리 목록 중 많이 헷갈리는 의존성에 대해서만 살펴보겠습니다.

단적으로 devDependencies는 개발용, dependencies는 배포용입니다.

npm install --save or npm i
dependencies <배포 의존성>

npm install --save-dev or npm i -D
devDependencies <개발 의존성>

devDpendencies은 최종 애플리케이션 빌드시 코드 안에 포함되지 않습니다. 따라서 배포용으로 사용하지 않는 라이브러리는 devDependencies에 저장하면 됩니다.

Node.js 모듈

브라우저 상에서 동작하는 JS는 script tag로 로드하며 복수의 JS 파일을 로드할 경우 하나의 파일로 merge되며 동일한 유효범위를 갖게된다.

  • ES6에서는 클라이언트 사이드 JS 에서도 동작하는 모듈 기능을 추가하였다. 👉 키워드 export, import

Node.js는 모듈 단위로 각 기능을 분할한다.

  • 모듈과 파일은 1:1 대응 관계를 가지며
    하나의 모듈은 자신만의 독립적인 스코프를 가진다.
    전역변수 중복 문제가 발생하지 않는다.

모듈은 module.exports 또는 exports 객체를 통해 정의하고 외부로 공개한다. 공개된 모듈은 require 함수를 사용해 임포트한다.

exports

모듈 안에 선언한 모든 것들은 기본적으로 해당 모듈 내부에서만 참조 가능하다.

이를 외부에 공개하여 다른 모듈에서 사용할 수 있도록 해주는 것이 export 객체이다.
전역 함수 require()로 추출한다.

// circle.js
const { PI } = Math;
exports.area = (r) => PI * r * r;
exports.circumference = (r) => 2 * PI * r;

// app.js
const circle = require('./circle.js'); // == require('./circle')

console.log(`지름이 4인 원의 면적: ${circle.area(4)}`);
console.log(`지름이 4인 원의 둘레: ${circle.circumference(4)}`);

module.exports

export 객체는 프로퍼티/메소드를 여러개 정의 할 수 있는 것에 반해 module.exports에는 하나의 값(원시 타입, 함수, 객체)을 할당할 수 있다.

require()로 할당받은 변수는 module.exports에 할당한 값 자체이다.

exports는 module.exports의 참조이며 module.exports의 alias이다. 즉, exports는 module.exports와 같다고 보아도 무방하다.

module.exports에 함수를 할당하는 방식

// foo.js
module.exports = function(a, b) {
  return a+b;
};

// app.js
const add = require('./foo');

const result = add(1, 2);
console.log(result);

module.exports는 1개의 값만을 할당할 수 있기에 다음과 같이 객체를 사용하여 복수의 기능을 하나로 묶어 공개하는 방식을 사용할 수 있다.

exports에 객체를 할당하는 방식

// foo.js
module.exports = {
  add (v1, v2) { return v1 + v2 },
  minus (v1, v2) { return v1 - v2 }
};

// app.js
const calc = require('./foo');

const result1 = calc.add(1, 2);
console.log(result1); //3

const result2 = calc.minus(1, 2);
console.log(result2); //-1

require

require 함수의 인수에는 파일뿐만 아니라 디렉터리를 지정할 수도 있다.
모듈을 명시하지 않는 경우에는 해당 디렉터리의 index.js를 로드한다.

project/
├── app.js
└── module/
├── index.js
├── calc.js
└── print.js

// app.js
const myModule = require('./module');

// module/index.js
module.exports = {
  calc: require('./calc'),
  print: require('./print')
};

app.js 에서의 한 번의 require로 module/ 디렉터리 하위의 모든 모듈들을 사용할 수 있다.

코어 모듈과 파일 모듈

  • 코어모듈 : Node.js가 기본으로 포함하는 모듈. 패스를 명시하지 않아도 무방하다.
    const http = require('http');
  • npm의 통해 설치한 외부 패키지 : 패스를 명시하지 않아도 무방하다.
    const mongoose = require('mongoose');
  • 파일 모듈 : 위 두 종류를 제외한 나머지. 반드시 패스를 명시하여야 한다.
    const foo = require('./lib/foo');

CSR

간단하게 비유하면 "비조리형 배달음식"으로 볼 수 있다.
식당에서 재료만 손질해서 전달 주면 고객이(client) 알아서 음식을 완성해서 식사하는게 최종 형태를 브라우저에서 완성하는 CSR과 비슷하다고 할 수 있다.

조금 더 사전적으로 정의하여보면, "웹 페이지의 렌더링이 클라이언트 측에서 이루어지는 것"을 의미한다.
브라우저가 최초로 서버에 Request를 보내면, html, css, js파일을 차례로 다운로드 한다.
React를 사용하여 페이지를 구현하였을 경우, html만 받아졌을 때는 페이지가 비어져있다가 javascript가 모두 다운로드 완료되어야 그제서야 화면에 컨텐츠가 그려진다.

우리가 React를 CRA를 사용해서 생성할 경우 렌더링이 CSR방식으로 일어나게 된다.

특징

  • 처음 request를 보낼 때만 서버와 통신이 이루어지기에 서버 호출을 최소화 할 수 있다.
  • 새로운 페이지로 이동하더라도 html자체가 바뀌는 게 아니라 Javascript 차원에서 새로운 화면을 그려낸다
  • SPA를 구현할 때 많이 사용한다(CRA)
  • 마지막에 javascript가 다운로드되면서 화면이 나타나기에 TTI와 TTV가 동시에 일어난다

단점

  • SEO에 불리하다
    첫 페이지가 비어있기에 검색 엔진이 페이지 내용을 크롤링 하지 못한다. 구글은 조금 개선되었다고는 하지만 아직까지는 SSR 대비 전반적으로 불리한 편이다.
  • UX도 SSR에 비하면 불리하다
    TTV와 TTI가 동시에 나타난다는 것은 view가 완성되기까지도 시간이 걸린다는 것이기에 사용자 경험 입장에서 약간 불리한 면이 있다.

SSR

CSR과 반대로 "완조리형 배달음식"을 떠올리면 된다.
식당에서 음식을 완성해서 배달하면 고객은 먹기만 하면 되는거다.
일일이 조리를 다 해야하기에 주방이(서버가) 바쁘다는 특징이 있다.

이것도 사전적으로 정의해보면, "첫 페이지 렌더링을 클라이언트가 아닌 서버에서 진행하는 것"이라고 볼 수 있다.
서버에서 먼저 HTML,CSS를 렌더링 해서 정적인 화면을 먼저 client측에 전달해주고 나중에 동적인 요소가 필요한 경우에 client로 JS를 가져와서 활용하는 형태이다.

특징

  • SEO에 유리하다
    서버에서 사용자에게 보여줄 페이지를 모두 구성하여 사용자에게 보여주는 방식이기 때문에 CSR의 단점인 "첫 페이지 깡통" 상태를 극복할 수 있다.
  • UX가 좋다
    구성하는 속도는 느리지만, 전체적으로 사용자에게 보여주는 콘텐츠 구성이 완료되는 시점이 빠르다
  • HTML, CSS가 1차례 들어오고, 그 다음에 JS가 처리되기에 TTV와 TTI간 시차가 있다.

단점

  • 서버의 부하가 커진다
    아무래도 서버에서 다 처리하는 형태이기 때문에 request가 많이 들어올 경우 부담스러워진다
  • 용량이 너무 큰 경우 첫 페이지 로딩이 너~무 오래 걸릴 수 있다.

SPA for SSR

SEO 최적화를 이루어내면서 동시에 SPA를 활용하여 쾌적한 사용환경을 만들 수 없을지 여러 사람들이 고민하였고, 그 결과로 SPA for SSR이 등장하게 되었다.
그 방법인 즉슨 1. 첫 렌더는 SSR방식으로 진행하고, 2. 두번째 렌더부터는 CSR로 진행하는 것이다.

profile
코린이 입니당 :)

0개의 댓글