본문 바로가기

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

[79일차] 20210705 react Webpack 웹팩 수동으로 개발 환경 구축/ 핫리로드 / & CRA 사용버전

반응형

 

Webpack 이란 ? 

 

웹팩 개념을 위함 자세한 포스팅 ↓↓

https://blckchainetc.tistory.com/253

 

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

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

blckchainetc.tistory.com

 

 

 

여러개의 JS를 하나의 JS로 만들기 

Component 별로 파일을 쪼개놓고 (코드를 짤 때, 협업할 때 필수) 그리고 실제로 빌드해서 배포할 때는 한 파일로 만들 때 Webpack을 쓴다. 

 

Node.js 환경에서 돌아간다. 웹팩을하기 위해 코드까지 짤 필요는 없지만 설정해야하는 것이 많다. 웹팩을 실행하기 위해서는 하나의 JS 파일이 필요하다. Json 형태로 된 변수가 엄청 많다. 환경설정하는게 코드 짤 때보다 힘들 수도 있다. 

 

 

예시 1) 

맨처음 let a = 10 

그 다음 외부 파일에 let a = 0 

그 다음 console.log(a)

console.log가 사실 찍히면 안된다고 함 (다른 대부분의 언어 기준) 

JS 같은 경우 모듈시스템이 잘 되어 있지않음 

어떻게 해야 변수가 꼬이지 않을가,,, --- Webpack 출현 ---> webpack에 보내면 위의 코드 둘 다 쓸 수 있도록 변환을 해줌. 코드가 꼬임이 없게 해줌 ! 변환을 해줄 때 모든 브라우저에서 실행이 가능한 코드로 바꿔 준다. 

하나의 파일로 묶어준다. (여러 파일로 쪼갤 수 있도록 해준다.) 

 

 

 


 

 

 

Webpack 환경설정 

 

1. cd webpack 까지 들어오기

2. 들어온 상태에서 terminal명령 실행 

$npm init 

 

3. react 아래 환경 설정

$npm install react 
$npm intstall react-dom

 

 

4. 이제 앞으로 사용할 webpack 설치 

$npm install -D webpack

-D = 개발 용도 (실제 배포 때는 사용하지 않는다 라는 의미) 

웹팩은 결국 하나의 파일로 만드는 것 ! -> 굳이 실 서버에 쓸 이유는 없다. 개발의 도구일뿐 ! 

 

5. webpack cli설치 

$npm install -D 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 / webpack-cli는 devDependencies 가 있음 ! 

 

 

6. 파일 webpack.config.js 만들기

-> webpack 아이콘 나타남 

* 이름 'webpack.config.js' 로 ! 

 

 

 

7. webpack.config.js  작성 

 

Concepts 순서대로 배워보기 

 

Entry : 내가 가져올 파일들을 설정하는 값 

합칠 파일들을 가리키는 내용 적기 - 복수이기 때문에 배열형태로 webpack이 읽을 파일들 알려주기 

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

 

 

Output : 내가 위의 파일들을 어떻게 내보낼 것인지 

경로와 파일명을 적기 - path는 절대경로를 가져오는게 좋다고 함. -> path 를 사용하기 

const path = require('path')

path = node.js 기본적으로 가지고 있기 때문에 설치가 필요 없다. 

 

    // 내보낼 내용들 
    // 현재 디렉토리 + dist까지 
    output:{
        path:path.join(__dirname,'dist'),
        filename:'app.js'
    }

 

 

전체 

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'
    }
}

 

 

 

8. index.html / index.jsx 새로 만들기 

 

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>
</body>
</html>

 

jsx - JS 파일인데 x을 달아줌   - > '아 리액트 컴포넌트 파일이구나' 구별할 수 있음 가독성의 차이일 뿐 / 기능이 다른게 아니다. 

 

0705webpack - index.jsx

--> 웹팩이 해석해서 다른 파일로 만들 것이야

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


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

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

 

 

 

9. webpack 실행시키기 

webpack.config.js 실행시켜서 index.html 파일을 바꾸ㅓ주는 것  

 

