[React.JS] Tip: create-react-app 사용하기 + react-hot-loader 적용 + Express.js 와 함께 사용하기


9VsY9i09_400x400

Redux 를 개발한 Dan Abramov, React 가 릴리즈 된 이후에 React.js 생태계에 가장 큰 영향을 끼친 인물이 아닐까요?

2016년 7월 22일, 그가 React 블로그를 통하여 멋진 소식을 전했는데요.

gasdfg

React 작업환경을 명령어 하나로 설정 할 수 있는 “공식 도구” 를 릴리즈하였습니다! 더 이상 webpack / babel 등을 설정하느라 시간을 투자하지 않아도 되고, unofficial hot boilerplate 를 사용 할 필요도 없어요.

그는 며칠전 트위터에 다음과 같은 글을 남겼었는데요:

그는 Ember 웹프레임워크 컨퍼런스인 EmberCamp 에 갔었는데,  Ember 웹프레임워크 작업환경 설정을 쉽게 해주는 Ember CLI 을 보고는 감명을 받았다고 합니다. 그리곤, React.js 커뮤니티도 이런걸보고 배워야해! 라고 언급을 했었는데요.

그 말을 한지 10일만에 위 같은 멋진 도구를 릴리즈하였답니다.

그럼, 한번 사용을 해봐야겠죠?

이 포스트에서는 create-react-app 을 사용해보고, 추가적으로, Express 도 함께 사용하는 방법을 알아보도록 하겠습니다.

기본적으로는, react-hot-loader가 적용되어있지 않아서 이를 적용하는 방법 또한 알아보겠습니다.

 

시작하기

설치하기

글로벌 패키지를 설치해주세요. Node 버전은 4.x 이상이여야 합니다.

 

App 생성하기

위 명령어를 실행하면, create-react-app 도구를 통하여 react 프로젝트를 initialize 하구요,

그 다음에 자동으로 스크립트를 통하여 dependency package 들을 설치합니다 (webpack babel eslint 등..)

(dependency package 를 루트 프로젝트에 설치하는게 아니라 node_modules/react-scripts 디렉토리에 설치합니다)

DigitalOcean 싱가폴 서버 기준으로 이 작업은 약 3분이 걸립니다.

작업이 끝나면 다음과 같이 실행 할 수 있는 커맨드가 출력됩니다.

ffaa

package.json 을 살펴볼까요?

 

babel / webpack 등의 dependency package 들은 node_modules/react-scripts 에 설치되어있기에 여기서 보이지 않습니다.

 

서버 실행하기

npm start 명령어를 통하여 webpack-dev-server 를 시작 할 수 있습니다.

compiled-successfully

hot-reload 가 적용되어있기 때문에, 이 개발 서버를 키고, 코드를 수정하면 자동으로 적용이 됩니다.

주의: 개발서버를 열 때 0.0.0.0 이 아닌 localhost 로 열기 때문에 외부에서 접근이 불가능합니다. 이 포스트의 하단에서 커스터마이징을 할거니까 걱정하지마세요 🙂

vv

ESLint 를 통하여 경고가 있는 경우 이를 출력해줍니다

ss

Production 을 위한 빌드

npm run bulid 명령어를 통하여 production 을 위한 빌드를 할 수 있습니다. 코드가 minify 되고, envify 되고, 또 assets에 content hashes 를 통하여 캐싱이 적용됩니다.

 

설정이 없음!

구조가 정말 깔끔하죠? 설정 관련 파일이 하나도 없어요.

빌드 설정은 preconfigured 되어있고 변경 할 수 없습니다 (아 물론 node_modules/react-scripts/ 경로에 들어가시면 설정 할 수 있습니다만.. 그렇게 하면 안돼요)

이 “도구“에선 커스터마이징이 불가능합니다. 엥? 그럼 어쩌라구요!

어이가 없죠? 당황하지 마세요. 도구 글씨체가 bold 로 되어있는점 유의하세요. 이 도구에서만 커스터마이징을 불가능합니다.

그럼.. 이 도구를 제거하면 되지 않을까요? 아, 그렇다고 무작정 npm remove 를 통하여 삭제하란건 아닙니다.

다음 기능을 주목해주세요!

 

도구 Eject

이 도구의 개발자는 그렇게 사용자들을 ‘그 환경에 가둬놓으면’ 안되는걸 알기 때문에 이를 대비하여 eject라는 기능을 만들어줬습니다.

이 기능의 역할은 현재 프로젝트의 모든 설정 / 스크립트를 여러분의 프로젝트로 옮겨줍니다. eject를 하고나서는, 여러분 마음대로 커스터마이징이 가능합니다.

