본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[79일차 복습] 웹팩 CRA 없이 React 개발 환경 구축 및 핫리로드 & CRA 사용버전

반응형

 

Webpack, 웹팩이란 ? 

 

-> https://blckchainetc.tistory.com/253

 

[Webpack] 웹팩이란 ? 웹팩 사용 전, 알아야할 기본 개념 6가지

 웹팩(Webpack)이란 ? 수많은 모듈을 잘 관리하도록 돕는 번들러(Bundler) 중 하나이다. "webpack" 이 번들러 중 가장 유명하다. 여러개의 파일을 하나로 묶어 제공 ---> 웹 애플리케이션의 빠른 로딩을

blckchainetc.tistory.com

 

 

 

 

Webpack 환경설정 하기 

 

1. terminal 경로를 webpack 을 하려는 파일까지 들어오기 

ex) 파일 이름이 0705webpack이고 이 안에 파일들을 생성할 예정이면 

$ cd 705webpack 

 

 

2. 아래 npm 명령어 실행 

$ npm init
$ npm install react   # react 사용 
$ npm i react-dom   # '' 
$ npm i -D webpack   # webpack 사용 
$ npm i -D webpack-cli  #webpack 실행 

* i 는 = install 

* -D = development 개발 용도

* npm은 명령어들을 병렬로 쭉 다운 가능 

ex) npm i -D webpack webpack-cli

 

 

-> packages.json 파일에 설치된 것 확인 

  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "webpack": "^5.42.0",
    "webpack-cli": "^4.7.2"
  }
}

 

-> 파일트리에 'webpack.config.js' 파일이 생성 확인

 

 

 

3. webpack.config.js 환경 설정 

 

세팅할 부분의 해설은  click -> webpack 이란 ?  포스팅에 상세히 정리해 놓음! 해당 포스팅에서는 환경 설정 코드만 작성할 예정! 

 

const path = require('path')

module.exports = {  //module.exports부터 무조건 쓰기 ! 
    name:'firstWebpack', //webpack의 이름 - 안적어도 된다. 
    mode:'development', //어떤 용도로 개발을 할 것이냐 
    // development -> 개발용 
    // production -> 배포 용!
    devtool:'eval', 
    // eval -> 개발용 
    // hidden-source-map -> 배포용 

    // 입력받을 내용들 
    entry:{
        app:['./index.jsx']
    },
    // 내보낼 내용들 
    // 현재 디렉토리 + dist까지 
    output:{
        path:path.join(__dirname,'dist'),
        filename:'app.js'
    }
}

 

 

 

4. 웹팩 실행시킬 index.html / index.jsx 새로 만들기 

 

* jsx = js 같음 -> 가독성 / '리액트 컴포넌트 파일이구나 ~ ' 구별 위함 ! 

 

0705webpack - index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="./dist/app.js"></script>  // 위 output에서 적은 위치 및 파일명
</body>
</html>

 

0705webpack - index.jsx

const React = require('react') // CRA 에서 import ~ 하는 경우가 있음 
const ReactDOM = require('react-dom')


class App extends React.Component{
    render(){
        return(
            React.createElement('div',null,'Hello webpack')
        )
    }
}

ReactDOM.render(
    React.createElement(App),
    document.querySelector('#root')
)

* 아직 babel 읽는 능력 없는 상태 ! 아래에 babel에 대한 환경설정 추가할 예정 

 

 

 


 

 

 

5. 웹팩 실행시키기 

 

-> 웹팩이 실행되면 entry에 적은 index.jsx 파일이 dist 폴더 안 app.js 파일로 return 된다. 

 

 

아래 명령어 입력하면 웹팩이 실행된다. 

$webpack 

* window의 경우 ERROR 가 남 - > 아래처럼 진행해주면 된다. 

 

 

 

1) 첫 번째 방법 

$ npm webpack 

이것도 안되면

 

 

2) 두 번째 방법

package.json 파일에서 script 의 webpack 설정 키 입력 

{
  "name": "0705webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    
    // 아래 추가해주기 
    "dev":"webpack"  
    //npm script 명령어 미리 설정 
    //npm run dev  라고 실행하면 dev 의 webpack이 실행되게 
    
  },
  "author": "",
  "license": "ISC",

