강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 

 


여기서 필요한건 react-hot-loader, webpack-dev-server 모듈이다.

webpack-dev-server 모듈은 webpack.config.json을 읽어 빌드하고 서버로 유지해주는 역할이라고 한다.

로컬에서 서버를 돌릴 수 있다.

 

react-hot-loader는 실시간으로 변경된 것을 확인할 수 있게 해준다.

 

모듈 install

// cmd

npm i -D react-hot-loader
npm i -D webpack-dev-server

 

제로초님 강의에 서버가 공포감을 줄 수 있다고 한다.

나역시도 그랬던 것 같다 ㅎㅎㅎ.

 

package.json에 script 부분을 수정해준다.

// package.json

  // ..
  "scripts": {
  	"dev": "webpack-dev-server --hot"
  },
  // ..

npm run dev하면 webpack-dev-server와 react-hot-loader가 실행되게 해준다.

 

그리고 webpack.config.json으로 가서 plaugins를 작성해준다.

// webpack.config.json

  module : {
    rules : [{
      test : /\.jsx/,
      loader : 'babel-loader',
      options : {
        presets : ['@babel/preset-env', '@babel/preset-react'],               
        plugins : [
          '@babel/plugin-proposal-class-properties',
          
          // 이 부분!!
          'react-hot-loader/babel',
        ]
      }
    }]
  },

output의 publicPath도 수정해준다.

// webpack.config.json

output : {
  path : path.join(__dirname, 'dist'),
  filename : 'app.js',
  
  // 이부분!
  publicPath : '/dist'
}

 

app.js (entry에서 최초로 실행되는)에 react-hot-loader를 require해서 사용한다.

// app.js 

import React from 'react';
import ReactDOM from 'react-dom';

// react-hot-loader/root 로 입력해야한다. root를 입력하는건 그렇게 만들어졌기 때문이라고..ㅎ
import { hot } from 'react-hot-loader/root';
import Example from './Example';

// hot메서드에 Example 컴포넌트를 파라미터로 넘긴다.
const Hot = hot(Example);

// <Hot />을 컴포넌트 넣던 부분에 넣어준다.
ReactDOM.render(<Hot />, document.querySelector('#root'));

 

index.html에 app.js를 output한 파일을 볼 수 있도록 수정해준다.

path는 실제경로, publicPath는 대충 가상경로라고 생각하면된다고한다. // express.static과 비슷한기능이라고하는데?

  // index.html
 
  - <script src="./dist/app.js"></script>
  + <script src="./dist/app.js"></script>

 

그리고 아까 저장한 dev가 실행될 수 있도록 또는 npx webpack하면 실행된다.

// cmd

npm run dev

// 또는
npx webpack

 

 

자동으로 반영이 되는 것을 확인해보자.

.js를 수정하고 수정된 것을 확인해보자.

하지만.!

ReactDOM.render하는 js는 캐치하지 못하니 주의하자. 이곳에서 require하는 부분들만 캐치가 가능하다.

그래서 ReactDOM을 작성하는 entry부분은 서버를 내렸다가 올려야한다.

 

강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 


 

일단 index.html 파일이 필요하다.

(webpack.config.js에서 entry에 적었던 파일들을 output으로 출력했을 때, 이 파일을 로드할 index.html!)

 

프로젝트 루트에 index.html을 생성한다.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>예제</title>
</head>

<body>
  // react에서 DOM을 생성하여 넣어줄 태그! app.js에서 id값으로 접근하고 있다.
  <div id="root"></div> 
  
  // webpack.config.js에서 output에 경로를 작성한 파일 입력
  <script src="dist/app.js"></script> 
</body>
</html>

 

그리고 html에서 처음으로 로드할 app.js 파일이 필요하다.

이 파일은 entry.

 

프로젝트 루트에 app.js 생성한다.

// insatll한 리액트 모듈
const React = require('react');

// install한 리액트 돔 모듈
const ReactDOM = require('react-dom');

// 화면에 뿌려줄 컴포넌트
const Gugudan = require('./Example'); 