npm run eject 명령어를 통하여 이 기능을 사용해보세요!

이 명령어가 사용되면, 스크립트를 통하여 react-scripts 를 제거합니다.

그리고, react-scripts 에서 사용하던 스크립트들을 그대로 여러분들의 프로젝트에 생성합니다.

작업이 끝나면 디렉터리 구조가 다음과 같이 변경됩니다:

 

package.json 은 어떻게 변했는지 확인해볼까요?

패키지들이 이 프로젝트에 설치되었네요. 그리고 실행/빌드 스크립트는 똑같이 사용 할 수 있답니다.

 

꽤 멋지지 않나요? 다음 섹션에선 현재 프로젝트에서 Express 작업환경을 설정하는 방법을 알아보도록 하겠습니다.

Express 를 사용하지 않는 분들은 스킵하셔도 됩니다.

포스트 최하단에 webpack-dev-server 의 host 를 0.0.0.0 으로 바꾸고 개발서버의 포트도 변경하는 방법이 적혀있습니다.

추가적으로 현재 기본설정으로는 react-hot-loader 가 적용되어있지 않습니다. 포스트의 하단에 react-hot-loader 를 적용하는 과정도 설명되어있으니 참고하세요.

 

Express 작업환경 설정하기

React 프로젝트에서 Express 작업환경을 설정하는건 강좌 11편 에서 했었는데요, 시작하기전에 한번 참고해보시길 바랍니다.

우리는, create-react-app 을 통하여 만든 프로젝트에 Express 작업환경을 추가적으로 설정해보겠습니다.

강좌 11편에서는 서버와 클라이언트를 한 프로젝트에서 같이 사용했었는데요, 이번엔 프로젝트 안에 또 다른 프로젝트를 만드는 방식으로 진행해보겠습니다.

 

글로벌 패키지 설치

ES6 문법으로 작성된 코드를 transpile 하고,

개발환경에선 babel-node 를 통하여 바로 코드를 실행하기 위하여 babel-cli 를 설치하세요.

 

로컬 패키지 설치

path는 의존경로를 절대경로로 변환해주는 모듈입니다.

nodemon은 코드에 변화가 있을 때 서버를 재시작 해주는 모듈입니다.

 

디렉토리 구조 이해

src 폴더에 ES6로 작성된 코드가 저장되고, 나중에 이를 transpile 하여 build 폴더에 저장합니다.

 

서버 메인 파일 – src/main.js 작성

parent 디렉토리에 있는 React build 파일들을 정적파일로서 제공합니다.

 

예제 라우트 – src/routes/post.js 작성

 

인덱스 라우트 – src/routes/index.js 작성

 

서버 메인 파일 – src/main.js 수정

 

여기까지 코드 작성이 완료되었다면,

babel-node main.js --presets=es2015 명령어를 입력하여 서버를 테스팅해보세요.

 

자, 이제 스크립트를 작성해보겠습니다.

개발환경 전용 스크립트 작성 – server/src/scripts/development.js

이 코드는 ES6 문법으로 작성하지말고 ES5문법으로 작성하세요.

그 다음, package.json 파일에 스크립트를 작성하세요.

 

package.json 에 build, start, development 스크립트 작성

development 스크립트를 굳이 스크립트파일을 따로 만든 이유는, 윈도우 / 유닉스 계열에서 NODE_ENV 설정하는 방식이 다르기 때문입니다.

스크립트 파일을 따로 만들기 싫으면 위와같이 package.json 에 스크립트를 작성해도 됩니다.

 

이제 Express 서버에서 해야 할 기본 설정들은 끝났습니다.

이제, webpack 개발서버에서도 Express 서버에있는 API를 사용 할 수 있도록 config 를 수정해줍시다.

 

config/webpack.config.dev.js 수정하기

localhost:3000 에서 0.0.0.0:8081 로 바꿨습니다.

0.0.0.0 으로 해야 외부에서도 개발서버에 접속이 가능합니다. (포트는 변경하지 않아도 무방합니다)

 

scripts/start.js 수정하기

하단부의 WebPackDevServer 의 설정에 proxy 를 추가하시고,

listen 할 때 host를 localhost 가 아닌 0.0.0.0 으로 설정하세요.

그리고 (포트를 바꾸고싶다면) 코드 전체에서 3000 을 8081로 Replace 하세요.

 

이 두 파일을 수정하셨으면, webpack-dev-server에서도 Express.js 에서 만든 API를 사용 할 수 있게 됩니다 😀

 

마지막으로, react-hot-loader를 적용하는 방법을 알아보겠습니다.

 

