React 라이브러리

2. 리액트 환경 직접 만들기 (webpack 사용하기)

문정훈 2021. 11. 13. 02:13

0. webpack을 사용하는 이유

컴포넌트는 .jsx 형태로 클래스 또는 hooks로 만들어지며 만들어진 컴포넌트는 react-dom의 render 함수를 통해 html DOM 트리에 장착(?) 하게 된다.

facebook과 같은 2만개의 컴포넌트가 존재하는 웹 사이트를 만든다면 jsx 파일이 2만개 존재할 수 있고 이 2만개의 jsx 파일을 html의 script태그로 정의해야하고 사실 jsx파일을 html파일에서 <script>태그로 불러올 수도 없다. 

 

webpack은 겉으로 보여지는 기능은 여러개의 jsx 파일을 하나의 js 파일로 만들어 주는 역할을 하는 것이다. 

하나로 합쳐진 js 코드에 babel을 적용할 수 있게 된다. 

 

1. 리액트 환경 만들기 및 webpack 설치

순서1)

npm init을 입력한다

pakage name, auhtor, license의 값을 입력하면 해당 경로에 pakage.json 파일이 생성된다. 

package.json 파일은 배포한 모듈 정보를 담고자 만들어졌다.

노드로 작성하는 애플리케이션도 package.json 파일을 사용하여 관리할 수 있다.

애플리케이션을 개발시 package.json 파일을 이용하면 사용하는 확장 모듈에 대한 의존성 관리가 가능하기 때문에 편리하다. 

 

순서2) 

npm i react 
npm i react-dom

 

위와 같이 명령을 주면 npmReactReact-DOM을 설치해준다. pakage.josn 파일에 "dependencies 란에 추가 된다. 

여기 까지 진행하면 해당 경로에 node_modules 파일과 pakage.json, pakage-lock.json파일이 존재하게 된다. 

이제 순서에 맞게 필요한 명령어를 통해 pakage.json에 추가하여보자

 

순서3) webpack 추가

npm i -D webpack 
npm i -D webpack-cli

 

-D 옵션으로 설치하면 pakage.josn에서 devDepencencies란에 추가가 된다. 

실제 서비스에서 사용되는 것들은 dependencies에 설치 되고

개발에만 사용되는 것들은 devDependencies에 생성된다.

 

 

순서4) webpack.config.js, client.jsx 파일 만들기

class2 디렉토리 안에 webpack.config.js 라는 파일을 만들고 아래와 같이 입력한다.

//webpack.config.js 파일
module.exports = {};

 

client.jsx 파일을 만들고 아래와 같이 작성하여 ReacReact-DOM을 불러온다.

//client.jsx
import React from 'react'
import ReactDom from 'react-dom'
import BaseBallGame from './BaseBallGame.jsx'

ReactDom.render(<React.StrictMode><BaseBallGame /></React.StrictMode>, document.querySelector('#root'));

 

아래와 같이 컴포넌트를 예시로 지정하는 기본코드를 작성해보았다. 

import React from 'react'
import { Component } from 'React'; // const { Component } = React;

class BaseBallGame extends Component {
  state = {}
  
  render() {
  	return ()
  }
}

export default Home;
//module.exports = BaseBallGame;

 

2. 리액트 환경 만들기2

 

아래 코드는 index.html 파일이다. 

<!DOCTYPE html>
<html>
  <head>
    <title>숫자 야구 게임</title>
    <meta charset="UTF-8">
  </head>
  
  <body>
    <div id="root"></div>
    <script src = "./dist/app.js"></script>
  </body>
  
</html>

위 디렉토리 구조와 같이 client.jsx 파일에서 BaseBallGame.jsx 라는 Component를 require해서 

client.jsx 에서 ReactDom.render를 호출해주는 파일이 된다. 

그리고 index.html에서 root id를 가지는 요소 아래 웹펙을 통해 client.jsx 스크립트를 넣는것이다. 

 

● webpack이 필요한 이유

(1) 우선 위 코드에서 <script> 태그 안에는 하나의 js 파일만 load된다.