그리고 아래 명령어 실행

$ npm run dev 
         or
$ npx webpack

 

 

---> 그럼 실행된다 ! 그리고 파일 트리에는 dist 폴더 - app.js 가 생기고 

app.js 를 자세히 보면 내가 적은 코드들이 군데 군데 보이지만 무슨 말인지는 모르겠다.

 

구문 실행이 됨 

일단 웹팩 성공 ! 

 

 

 

 

 

6. react에서 아주 유용한 babel 기능 webpack에 추가하기 

 

아래 명령어 추가 

$npm install -D @babel/core               - bable의 기본적인 core 핵심 내용을 담고 있다. 
$npm install -D @babel/preset-env       - 브라우저에 맞게 최신문법을 옛날 문법으로 바꿀 수 있는 기능 
$npm install -D @babel/preset-react     - React에 필요한 babel 설치하겠다. 
$npm install -D babel-loader               - babel & webpack 을 연결해줄 때 필요 ! (loader -> 확장기능) 

* 실무에서는 다른 것들을 더 설치하는 경우도 있다고 한다. 

 

 

 

만약 위의 babel 설정들을 안하고 실행시키면 아래와 같은 오류가 난다 ! 

저 화살표의 문제

 

webpack.config.js 추가 

    // module을 통해 babel or sth 통해 해석해야하는구나 알도록 설정
    // 외부파일 가져와서 읽을 때 사용하는 
    // babel은 js 뿐만 아니라 다른 파일도 읽을 수 있음 -> 규칙 정해주기
    module:{
        rules:[{
            //확장자가 .jsx 이냐 .js이냐 - 적합하면 실행하겟다. -> 파일 불러올 때 확장자 안써도됨 
            test:/\.jsx?$/, 
            loader:'babel-loader', // webpack - babel 이해해주는 아이
            // babel 내용 바꾸고 싶을 때 ex) plugin, preset..
            options:{
                presets:[
                    '@babel/preset-env', 
                    '@babel/preset-react'
                ]
            }
        }]
    },

index.jsx 수정 (babel 기능 되는 아래 코드로!) 

const React = require('react') // CRA 에서 import ~ 하는 경우가 있음 
const ReactDOM = require('react-dom')


class App extends React.Component {
    render() {
        return (
            <div> Hello babel! </div>
        )
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('#root')
)

그리고 실행 명령어  둘 중 하나 입력 ! --> 웹팩 실행됨 

$ npx webpack 
    or 
$ npm run dev

 

 

Q. 이전까지 html script type을 설정할 때 babel을 쓰는 경우

<script type="text/babel"> 로 적었었는데 지금은 

<script type="text/javascript"> 인 이유 ? 

 

=> webpack이 babel을 이미 다 읽고, 처리해서 보내주기 때문 ! 

 

 

* preset - env  : 옛날 문법을 최신 버젼으로 바꿔줌 !  아래 링크에 더 자세히 어떤 종류의 브라우저만 설정할지, 제외할지 정할 수 있다. 

https://github.com/browserslist/browserslist

 

browserslist/browserslist

🦔 Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-preset-env - browserslist/browserslist

github.com

 

한국에서 5% 이상의 점유율을 차지하는 브라우저만 ! 그리고 최근 2개의 크롬 버젼까지만으로 설정하기 

 

webpack.config.js

    module:{
        rules:[{
            test:/\.jsx?$/, 
            loader:'babel-loader', 
            options:{
                presets:[
                    ['@babel/preset-env', {
                        targets:{
                            browsers:['>5% in KR','last 2 chrome versions']   //추가 
                        },
                        debug:true,
                    }], 
                    '@babel/preset-react'
                ],
                plugins:[
                    'react-refresh/babel'
                ]
            }
            
        }]
    },

 

 

 

7. Components module화 해서 사용해보기 

 

loginBox.jsx 생성 + 아래 내용 붙여넣기  (이전에 연습한 아무 component) 

        class LoginBox extends React.Component{
            state={
                userid:'', 
                userpw:''
            }

            handleChange = (e) =>{
                this.setState({[e.target.name]:e.target.value})    
            }