react-hot-loader 적용하기

 

config/webpack.config.dev.js 수정하기

loaders 의 .js 부분에 기존의 loader 과 query 를 제거하고, loaders: 를 추가하세요.

로더가 두개이므로 query를 할 수 없습니다. 그 대신에 babel? 를 통하여 babel 설정을 JSON.stringify 하여 전달해주면 됩니다.

주의: 최근 react-hot-loader 가 업데이트 되어서, 그냥 설치하시면 “react-hot-loader”: “^3.0.0-beta.3” 가 설치됩니다.

설치 하실 때, npm install –save [email protected] 을 하시거나, 버전 3을 쓰고 싶다면 수정을 다음과 같이 하세요:

 

 

마무리

다 하셨나요? 이제 개발 서버를 열 땐, express 서버를 따로 실행 한 다음에 (터미널 창을 하나 더 열거나, screen 기능 사용) webpack 개발서버를 실행하시면 됩니다.

저같은 경우는, 원래 boilerplate 를 잘 사용하지 않고, (필요하지 않는 기능이 있는 경우가 있어서) 처음부터 직접 작업환경을 설정하는걸 좋아하는데.
이 create-react-app 은 핵심적인 기능이 다 있고, 무려 공식적으로 React 팀에서 내놓은거니까, 꽤 쓸만 한 것 같습니다 (음.. 심리적인 느낌도 살짝 없지않아 있습니다)

이 도구는, sass 로더라던지, redux 설정이라던지 그런것들이 안되어있으므로, 작업환경을 직접 설정 하는것이 번거롭다고 생각하시는분들은 익숙한 react boilerplate가 있다면, 그걸 사용하셔도 무방 할 것 같습니다.

