본문 바로가기
Today I learned

[react] 2 주차 - webpack으로 모듈화 그리고 create React App

by soheemon 2020. 1. 18.

 

지난주 복습
  • reactElement는 DOM이 아니다. DOM에 부합하는 json이다.
  • createElement를 사용하기는 어려워서 JSX를 사용한다. bebel에서는 JSX문법을 createElement로 변환해준다.
  • component - 작은 UI조각. componenet가 이루어져서 component Tree가 만들어진다.
  • function component, class component (상태를 가짐)
  • Component사이의 통신 - 1) props: 부모와 자식간의 통신 2)state: 화면에 동적인 기능을 추가 할 수 있다.
  • eventHandler: 함수 호출이 아닌 함수가 와야 한다.

 

지난주에 배운 방식으로는 하나의 페이지에서 작업 할 수 있게 되었다.

하지만.. 모든 페이지에서 rootElement를 만드는등의 개발을 위한 초기 작업을 진행해야 하는지에 대해서 의문이 생긴걸이다.

 

페이지를 모듈화하자 SPA

페이지를 모듈화하여, 웹사이트 전체를 하나의 웹으로 만든다.

->create-react-app을 사용하자.

 

의존성

- node 8.10.x 설치

- git 설치

 

npx 설치

npx는 create-react-app을 global로 설치하지 않고 실행하게 해주는 유틸리티이다.

npx create-react-app ${프로젝트명}

프로젝트가 생성된것을 볼 수 있다.
실행 후 위와같은 명령어들을 확인 할 수 있다.

start - 개발모드에서 앱을 연다

 

 

terminal을 직접 실행 할 수도 있다.
스캐폴딩 - 앱을 개발하는 최소한의 환경을 구축한 상태.
자동으로 브라우저를 띄워준다.

  • npm run build

개발이 끝났을때 사용 하며, build 폴더 생성한다.

build폴더 하위에는 build 결과물이 생기고, 이것들을 웹서버에 올리면 실행이 된다.

build 폴더 생성. 웹서버에 배포할 폴더가 된다.
package.json을 확인하면 dependencies, 명령어들을 확인 할 수 있다. 

최신 frontEnd를 하려면 webPack을 알아야 한다.

WebPack

webpack은 여러가지 모듈을 모아서 하나로 만들어주는 모듈 번들러이다.
페이지 방식으로 된 웹페이지를 하나 만들고 모듈 방식으로 변경해가면서 왜 웹팩같은 모듈 환경으로 옮겨가야 하는지 이해해 보자.

 

//index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>webpack demo</title>
  <script src="https://unpkg.com/lodash@4.16.6"></script>
</head>
<body>
 
<script src="./src/index.js"></script>
 
</body>
</html>

//src/index.js
function component() {
  let element = document.createElement('div');
 
  // Lodash, currently included via a script, is required for this line to work
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');
 
  return element;
}
 
document.body.appendChild(component());

 

페이지 방식의 문제점
  1. global환경에 하나의 페이지에 로드된다.
  2. 의존성이 생긴다
  3. 페이지가 바뀔때 마다 이전페이지에서 로딩했던 동일한 자바스크립트 파일들이 다시 로딩되어야 한다.

웹은 문제가 없지만 앱모바일이 등장하면서 페이지가 바뀔때 마다 많은 자바스크립트와 css가 로딩이 되는것은 네트워크 트래픽 증가와 속도의 저하를 가져오게 되면서 SPA 프레임웍이 등장하게 된다.

 

차례대로 코드를 실행하다, script를 만나면 blocking되고 해당 스크립트를 가져온 후 실행된다.

script가 실행되면 해당 스크립트의 파일들은 하나의 페이지에 로딩이 된다! 이게 한페이지라는 의미임! 한페이지에서 실행됨!

=> 그래서 jQUery를 가져오면 $가 global 변수가 되는것이다

=> 페이지 방식의 문제점! 충돌이 날 수 있음..! js에서는 충돌을 방지하기 위해 네임스페이스 패턴이나 IIFE 패턴 여러가지 패턴을 쓴다.

css로딩은 head에서 해야한다. body에 넣으면 화면이 깜빡이는 느낌이 들 수 있음!