            letsubmit = (e) =>{
                console.log(e)
                e.preventDefault()
                this.props.onCreate(this.state)
            }

            render(){
                return(
                    <form onSubmit={this.letsubmit}>
                        <input 
                            type="text" 
                            placeholder="아이디를 입력해주세요"
                            value={this.state.userid}
                            name="userid"
                            onChange = {this.handleChange}
                        />
                        <input 
                            type="password" 
                            placeholder="비번 입력해주세요"
                            value={this.state.userpw}  
                            name="userpw"
                            onChange = {this.handleChange}
                        />
                        <button type="submit">로그인</button>
                    </form>
                )
            }
        }

 

 

webpack이 react를 처리하도록 하는 코드 추가 

const React = require('react')

class LoginBox extends React.Component{
    state={
        userid:'',

또는 

const React = require('react')
const {Component} = React

class LoginBox extends Component{
    state={
        userid:'',

둘 다 같다. 

 

 

해당 component를 exports 시키는 코드 가장 마지막에 추가 

module.exports = LoginBox

 

전체 코드

const React = require('react')   // 추가 1

class LoginBox extends React.Component{
    state={

.
.
.            ( 위와 같음 ) 
.
.


                <button type="submit">로그인</button>
            </form>
        )
    }
}

module.exports = LoginBox    // 추가 2

---> 어디론가 빼내어 쓸 수 있는 하나의 모듈 완성 

 

 

index.jsx에서 LoginBox 가져오기 (연결) 

const React = require('react') 
const ReactDOM = require('react-dom')
const LoginBox = require('./loginBox.jsx')  // 가져오기 


class App extends React.Component {
    render() {
        return (
            <>
                <div> Hello babel! </div>
                <LoginBox />                // 가져온 LoginBox 사용    
            </>
        )
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('#root')
)

 

* import ~ from ~ 

위 index.jsx는 webpack으로 사용되기 떄문에 import 문 (최근 많이쓰는 구문) 사용을 할 수 있다. webpack.config.js같은 경우는 webpack과 연결이 되어있지 않기 때문에 사용이 안됨. 

위의 내용을 아래처럼 바꿀 수 있다! 

const React = require('react') 
const Component = React
const ReactDOM = require('react-dom')
const LoginBox = require('./loginBox.jsx')

// import 의 장점 변수 두가지 설정 가능 
// import는 babel이 한 번  읽고 처리됨 (require는 node.js가 )

import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import LoginBox from './loginBox.jsx'

 

 

* 가져오는 파일의 확장자를 반드시 써야한다. 만약 쓰기 귀찮다면 webpack.config.js에서 확장자 설정해주기 ! 

 

webpack.config.js

    devtool:'eval', 

    resolve:{
        extensions:['.js', '.jsx']    // 추가 --- 복수일 때 보통 s를 붙임 
    },

    entry:{
        app:['./index.jsx']
    },

위처럼 js / jsx 확장자를 설정해주면 아래처럼 index.jsx 안에 확장자를 제거해서 쓸 수 있다. 

import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import LoginBox from './loginBox'    // .jsx 제거해도 오류가 안난다 !

 

 

 

 

실행 -> 

 

그럼 연결됨 ! 

 

 

 

 

위와 같은 모듈화의 장점 

1) 코드 관리 용이

2) 협업 시 용이

- 여러명이 같은 page를 개발한다고 하면 개인별로 맡은 Components별로 관리 가능  

3) sub page의 경우 같은 component 재사용할 수 있음 ! 

 

 

 

 


 

 

 

HOT RELOAD 핫리로드,  실시간 디버깅 설정 

build를 하지 않아도 실시간으로 처리해주는 것 ! -> 매우 유용한 기능 

 

1. 아래 명령어 실행 

$ npm install -D react-refresh     - refresh
$ npm install -D @pmmmwh/react-refresh-webpack-plugin   - refresh
$ npm install -D webpack-dev-server    - express로 구현되어 있는 webpack 세팅을 다 해놓기 

 

$ npm install -D @pmmmwh/react-refresh-sebpack-plugin 오류 날 경우 아래 코드 입력 

$ npm install -D @pmmmwh/react-refresh-webpack-plugin --save --legacy-peer-deps

 

 

2. index.jsx 실행될 때 무조건 함께 실행되도록 plugin 설정 

 

webpack.config.js

1) 다운받은 내용 가지고 오기 

const webpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin') //추가

output 전에 가져온 plugin 달아주기 - plugin은 번들이 되어진 결과물을 처리 그래서 output (결과 배출) 전 입력 하기 

 

 

 

2) 첫 번째 설치 명령에 대한 설정 

            options:{
                presets:[
                    '@babel/preset-env', 
                    '@babel/preset-react'
                ],
                plugins:[
                    'react-refresh/bable'
                ]
            }

 