$ webpack  

-> 윈도우 환경의 경우에는 에러가 난다. 

첫 번째 방법 : package.json 파일에서 아래 scripts에 설정값 정하고

$npm run dev 

{
  "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",

 

두 번째 방법 :  

$npx webpack

 

 

--> 두 방법 다 에러가 나옴,,

 

 

JS 읽는 능력치를 올려줘야함 

저 화살표의 문제

webpack도 바벨 babel 이 있어야 사용이 가능하다 ! 

 

만약 babel을 사용 전인 React 아래 코드로 한 후 

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')
)

$ npm run dev 를 해보기  -> 오류없이 잘 됨 ! 

dist 폴더 - app.js 파일이 생김 

 

index.html 실행시켜보기 

 

구문 실행이 됨 

 

 

 

* build - 있던 코드를 다른 코드로 바꾸는 것 

 

 

 

 

 

10. webpack에 babel 세팅해주기 

webpack이 babel도 해석해 줄 수 있도록 ! - 환경설정이 생각보다 많이 길다. 

 

첫 번째 - bable의 기본적인 core 내용을 담고 있는

두 번째 - 브라우저에 맞게 최신문법을 옛날 문법으로 바꾸기

세 번째 - React에 필요한 babel을 설치하기

네 번째 - babel & webpack 연결해줄 때 

$npm install -D @babel/core
$npm install -D @babel/preset-env
$npm install -D @babel/preset-react
$npm install -D babel-loader

* 실무에서는 더 설치 필요한 경우도 있음 

 

 

 

 

11. 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:{
                preset:[
                    '@babel/preset-env', 
                    '@babel/preset-react'
                ]
            }
        }]
    },

 

 

---> 되는지 test 

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')
)

-> $ npm run dev 

-> presets로 변경 

 

Sucessfully 뜸 

 

JSX 파일 BUILD 완료 ---> app.js 파일로 변환됨 

 

* html 에 <script type="text/javascript"> 인 이유 ( "text/babel" 이 아닌 이유) 

이미 webpack에서 babel의 --> 일반 js로 만들었기 때문에 build할 떄 babel의 내용 해석해서 보냈기 때문

- 이미 webpack이 babel을 다 읽고 처리해서 보내줬기 때문 

 

components가 2만개야 그럼.. -> 그럼 넘 힘들 -> 최소화해주는게 webpack 

 

 

 

12. components module화 해서 사용하기 

 

loginBox.jsx 생성  & 아래 내용 붙여넣기

        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:'', 

요것도 가능 

 

마지막에 module.exports = Class 명 

module.exports = LoginBox 

 

 

이제 요 파일은 require로 보낼 수 있는 파일이 됨 

 

전체 코드 

const React = require('react')

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>
        )
    }
}

module.exports = LoginBox 


 

 

 

13. index.jsx에서 LoginBox 불러오기 

 

index.jsx

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


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

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

 

 

terminal 명령

$npm run dev 

or 

$npx webpack (package.json에서 설정안했다면) 

 

 

브라우저 확인 

오우.... 연결되엇당.. 신기하군,,

 

 

모듈화의 장점 

-> 하나의 component 씩 만들어서 위처럼 끼워 넣기 -> 협업이 좀 더 쉬워짐 ! 간결 

-> sub page의 경우 또 한 component를 재사용해야할 때 편함 ! 

 

 

 


 

 

 

1. 아래 내용을 import 사용해서 바꾸기 

 

webpack과 함께 있을 때만 import 구문이 사용된다. 

webpack.config.js 같은 경우 안되고 아래 index.jsx 가 됨 

 

index.jsx 

const React = require('react') // CRA 에서 import ~ 하는 경우가 있음 
// react 객체를 담아 사용하겠다. 
// react안에는 component가 있다. 그래서 아래에 저렇게 사용 가능 
// 비구조 할당문 {Component} = React 로 만들어서 아래 React제거 가능 
const ReactDOM = require('react-dom')
const LoginBox = require('./loginBox.jsx')