body에서 lodash@4.16.6스크립트를 불러오면 안된다..! 왜냐 index.js에서 _를 쓰고있기 때문... 동기방식이라서... => 의존성에 문제가 생긴다.. 반드시 라이브러리를 먼저 불러와야 한다...!

 

모듈 방식

webpack

의존성 그래프. 엔트리포인트부터 시작해서 빌드를 한 후 결과물을 만들어낸다. 가운데 큐브는 pack을 의미한다. 

webpack은 bundler라고도 부른다.

 

-WebPack tutorial에서 가장 중요한 4가지.

-Entry

-Output

-Loader

-Plugin

 

하나의 페이지가 하나의 모듈이 된다.

모듈을 정의하고 export 하면, 다른곳에서 import 해서 가져다 쓸 수 있다. 

 

잠깐의 흥미로운 곁다리
  • 디자이너가 없으면 CSS 오픈 라이브러리를 활용 할 수 있다.
  • custom-Element: react에서 하는것도 하나의 custom-Element HTML5에서 표준화 진행중.
  • UI 컴포넌트 - create-react-app으로 만드는것도 하나의 컴포넌트
  • README.md에 실행방법을 명시하는것은 중요하다.
  • react-cli , sass(css전처리기) post css(css후처리기) 
모듈 저장소 만들기
npm init

npm init : 모듈저장소를 만드는 명령어. package.json파일을 만든다. package.json파일은 모듈방식 개발에서 가장 중요한 환경파일이다.

 

#의존성 모듈 설치
npm install --save lodash
#web-pack 설치
npm install webpack webpack-cli –save-dev

"webPack - package dependency.

폴더가 더 많은 이유는 dependency의 dependency가 많기 때문이야... npm은 npm저장소의 라이브러리끼리의 의존성을 관리해준다..! 이때 package.json을 참조해서 관리한다."

 

loadash라는 모듈은 누군가 모듈화 한 후 npm 저장소에 넣어두었다.

그렇기 때문에 install 명령을 사용하면 그 저장소에서 모듈을 다운로드해서 설치하게 된다.

모듈방식에서는 lodash라이브러리를 먼저 가져온뒤에 필요한 부분만을 가져와서 배포하게 된다.

  • lodash는 형상관리 대상이 아니다! 다른개발자가 받으면 형상관리에 없겠지... 하지만 사용하고 있다는것을 알리기 위해 의존성을 명시해준다.
  • --save 옵션은 의존성 모듈을 package.json 파일에 기록하라는 의미이다.
  • 이와 비슷한 -save-dev는 개발 의존성을 package.json에 기록하라는 의미이다. 실제 배포할때는 필요없지만 개발할때만 필요한 모듈이라는 뜻.
  • dependency: 실제 소스에서 사용하는 라이브러리. devDependencies: 개발에서 사용하는 라이브러리... 상용에 배포하면 크기가 커지기 때문에 분리를 한다! 

이 모듈을 설치 한 다음 node_modules를 열어보면 수많은 파일들이 있다. 이는 lodash가 의존하는 여러 모듈들이 있기 때문에 그 모듈들이 먼저 설치된 다음 loadsh모듈이 설치 된 것임.

 

실행하지만 실행이 안된다.

설치 이후 아래와 같이 변경한다.

import _ from 'lodash'; 
 
function component() {
  let element = document.createElement('div');
 
  // Lodash, currently included via a script, is required for this line to work
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');
 
  return element;
}
 
document.body.appendChild(component());

처음 실행하면 실행이 안된다

아직 import 혹은 require이라는 모듈 방식을 브라우저가 이해하지 못하는 방식이다.

그래서 브라우저가 이해할 수 있도록 lodash에서 필요한 부분만을 꺼내와서 컴파일하고 별도의 자바스크립트 화일을 생성하도록 해야 한다.

이것을 수행하는 역할이 웹팩의 역할이다.

 

# 컴파일 명령어
npx webpack
  • main.js는 우리가 만든 index.js랑 loadash가 들어있다.
  • 아무런 옵션을 주지 않으면 Default Entrypoint는 src의 index.js이고, output은 dist폴더의 main.js이다.
  •  

실행결과 흐헉허겋거헉ㅎ