3) 두 번째 설치 명령에 대한 설정

    //webpack이 구동이 될 때 아래 plugins를 무조건 실행하겠다. 
    plugins:[
        new webpackPlugin()
    ],

 

 

4) 세 번째 설치 명령에 대한 설정

    // 내보낼 내용들 
    // 현재 디렉토리 + dist까지 
    output:{
        path:path.join(__dirname,'dist'),
        filename:'app.js',
        //정적 파일로 바꾼다. 
        publicPath:'/dist'
    },

    // 실행할 때 
    devServer:{
        publicPath:'/dist',
        hot:true, // hot reload 
    }
}

 

 

webpack.config.js 전체 코드 

const path = require('path')
const webpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')  //추가 
const webpack = require('webpack')

module.exports = {  //module.exports부터 무조건 쓰기 ! 
    name:'firstWebpack', //webpack의 이름  / 안적어도 된다. 
    mode:'development', //어떤 용도로 개발을 할 것이냐 
    // development -> 개발용 
    // production -> 배포 용!
    devtool:'eval', 
    // eval -> 개발용 
    // hidden-source-map -> 배포용 

    resolve:{
        extensions:['.js', '.jsx']
    },

    // 입력받을 내용들 
    entry:{
        app:['./index.jsx']
    },

    // module을 통해 babel or sth 통해 해석해야하는구나 알도록 설정
    // 외부파일 가져와서 읽을 때 사용하는 
    // babel은 js 뿐만 아니라 다른 파일도 읽을 수 있음 -> 규칙 정해주기
    module:{
        rules:[{
            //확장자가 .jsx 이냐 .js이냐 - 적합하면 실행하겟다. 
            test:/\.jsx?$/, 
            //js 실행할 때 babel 쓸꺼야 ! 
            loader:'babel-loader', // webpack - babel 이해해주는 아이
            // babel 내용 바꾸고 싶을 때 ex) plugin, preset..
            options:{
                presets:[
                    ['@babel/preset-env', {
                        targets:{
                                //여기에 link 에 나온 내용들 넣어주기 
                            browsers:['>5% in KR','last 2 chrome versions']
                        },
                        debug:true,
                    }], 
                    '@babel/preset-react'
                ],
                plugins:[
                    'react-refresh/babel'
                ]
            }
            
        }]
    },
    //webpack이 구동이 될 때 아래 plugins를 무조건 실행하겠다. 
    plugins:[
        new webpackPlugin(),
        new webpack.LoaderOptionsPlugin({debug:true})
    ],

    // 내보낼 내용들 -현재 디렉토리 + dist까지 
    output:{
        path:path.join(__dirname,'dist'),
        filename:'app.js', 
        //정적 파일로 바꾼다. 
        publicPath:'/dist'
    },

    // 실행할 때 
    devServer:{
        publicPath:'/dist',
        hot:true, // hot reload 
    }
}

 

 

5) package.json  수정

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack server --env development"
  },

원래 dev : webpack 이었으나 위의 server --env development 로 변경

 

web server - 코드가 바뀔 때마다 다시 읽어서 build 해준다 --> 실시간 핫리로드 가능 

 

$npm run dev 실행 -> 아래 http:localhost:8080 이 나오고 --> 요기로 브라우저 들어가보면 해당 내용이 나옴 

그리고 이제 실시간으로 디버깅 가능해졌따 !

웹팩 장점

 

 

 

6) options 안의 debug를 전체에서 실행되도록 만들기 