제 생각엔 이 도구는 초보자들에게도 매우 쓸만 할 것 같습니다 (처음 시작 할 땐 webpack을 이해하고 설정하는게 조금 귀찮긴 합니다..)

  • bangbwa

    npm run eject로 해야하지 않나요~

    • 네 그렇죠!! 포스트 작성하다가 오타냈네요~ 감사합니다

  • There is an alternative solution that supports CSS Modules, PostCSS and HRM + React Hot Loader (as opposed to create-react-app):

    • Alright 🙂 I will check it out

      • Thanks 🙂 So far, I’m just trying to collect a little of feedback and prioritize stuff that be included (or removed) into this tool + thinking about integrating it into React Starter Kit, React Static Boilerplate projects..

  • 설거지의 달인

    감사합니다. 큰 도움이 되었습니다.

  • KangKY

    궁금한게 eject를 하지 않고서는 express와 연동이 불가한가요??
    처음의 폴더 구조가 너무 깔끔해서 유지하고 싶은 마음이 있는데 ..

    • 간단한 방법으로는 devServer의 프록시 기능을 사용하지 않고,
      Express에서 Cross-origin resource sharing을 허용한다음에 /api 이런 경로가 아닌 http://url/api 이런식으로 요청을 하시면 되겠습니다

  • goodman

    맥 환경에서는
    user> npm install -g create-react-app
    user> npm i -g [email protected]
    user> create-react-app hello-world –scripts-version [email protected]
    다음과 같이 설치해줘야 하네요.. 포스팅대로 설치하면 eject시 에러가 떠요.. 이것 때문에 엄청난 삽질을 했습니다. ㅠㅠ

  • Machen

    인프런에서 동영상 강의를 듣다가 react-hot-loader 버전 변화로 에러가 생겨 질문 드립니다. 위 포스팅처럼 3버전에 맞게 webpack.config.js를 변경했는데 리로드할 때마다 미리 설정해놓은 state 값이 날아가버립니다. 어떻게 수정하면 서버를 켜놓은 상태에서 html 파일 변화시 state값을 유지할 수 있을까요?

    • https://youtu.be/GIMjnWuA9B0

      제대로 작동하지 않는다면 이 동영상을 참조해보세요. 영어이긴 합니다만.. 요청하시면 자막 깔아드리겠습니다.

  • 서재원

    주제와 약간 벗어난 질문인데요. react-hot-loader와 webpack-hot-middleware의 차이점이 뭐에요?

    • webpack-hot-middleware: 파일이 수정 될 때 번들이 완료된 파일을 새로 로딩하는게 아닌, 바뀐 부분만 패치하는 방식으로 업데이트하는 기능을 지원하는 라이브러리
      react-hot-loader: 위 기능을 리액트에서 컴포넌트의 state 를 유지하면서 사용가능케 하는 라이브러리 입니다.

  • react noob

    안녕하세요. 인프런에서 리액트 강좌 조금씩이지만 잘 보고 있습니다:)
    현재 진행중인 프로젝트가 있는데 express + jade로 작성되어있습니다.
    이 것을 express + react로 마이그레이션 할 수 있는 방법이 있을까요?
    view layer에서 REST 서버로 데이터를 요청하는 형식이 아니라
    서버에서 데이터까지 취합해서 렌더링해주는 구조라 다 걷어내고 작업해야 할 것 같긴 한데
    혹시 좋은 방법이 있나 궁금합니다.
    늘 좋은 강의 감사합니다.

    • 리액트를 사용 하실 땐,
      1) 전체적으로 사용하거나
      2) 부분적으로 사용하는

      방법이 있습니다.

      React 에서 Jade 형식으로 코드를 작성하고싶다면, https://github.com/pugjs/react-jade 이런 라이브러리를 사용하는 방법도 있습니다.

      REST 서버로 데이터를 요청하는 형식이 아니라면, React 의 서버 사이드렌더링을 알아보아야합니다. 서버사이드 렌더링을 할 때는 Redux 를 사용하는것이 관리하기가 쉽습니다.

      https://www.npmjs.com/package/redux-async-connect

      • react noob

        부분적으로 사용하는 것을 검토해 보아야겠습니다.
        답변 감사합니다!

  • Lee Hyeon-Soo

    저는 $ react-scripts eject를 하면 설정 파일이 다 튀어나와 멘붕이 와서, 그냥 react-scripts를 유지하고 싶었습니다.

    그래도 react-hot-loader를 쓰고 싶은데 꼼수가 없을까 생각해보니,

    node_modules/react-scripts/config/webpack.config.dev.js 파일만 수정해서 사용하면 되겠구나 했습니다.


    // Process JS with Babel.
    {
    test: /.(js|jsx)$/,
    include: paths.appSrc,
    loaders: ['react-hot', 'babel?presets=react-app']
    },

    그런데 hot-loading은 잘 되는데(refresh 없이 즉시 DOM 변경),

    뭐가 문제인지 state 유지가 안 되고 초기화 되어버립니다.

    이거 방법 좀 같이 찾아봐주실 수 있을까요? ㅎㅎ

    • Lee Hyeon-Soo

      제가 패키지 매니저로 yarn을 쓰고 있는데,
      파일을 변경시켜놓으면 hash값이 달라지는 걸 알아차리고 서버에서 다시 받아서 원래대로 돌아가버리네요 ㅎㅎ

  • Sunchul Kim

    안녕하세요. 이제 막 React를 공부하는 개발자입니다.
    강의보고 따라하던 중 이해되지 않는 부분이 생겨서 질문드립니다.
    – create-react-app으로 프로젝트 생성
    – 프로젝트 루트 디렉토리에 webpack.config.js 파일 생성 및 설정
    – webpack 명령어 실행
    – 번들파일 생성

    이 과정으로 webpack 번들파일 생성하는데는 이슈가 발생하지 않았으나

    – create-react-app으로 프로젝트 생성
    – npm run eject로 프로젝트에 react-scripts 가져오기 (추가!!)
    – 프로젝트 루트 디렉토리에 webpack.config.js 파일 생성 및 설정
    – webpack 명령어 실행
    – 번들파일 생성 시 에러발생
    Using babel-preset-react-app requires that you specify NODE_ENV or BABEL_ENV environment variables

    해결방법으로는 프로젝트 루트 디렉토리에 .babelrc 파일생성 후 바벨 설정
    다시 webpack 실행하니 문제없이 생성되었습니다.

    단순히 eject 도구를 사용하여 문제가 발생한건지 아니면 create-react-app
    으로 프로젝트를 생성하게 되면 webpack 적용하는 방법이 따로 있는지 질문
    드립니다.(자세하게 설명 못드려서 죄송하네요;;)

  • 임도경

    안녕하세요ㅎ
    create-react-app으로 사용하다 궁금한 점이 있어서요ㅎ
    컴퍼넌트 파일에 확장자가 js 혹은 jsx 차이가 있을까요?
    jsx로 했을경우 npm start했을때 에러가 나는데 react-scripts를 install해도 해결이 안되네요..ㅠㅠ

  • 안녕하세요 공부를 하던 도중 궁금한게 있어 여쭈어 봅니다.

    server 소스구조를 어떻게 만든다는 것인지 잘 이해가 안가서요.

    root 디렉토리에 server 디렉토리를 만들고 cd server && npm init을 하여 package.json을 생성하는 것인가요 ??

    express 같은 서버 모듈들은 루트디렉토리의 node_modules에 설치하는 것인가요 ?