하지만 우리는 이미 client.jsx, WordRelay.jsx 두 파일이나 있다.

따라서 여려개의 파일을 하나로 app.js하나로 packing하는 것을 웹펙이라함.

 

(2) index.html 파일에서 <script> 태그를 사용하여 외부 js 파일을 읽어올 수 있지만 만약 컴포넌트가 매우 많아지게 되면그만큼 <script> 태그도 많아진다. 

따라서 webpack 기술을 통해 여러 jsx 파일을 ./dist/app.js라는 하나의 파일로 만들 것이다. 

 

리액트 컴포넌트와 같은 코드는 jsx 파일에서 작성되야한다. js 파일에서 작성하면 안된다. 

create-react-app에서는 .js 파일로 컴포넌트를 작성하는데 그 이유는 js 파일을 jsx 파일로 바벨이 변경해주기 때문이다. 

 

 

3. webpack 설정

1) webpack 처음 설정하기

const path = require('path');
const webpack = require('webpack');

module.exports = {
  //웹펙 이름 설정
  name :'wordrelay-setting', 
  mode : 'development', //실서비스에서는 prodeuction
  devtool :'eval', 
  resolve: {
    extensions: ['.js', '.jsx']
  },
  
  entry: {
    //아래 두 파일은 합쳐질 파일들이다. 
    app: ['./client'],
  }, //입력
  
  
  output: {
    //path로 __dirname은 이 파일의 디렉토리 경로이다.
    //그리고 dist는 _dirname/dist 아래에 app.js를 웹펙된 파일로 만드는 것임
    path: path.join(__dirname, 'dist'),
    filename: 'app.js',
    publicPath: '/dist/',
  }, //출력
}

웹펙은 webpack.config.js 하나의 파일로 웹펙이 모든게 돌아간다.

name은 웹펙이름이고, mode, devtool은 일단 넘어가자

entry를 위와 같이 입력하면 웹펙할 파일들을 나열한다. 근데 이때 client.jsx안에서 BaseBallGame.jsx 파일을 불러오기 때문에 사실 ./client.jsx 파일 하나만 적어줘도 된다.

output은 위와 같이 'dist'라고 경로를 주고 그 경로에 filename으로 지정한 파일(app.js) 웹펙을 한다.

 

resolve: 란을 통해 extensions로 배열을 지정하는데 app에서 파일 이름 끝에 확장자명을 생략하기 위한 일종의 등록이다.

 

 

2) 웹펙 명령어 등록 방법 3가지

이제 실제로 webpack.config.js 파일이 있는 디렉토리 경로로 가서

‘webpack’이라고 명령을 주면되는데 이 webpack이라는 명령어를 등록해줘야 사용 가능하다. 등록하는 3가지 방법

 

방법1)

package.json 파일로 가서 위와 같이 등록해주면

npm run dev 명령을 실행하면 webpack 명령어가 실행됨

 

방법2)

npx webpack이라고 명령을 준다.

 

 

3) 웹펙 실행하여 app.js 만들기=> 에러1개 발생 함

그 이유는 3가지 방법으로 webpack명령어를 등록하여 사용 또는 사용하여 app.js를 만들 수 있다.

여기까지 진행하면 app.js는 만들어지지만 오류 하나를 해결해야한다.

웹펙이!! 웹펙을 진행할 때 client.jsx랑 BaseBallGame.jsx 두 파일을 합쳐 app.js 로 만드는 webpack 작업을 진행하는데 이때 jsx문법을 읽지 못한다는 것이다. 즉