// ReactDOM의 render 메서드를 통해 <Example /> 컴포넌트를 #root에 생성
ReactDOM.render(<Example />, document.querySelector('#root'));

 

위 app.js에서 로드하고 있는 컴포넌트 <Example>를 생성해보자!

const React = require('react');

// 리액트의 component 메서드 선언를 비구조화할당으로 선언한다.
// 비구조화 할당으로 선언하기 위해서는 모듈이 export 시에 해당 메서드를 export하고 있어야한다.
// 이것은 ES6문법
const { Component } = React;

// Example 컴포넌트를 생성한다.
// 위에서 비구조화할당으로 Component 선언한 메서드를 사용한다.
class Example extends Component {

  // this를 사용하기 위해 construct를 사용했으나 하단에서 arrow function을 사용하면 없어도된다.
  constructor(props){ 
    super(props);

    // state 선언
    this.state = { 
      value : '',
      result : ''
    };
  }

  setExampleNumber = () => { 
  	return '123';
  };

	
  // state 선언시에는 무조건 this.setState를 사용해서 해줘야한다.
  onChange = (e) => { 
    this.setState({
    	value : e.target.value
    })
  };

  // inputEl 선언 후 Ref 설정해주면 객체에 접근가능
  inputEl; 

  // dom에 접근하기 위해서는 ref를 사용한다.
  this.inputEl.focus();

  // ref선언
  onRefInput = (o) => {  
  	this.inputEl = o;
  };

  render() {
    return (
	
	  // React.Fragment 로 감싸줄 수 있다. (불필요한 태그 생성 방지) 
      <React.Fragment>
        <div>
          {this.state.value}
        </div>

        <form onSubmit={this.onSubmit}>
          <input

            // ref 선언
            ref = {this.onRefInput} 
            type="number"

            // value와 onChange는 함께 쓰여야한다.
            // 하나만 사용하려면 value 속성 대신 defaultValue를 쓸수도 있다.
            value={this.state.value}
            onChange={this.onChange}
          />
          <button>입력</button>
        </form>
        <div>
        {this.state.result}
        </div>
      </React.Fragment> 
    );
  }
}

// 모듈 내보내기
module.exports = Example; 

 

강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn


필요한 패키지 install 후에 webpack 설정해보기

프로젝트 폴더에서 npm 설정

// cmd
npm init

 

필요한 모듈을 받아준다.

react, react-dom, webpack, webpack-cli

@babel/core, @babel/preset-env, @babel/preset-react, @babel/plugin-proposal-properties, babel-loader

npm install --save-dev webpack webpack-cli
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader @babel/plugin-proposal-class-properties

dev와 아닌것을 구분하여 다운로드 받자.

dev는 개발환경에서 사용할 모듈들이며 package.json의 devDependencies에 저장된다.

 

webpack 설정파일을 프로젝트 루트에 생성한다.

webpack.config.js

아래 내용을 입력한다.

const path = require('path'); 
// node의 내장모듈, 경로를 문자열로 만들어주는 모듈이라고한다.