webpack.config.js 

    //webpack이 구동이 될 때 아래 plugins를 무조건 실행하겠다. 
    plugins:[
        new webpackPlugin(),
        new webpack.LoaderOptionsPlugin({debug:true})
    ],

위에서 loader == module 안에서 option에 있는plugin을 모두 debug : true 해주겠다. 

 

맨 위에 webpack 추가 

const path = require('path')
const webpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin') 
const webpack = require('webpack') //추가

 

webpack.config.js 전체 코드 

const path = require('path')
const webpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')  //추가 
const webpack = require('webpack')


module.exports = {  //module.exports부터 무조건 쓰기 ! 
    name:'firstWebpack', //webpack의 이름  / 안적어도 된다. 
    mode:'development', //어떤 용도로 개발을 할 것이냐 
    // development -> 개발용 
    // production -> 배포 용!
    devtool:'eval', 
    // eval -> 개발용 
    // hidden-source-map -> 배포용 

    resolve:{
        extensions:['.js', '.jsx']
    },

    // 입력받을 내용들 
    entry:{
        app:['./index.jsx']
    },

    // module을 통해 babel or sth 통해 해석해야하는구나 알도록 설정
    // 외부파일 가져와서 읽을 때 사용하는 
    // babel은 js 뿐만 아니라 다른 파일도 읽을 수 있음 -> 규칙 정해주기
    module:{
        rules:[{
            //확장자가 .jsx 이냐 .js이냐 - 적합하면 실행하겟다. 
            test:/\.jsx?$/, 
            //js 실행할 때 babel 쓸꺼야 ! 
            loader:'babel-loader', // webpack - babel 이해해주는 아이
            // babel 내용 바꾸고 싶을 때 ex) plugin, preset..
            options:{
                presets:[
                    ['@babel/preset-env', {
                        targets:{
                                //여기에 link 에 나온 내용들 넣어주기 
                            browsers:['>5% in KR','last 2 chrome versions']
                        },
                        debug:true,
                    }], 
                    '@babel/preset-react'
                ],
                plugins:[
                    'react-refresh/babel'
                ]
            }
            
        }]
    },
    //webpack이 구동이 될 때 아래 plugins를 무조건 실행하겠다. 
    plugins:[
        new webpackPlugin(),
        new webpack.LoaderOptionsPlugin({debug:true})
    ],

    // 내보낼 내용들 
    // 현재 디렉토리 + dist까지 
    output:{
        path:path.join(__dirname,'dist'),
        filename:'app.js', 
        //정적 파일로 바꾼다. 
        publicPath:'/dist'
    },

    // 실행할 때 
    devServer:{
        publicPath:'/dist',
        hot:true, // hot reload 
    }
}

 


 

 

webpack 환경 구성하기 (자동) 

 

-> 프로젝트에 따라 webpack을 수동 or 자동으로 구성한다. 간단한 경우 자동적으로 쓰기도 하고 만약 조금만 규모가 커져도 직접 세팅하는게 좋다고 한다 !  그래도 개념을 익히기에는 스스로 설정을 해보면 best ! 

 

 

위의 내용을 수동으로 설정을 한 것이고 이제 위의 설정과는 100% 일치하지 않지만 자동으로 뚝딱 설정하기 ! 

 

1. 터미널 cd.. 명령으로 한 번 나가기 (webpack 할 파일의 부모 파일)

--> 요 아래에 새로운 파일을 만들 예정 (webpack으로 쓸) 

cd..

 

2. 아래 명령어 실행

$ npm i -g create-react-app
$ npx create-react-app reactsample   [reactsample은 파일명 설정으로 소문자로 내가 정하기 ! ]

* -g 는 global 의 뜻 

 

=> reactsample 이라는 폴더가 생성되어져 있음 ! 

 

 

3. 실행 명령어 입력 

$ npm start

 

 

 

안의 내용을 수정하면 실시간으로 변경된다 

 

 

 

 

 

 

static이라는 폴더를 숨겨놓음

 

reactsample 구조 잘 살펴보기 ! -> 위에서 수기로 설정을 한 것과 완벽히 일치하지 않고 큰 틀이 비슷하다. 

 

 

 

- 길고 긴 webpack 환경 설정 끝,,, - 

반응형