ReactDom.render(<BaseBallGame/>, document.querySelector('#root;));

위와 같은 jsx 문법을 읽지못하는 것이다.

따라서 아래 순서에 따라 바벨을 설치해줘야한다.

 

바벨 설치법: 아래 모두를 설치한다.

npm i -D @babel/core

=> 바벨의 기본적 요소가 들어있음

 

npm i -D @babel/preset-env

=> 옛날 브라우저 문법과 호환성을 보장해준다.

우리 브라우저에서의 최신 문법을 옛날 문법으로 지원하는걸로 바꿔 준다.

 

npm i -D @babel/preset-react

=>웹펙 할 때 jsx를 지원한다.

 

npm i -D babel-loader

바벨과 웹펙을 연결해준다.

 

npm i -D @babel/plugin-proposal-class-properties

state = {}와 같은  jsx 문법 사용하게 해주는 babel이다.

 

 

4) 웹펙에 바벨 등록해주기

바벨을 설치했으므로 바벨을 사용한다는 등록을 webpack.config.js에 등록해줘야한다.

바벨과 웹펙 연결하는 방법임

 

entry에 있는 파일을 읽고 거기에 module을 통해 바벨을 적용하고 output에 결과를 뺸다. 이런 흐름임

module안에 rules를 배열로 등록한다. 배열의 첫 객체로 test 값을 지정하는데 어떤 파일즉

js, jsx 등 어떤 파일 형식에 웹펙을 할 때 바벨을 적용할건지 등록한다.

그 파일들을 loader의 값으로 ‘babel-loder’ 지정하여 바벨을 연결하여 웹펙에 사용되는 해당 파일들 형식들은 모두 웹펙에서 jsx문법을 적용할 수 있는 babel이 등록된 것이다.

 

그리고 optionsbabel-loder의 옵션을 등록해주는 것이다. !!

const path = require('path');
const webpack = require('webpack');


module.exports = {
  //웹펙 이름 설정
  name :'response_check-setting', 
  mode : 'development', //실서비스에서는 prodeuction
  devtool :'eval', 
  resolve: {
    extensions: ['.js', '.jsx']
  },

  entry: {
    //아래 두 파일은 합쳐질 파일들이다. 
    app: ['./client'],
  }, //입력
  module: {
    rules: [{
      test:  /\.jsx?/,
      loader : 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', {
              targets: {
                browsers: ['> 1% in KR'], 
              }
          }],
         '@babel/preset-react'
        ],

        plugins: [
          '@babel/plugin-proposal-class-properties',
        ],
      },
    }],
  },
  plugins: [
    new webpack.LoaderOptionsPlugin({ debug : true}),
  ],
  output: {
    //path로 __dirname은 이 파일의 디렉토리 경로이다.
    //그리고 dist는 _dirname/dist 아래에 app.js를 웹펙된 파일로 만드는 것임
    path: path.join(__dirname, 'dist'),
    filename: 'app.js',
    publicPath: '/dist/',
  }, //출력

};

 

5) 최종 실행

npm run dev 또는 npx webpack 명령으로 ./dist/app.js 파일(웹펙 파일)을 만들면 된다.

 

 

4. @babel/preset-env의 옵션 지정하기 plugings

1) @babel/preset-env의 옵션

근데 바벨의 옵션을 등록하는걸로 @babel/preset-env 등록을 해줬는데 이것의 옵션을 또 등록할 수 있다. 즉 바벨의 옵션으로 @babel/preset-env (옛날 브라우저 문법과 호환성을 보장해주는)를 등록했는데 옵션에 옵션이 있을 수 있다.

위 그림에서 prugins들의 모임이 presets인데 즉 @babel/preset-env 이것은 수십개의 plugins들의 모임인 것이다.

만약 preset-env에 설정을 적용하고 싶은 경우 아래와 같이 한다.

preset-env는 옛날 브라우저 문법을 지원해주는 babel-loderplougins 뭉탱이인 preset인데 이 preset-env의 구체적 설정을 아래와 같은 방법으로 할 수 있다.

 

설정 경우1)

위 내용은 proset-env의 구체적 설정을 targets 프로퍼티 안에서 준 것인데

현재 크롬의 버전 이 70이라치면 7069만 호환되게 지정하는 것임.

원하는 브라우저에만 맞춰서 할 수 있다.

인터넷 expolor가 버전이 많은데 옛날거로 갈수록 최신 문법 못쓰는게 많다.

즉 바꿀게 많다.

그럼 일일이 다 바꿔줘야하기 때문에 babel이 할 일이 많아져 동작이 느려진다.

 