// require - node .js 에서 노드 구문
// import - js 버전 업그레이드되며 생김 (nodex.js 에서 X )
// import & require 둘 다 가능 import가 최근 추세 

아래처럼 변경 가능 

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'

 

 

 

2. 확장자가 반드시 있어야하는 이유 (위의 코드에서 LoginBox에 .jsx 없으면 오류!)

-> webpack에 확장자 설정해주기 

 

webpack.config.js

    devtool:'eval', 
    // eval -> 개발용 
    // hidden-source-map -> 배포용 

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

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

 

index.jsx 

import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import LoginBox from './loginBox'    //확장자 없애보기 

 

 

실행

$npm run dev or $npx webpack 

 

 

 

 

 

3. 핫 로드 (build를 다시 하지 않아도 실시간 ** 으로 처리해주는 것 설정)

== 자동으로 build 해주는 세팅 

webpack에 test 서버 하나 만들어서 구동시키기

코드가 변경될 때마다 서버를 알아서 restart 해주면서 코드의 내용을 바로 보여주기 

 

$ npm install -D react-refresh
$ npm install -D @pmmmwh/react-refresh-webpack-plugin
$ npm install -D webpack-dev-server

첫 번째, 두 번째 - react 코드 변경 시 refresh 

webpack-dev-server : express로 구현되어 있는 webpack 세팅을 다 해놓은 것 

 

 

 

 

pmmmwh 오류날 경우 아래 코드 입력 

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

 

 

 

 

4. index.jsx 실행될 때 무조건 실행될 plugin 설정 webpack 

 

webpack.config.js에 다운받은 내용 가지고 오기 

output 전에 가져왔던 plugin 달아주기

module 부분에 담기 

 

webpack.config.js 

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

 

 

첫 번째 코드에 대한 설정

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

 

 

두 번째 코드에 대한 설정

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

 

세 번째 코드에 대한 설정

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

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

 

 

package.json 파일 아래 dev 변경

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

 

 

webpack - webserver로 구동해서 돌리기

web server -코드가 바뀔 때마다 파일을 다시 읽어서 build 해줌 

 

$npm run dev 실행 -> http://localhost:8080/ 로 들어가면 내용이 뜸 --> 실시간 수정을 보여준다. 

 

 

장점 : --> 실시간으로 바뀜 / 디버깅하기 훨씬 쉽다 ! ex) 로그인하고 코드 코치고 새로고침하면 -> 다시 재로그인할 필요가 없다 ! --> 웹팩의 능력

 

 

 

 


 

 

 

preset-env - 옛날 문법을 최신 버젼으로 바꿔줌 

더 자세히 정해줄 수 있음 ! ~을 제외하겠다.  or 대한민국 점유율 5% 이상의 브라우저만 설정하겠다 등등..

 

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

 

 

webpack.config.js 

    // 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 실행 

$npm run dev 

 

 

options안 debug를 전체 실행되도록 만들기 

    //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') //추가 

 

 

전체 코드 

 

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 
    }
}

 

 

 

 


 

 

 

React 환경 구성하기 CRM 

 

 

1. cd.. 한 번 나가기 

 

2. 아래 명령어 실행 

$ npm install -g create-react-app

- g = global 

$npx create-react-app reactsample

reactApp -> 내가 생성한 폴더 명  / 폴더 명은 대문자 쓰면 안됨 

 

 

 

cd reactsample 들어가기 

실행할 때는 npm start 로 ! 

 

package.json 들어가보면 아까 본 익숙한 것들이 보임 

  "browserslist": {
    "production": [   //배포용
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [        //개발용
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]

 

 

$npm start

-> 안에 있던 react page 가 실행됨 (in src) 

-> 수정하면 바로바로 실시간으로 뜬다 ! 

 

별표뭐야,,,귀여워,,,,,,

 

static이라는 폴더를 숨겨놓음

 

 

reactsample 구조를 잘 살펴보기 ! 

 

위에서 직접 설정한 내용과 완벽히 똑같지 않지만... 큰 틀은 대강 비슷하다. 

 

 

반응형