module.exports = {  
	// name은 webpack.config.js 파일에 대한 이름
    name : 'gugudan', 
    
    // 개발상태라 development로 작성했지만, 배포시에는 production으로 변경해야한다.
    mode : 'development',
    
    // 소스맵 생성여부를 결정하는 옵션이라고 하는데, 추후에 한번봐야할것같다.
    // 참고 : https://webpack.js.org/configuration/devtool/  
    devtool : 'eval', 
    
    // 웹팩이 경로나 확장자를 처리할 수 있게 옵션 설정하는 부분   
    resolve : { 
	    // js나 jsx 확장자를 붙이지 않아도 자동으로 웹팩이 처리
        extensions : ['.js', '.jsx']    
    },  
    
    // 모듈의 진입점을 설정
    entry : { 
    	app : ['./app', './Gugudan']  
    },  
    
    // 진입점의 파일들을 output으로 만들때 설정
    module : {      
    
    	rules : [{      
        
        	// .js나 .jsx에 대한 파일들을 (정규표현식)
            test : /\.jsx/,       
            
            // 바벨로더로
            loader : 'babel-loader',       
            
            options : {        
            
              // 사용할 presets들 
              // preset-env는 옛날브라우저 지원하며 바벨과함께 사용되어야하는 플러그인들을 모아둔 모듈
              // typescript가 필요하면 @babel/preset-typescript 가 필요하듯
              // 플러그인들의 모음들이라서 수십개의 플러그인들이 합쳐져있다. 
              presets : [
              '@babel/preset-env', 
              '@babel/preset-react'
              ], 

              // 클래스의 프로퍼티를 사용할 수 있게 도와주는 바벨 플러그인으로 이게 없으면 state에서 오류가 났다. 
              plugins : ['@babel/plugin-proposal-class-properties'] 
            }    
        }]  
    },  
    
    // 추가적으로 플러그인을 사용할 경우
    // loaderOptionsPlugin 플러그인은loader에 모든 곳에 debug 옵션을 넣어주는 플러그인  
    plugins : [    
      new webpack.LoaderOptionsPlugin({        
      	debug: true    
      }),
    ], 
    
    // 출력
    output : {     
    
    	// 상단에서 선언한 path(경로)를 __dirnamae과 join하여 프로젝트 폴더(root)에 'dist'폴더를 생성       
        // dist 가 있으면 그 폴더 안에 파일을 만든다.
        path : path.join(__dirname, 'dist'), 
    
      // 출력되는 파일 이름
      filename : 'app.js'   
	}
};

 

위의 preset에 옵션을 넣을 수 있는데, 예제를 보자

// 옵션 사용 전
presets : ['@babel/preset-env', '@babel/preset-react']

// 옵션 추가
// 첫번째 값에 preset 모듈 이름
['@babel/preset-env', 
	
    // 그리고 옵션 값 추가 
    { 
    targets : {
    
    	// 브라우저 크로스브라우징할 범위를 선정하는 것인데
        // 예를들어 ['> 5% in KR'] 과 같이 쓰면 한국에서 5%이상의 브라우저 점유율을 가진 브라우저를 지원한다는 뜻
        // 이 옵션은 https://github.com/browserslist/browserslist 여기서 확인할 수 있다.
        browsers : ['last 2 chrome versions'], 
    }
}]

 

강의 유튜브 주소 :

http://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 


일단 우리가 아는 HTML에서 CDN방식으로 React를 사용하려면 총3개의 script가 필요하다며

강의에서는 하단의 3개의 script 경로를 알려준다.

// react
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> 

// react-dom
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> 

// babel-loader
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> 

babel-loader는 react문법을 html에서 알 수 있도록 컴파일하는 역할을 한다.

 

사용예제

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  
  // react
  <script src="https://unpkg.com/react@16/umd/react.development.js"></script> 
  
  // react-dom
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> 
  
  // babel-loader
  <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> 
</head>
<body>


  <div id="root"></div>
<!-- #root에 react로 생성한 dom 객체를 삽입한다. -->

<!-- text/babel 타입을 넣어주어야 babel-loader가 인식할 수 있다. -->
  <script type="text/babel">

	class LikeButton extends React.Component {
      constructor(props){
        super(props); // 이렇게 해줘야 class함수 내부에서 this로 접근할 수 있다.
        
        // state 선언
        this.state = {
          liked : false
        }
      }
      
      render(){

		// jsx 문법
        return (
        	<button type="submit" onClick={() => {
              this.setState({ liked : true })
            }}>
              { this.state.liked === true ? 'Liked' : 'Like' }
            </button>;
        );
      }
    }
  </script>

<!-- text/babel 타입을 넣어주어야 babel-loader가 인식할 수 있다. -->
  <script type="text/babel">
  
  	// ReactDom의 render 메소드를 통해 LikeButton 컴포넌트를 #root에 생성한 후 삽입한다.
    ReactDOM.render(<LikeButton />, document.querySelector('#root'));
  </script>
</body>
</html>

 

+ Recent posts