설정 경우2)

한국에서 점유율 5%이상이면 모두 지원한다는 것임.

 

2) plugins에 대해 정리

파란 색은 loader의 값인 babel-loader의 옵션을 지정하는 plugins인데, 빨간색으로 plugins도 따로있다.

우선 plugins 이란 확자 프로그램 개념이다. 여기다가 추가적으로 하고 싶은 것을 지정하는데

일단 위와 같이 작성해보자.

위 내용은 우선 module이 loader인데 이 loader의 옵션인 options에 모두 debug : true를 적용해주는 것이다.

 

 

5. 웹팩 hot reloading

우선 3번까지 설정해주고 실행하는거면 매번 파일의 내용이 수정되면 npm run dev로 웹펙을 계속 다시 해줘야하지만 핫 리로딩을 적용하면 웹페이지를 새로고침하는 걸로 수정된 코드 내용이 바로 적용될 수 있다.

 

1) 설치1

npm i -refresh @pmmmwh/react-refresh-webpack-plugin -D

 

2) 설치2

npm i -D webpack-dev-server

 

3) 설치3

npm i react-refresh -D

 

4) 기존의 "dev" 변경

기존에 "dev" : "webpack" 에서 위와 같이 수정한다. 

 

 

4) webpack.config.js 파일 수정

const path = require('path');
const webpack = require('webpack');
const reactRefresh = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
  //웹펙 이름 설정
  name :'response_check-setting', 
  mode : 'development', //실서비스에서는 prodeuction
  devtool :'eval', 
  resolve: {
    extensions: ['.js', '.jsx']
  },

  entry: {
    //아래 두 파일은 합쳐질 파일들이다. 
    app: ['./client'],
  }, //입력
  module: {
    rules: [{
      test:  /\.jsx?/,
      loader : 'babel-loader',
      options: {
        presets: [
          ['@babel/preset-env', {
              targets: {
                browsers: ['> 1% in KR'], 
              }
          }],
         '@babel/preset-react'
        ],
        
        plugins: [
          '@babel/plugin-proposal-class-properties',
          'react-refresh/babel',
        ],
      },
    }],
  },
  plugins: [
    new webpack.LoaderOptionsPlugin({ debug : true}),
    new reactRefresh(),
  ],
  output: {
    //path로 __dirname은 이 파일의 디렉토리 경로이다.
    //그리고 dist는 _dirname/dist 아래에 app.js를 웹펙된 파일로 만드는 것임
    path: path.join(__dirname, 'dist'),
    filename: 'app.js',
    publicPath: '/dist',
  }, //출력

  devServer: {
    devMiddleware: { publicPath: '/dist' },
    static: { directory: path.resolve(__dirname) },
    hot: true,
  }
};
  1. webpack.config.js 파일에서 위 코드와 같이
    const hot = require('@pmmmwh/react-refresh-webpack-plugin');
    위와 같이 불러오고 plugins에 new 를 통해 지정하면 된다.
  2. loader의 plugins에 'react-refresh/babel'까지 등록해준다.
  3. devServer를 추가로 위와 같이 등록해준다. 

※ devServer에서 static을 등록할 때 index.html 파일이 존재하는 경로가 만약 webpack.config.js파일과 동일한 위치라면

static: { directory: path.resolve(__dirname) }, 이렇게 해주면 되고

만약 src 파일에 index.html 파일이 존재한다면

static: { directory: path.resolve(__dirname, './src') }, 이렇게 설정해주면 된다.

 

 

여기까지 잠깐 정리하면 webpack-dev-server의 역할을 정리하면 이것은 webpack.config.js에 적어준대로 빌들의 결과물들을 돌린 뒤 devServer에 적어준 /dis/폴더에 결과물을 저장한다. webpack dev server는 소스코드의 변경점이 생기면 그에 따라 저장한 결과물을 수정하게 된다.

 

또한 hot reloading의 장점은 기존의 데이터는 그대로 유지하고 새로 수정된 내용을 반영하기 떄문에 데이터가 날라가지 않는다.