사용자가 entryPoint와 output을 직접 설정 할 수는 없을까? - webpack.config.js

"You can configure this part of the process by specifying an output field in your configuration:"

webpack에서 가장 중요한 두가지는

-entry point라는 진입점과

- output 폴더라는 번들링된 결과이다.

webpack.config.js 파일을 사용해서 deafult설정 말고 사용자 임의로 설정해서 사용 할 수도 있다.

 

결과는 default설정으로 사용할때와 동일하다. default설정 말고 사용자가 임의로 설정할 수 있음을 테스트 한것이다.

 

 

HtmlWebpackPlugin

index.html을 build 폴더에 복사하고 컴파일된 js 파일을 index.html에 자동으로 주입하는 모듈

옵션 확인

#개발의존성패키지로 설치
npm install --save-dev html-webpack-plugin
#start를 build로 바꿨다.
npm run build

 

자동으로 index.html이 생성되고, main.js를 가져오는것을 확인 할 수 있다.
plugins를 설정해준다. 플러그인 편해. 자동화 너무좋아.

 

 

 

파일을 변경하고 저장하면 수정된 내용을 바로 반영하고 확인하는 HMR 기능을 제공하는 모듈
#install, --saveDev 줄임
npm i -D webpack-dev-server

 

global이 아니라 npm모듈로 실행하게 된다. 그래서 명령어가 npm run start임.

 

8080 접근시..

load - css

css, ES6문법들은 별도의 load를 사용해야한다. 전처리 css 후처리 css... 뭐야어려웡

 

페이지 방식에서는 index.html에 include했었다면..! 모듈방식에서는 어떻게 할까?!

 

loader에는 여러가지 종류가 있다.

 

css 파일을 import하기위해 사용
DOM으로 css를 inject하기위해 사용

 

 

index.js에서 loadsh 뿐만아니라 style.css도 가져온다.

 

module 룰을 설정 할 수 있다. 확장자가 css라면 css-loader, style-loader 순으로 실행하게 된다.

 

 

 

 

 

/*npm run start 명령어가 실행된다.*/

script에서 설정을 하면 명령어를 설정 할 수도 있고 초록색 화살표를 눌러서 직접 실행 할 수도 있다.

중간정리

webpack 좋은점

  • 하나의 css로 만들 수 있다.
  • css in js : js안에 css를 넣는다.
    • css-loader: 떨어져있는 열개의 css를 하나로 뭉친다. => js변수로 만든다.
    • style-loader: js변수를 꺼내서 style태그를 동적으로 붙여준다.

 

css-loader: 떨어져있는 css를 합쳐서 js변수로 만든다. style-loader: js변수를 꺼내서 동적으로 붙여준다.

결과물인 main.js에는 css가 없다...! 어디에 적용되어있을까..? string 형태로 들어가 있다. 

 

css를 load하는것이 아닌 모은 css들을 css파일로 만들어주는 플러그인.

npm install --save-dev mini-css-extract-plugin

 

플러그인 설치 후.. 설정 + npm run build.. 새로 main.css를 만들어준다.

 

load - 전처리

css도 종류가 전처리/후처리로 나뉜다..

브라우저는 css만 이해한다 그래서 css로 컴파일 해야함.

전처리는 아마 scss를 css로 변환해주는것 같다..?

 

 

 

 

 

 

sass-loader를 가져오는 역할 node-sass는 컴파일 해주는 역할.

 

load - 후처리

post css - 수많은 플러그인 중 auto prefix 사용많은 플러그인 중 autoprefixer는 자동으로 vendor 별 prefix를 붙여주는 플러그인이다.

예를 들어, CSS3에 도입된 border-radius 속성은 표준속성이며 각 브라우저에서는 다음과 같이 해야 한다. 

webkit-border-radius : 사파리, 크롬 
moz-border-radius: 파이어폭스 

autoprefixer를 사용하게되면 표준속성만 사용하더라도 이 플러그인이 자동으로 브라우저 호환 속성들을 추가해주게 된다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

곁다리

node에서 사용. 환경변수를 가져 올 수 있음

+

개발서버는 변경사항을 watch하고있다가 변경해주지만

module은 3rd-party라 껐다 켜야함.

 

댓글