[React] Webpack

이호정·2022년 8월 17일
0

React

목록 보기
2/5

네이버 블로그에서 이전, 원글 작성일시 : 2021.07.15.23:13

ZeroCho님의 React 무료강의를 들으며 이미 배웠던 내용이지만, 까먹을 때가 되어 남겨본다.

여러 React 강의나 실습들을 살펴보면 create-react-app을 사용하는 것을 쉽게 볼 수 있다.
손쉽게 프로젝트를 만들어주며, 별다른 설정 없이 바로 코드를 작성할 수 있어서 매우 편리하다고들 한다.

그렇다면 create-react-app 이전의 방법은 굳이 알 필요가 없을까? 사람마다 의견이 분분할 것이다.
하지만 나는 왜 그렇게 편리한지 공감하고 싶다. 그래서 조금 돌아가지만 배워보기로 했다.

모든 강의들을 다 들어보진 않았지만, 최소한 내가 들어본 무료강의 중 create-react-app을
사용하지 않고 webpack을 사용해서 빌드(?)를 해보는 강의는 제로초 님이 유일했다.

각설하고, webpack에 대해 알아보자!



webpack

사실 배우긴 했지만 자세히 알지는 못한다.
'이게 무엇인지' 보다는 '왜 필요한지?'에 초점을 맞춰 얘기해보자

만약 클래식하게 js 파일로 분리하지 않고 react를 사용한다고 하면,
아래 코드처럼 html 파일안에서 react, react-dom을 cdn으로 로드하고
script 태그안에서 이러쿵 저러쿵 컴포넌트 만들고 '#root' 태그 찾아서 렌더링 할것이다.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Test</title>
        <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    </head>
    <body>
        <div id="root"></div>

        <script type="text/babel">
            class Temp extends React.Component {
                state = { blahblah: 'something' };                

                render() {
                    return (
                        <div>Hello HoJang~!</div>
                    );
                }
            }
        
        </script>
        <script type="text/babel">
            ReactDOM.render(<Temp/>, document.querySelector('#root'));
        </script>
    </body>
</html>

지저분해서 벌써부터 보기가 싫은데, 만약 컴포넌트가 20000개라면?
한 html 파일안에 모두 작성되어 있어 보기도 불편하고 유지보수도 어려울 것이다.

'엥? 그럼 컴포넌트 마다 js파일로 분리해서 html에서 <script src="~" ~ />로 불러오면 되는거 아니냐?'


그러네?


하지만 그럼 20000개의 js 파일을 불러올때 <script ~/>를 20000번 해야한다.
(또 강의에서는 'script간에 중복이 발생한다.'라고 하셨는데 정확히 무슨뜻인지 모르겠다.)

그럼 모든 컴포넌트의 js 파일을 하나의 js 파일로 묶어주고, 이 1개의 js 파일만 불러오게끔 하면??? 개꿀!
그렇다. 이 일을 해주는 것이 webpack이라는 모듈 번들러 이다.

덧붙이자면, 이 webpack이라는 녀석은 여러 js파일을 묶어줄 때 다양한 옵션(?)을 적용할 수 있다.
babel을 적용하거나, console.log()를 전부 빼준다거나. 대단한 녀석이다.

그럼 이제 진짜 webpack을 설치하고 사용해보자


webpack 설치

$ 뒤는 터미널의 커맨드라인
당연히 node는 설치되어 있어야 한다.

1. $ npm init

name, author 말고는 적당히 엔터 치면 된다.

2. $ npm i react react-dom

react, react-dom 설치, 당연히 필요하다.

3. $ npm i -D webpack webpack-cli

react에서 webpack을 사용하기 위해 필요
-D 는 개발 단계에서만 사용하겠다는 뜻

여기까지하면 설치는 껕


webpack 설정

webpack.config.js 파일 생성 후 아래 코드 작성, 저장

module.exports = {

};

이제 저 중괄호 안을 채워나갈 예정이다. 중괄호는 js에서 객체를 뜻하고, 객체는 키-값으로 이루어진다.

하나씩 알아보고, 최종 코드를 보여줄 예정

name : 걍 이름, 별로 안중요한듯?
mode : 개발일때는 'development', 실서비스에는 'production'
devtool: 'eval' 사용(뭔지 잘모른다.), 실서비스에서는 'hidden-source-map'

entry: 묶을 js 파일을 지정하는 부분, 입력에 해당된다. 중요!
module: entry의 파일들에 옵션?을 적용하는 부분. 중요!
output: 최종 결과 js 파일에 대해 지정해주는 부분. 중요!

이외에도 resolve, plugins, devServer등이 있지만, 필요할 때 알아보도록 하자.

중괄호, 대괄호 많아서 헷갈린다. 주의하시길

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

module.exports = {
    name: 'word-relay-setting',
    mode: 'development', // 실서비스 : production
    devtool: 'eval', // production 일때는 : hidden-source-map

    // entry(입력)의 확장자를 전부 지정해주기 귀찮잖아? 이걸로 몇개 지정해놓으면 됨
    resolve: {
        extensions: ['.js', '.jsx']
    },

    // 중요!
    entry: {
        app: './client' // client.jsx 에서 WordRelay.jsx을 불러오기 때문에 굳이 또 입력할 필요 없음
    }, //입력

    // jsx, js 파일에 babel 적용시키기, babel -> jsx 같은 최신(실험적인) 문법을 해석하는 녀석
    module: {
        rules: [{
            test: /\.jsx?/,
            loader: 'babel-loader',
            options: {
                presets: [
                    // 각 프리셋들에 대한 세부설정까지 가능!
                    ['@babel/preset-env', {
                        targets: {
                            // browserslist 검색해서 찾아보자
                            // 한국에서 1%이상 점유율 가진 모든 브라우저까지 지원가능하도록 설정
                            browsers: ['> 1% in KR']
                        },
                        //디버그 모드에서 로그 확인가능
                        debug: true
                    }],
                    '@babel/preset-react'
                ],
                plugins: [
                    'react-refresh/babel'
                ]
            }
        }]
    },

    plugins: [
        // Loader : module 속성, 아래 문장은 모든 module안에 debug:true를 추가하겠다는 뜻
        new webpack.LoaderOptionsPlugin({debug: true}),
        new RefreshWebpackPlugin()
    ],

    // 중요!
    output: {
        path: path.join(__dirname, 'dist'), // __dirname : 현재 폴더 절대 경로
        filename: 'app.js',
        publicPath: '/dist/',
    }, //출력

    devServer: {
        publicPath: '/dist/',
        hot: true
    }
};

강의들으며 적은 주석까지 함께 올려봤다. 조금 부끄러운 느낌

참고로 위 module에 적어놓은게 babel을 적용하기 위함인데, 이를 위해선 몇가지 설치가 필요하다.

npm i -D @babel/core @babel/preset-env @babel/preset-react bable-loader

조금 설명하자면, core는 core (?)
preset-env는 내 환경에 맞게 최신 문법을 옛날 브라우저에서도 사용할 수 있게끔 바꿔준다.
preset-react는 jsx 사용을 위해 필요
loader는 babel과 webpack을 연결

module이 중요하다.

module: {
        // 적용할 규칙
        rules: [{
            // 적용할 대상 -> .js 또는 .jsx -> 정규표현식
            test: /\.jsx?/,
            
            loader: 'babel-loader',
            options: {
                presets: [
                    // 각 프리셋들에 대한 세부설정까지 가능!
                    ['@babel/preset-env', {
                        targets: {
                            // browserslist 검색해서 찾아보자
                            // 한국에서 1%이상 점유율 가진 모든 브라우저까지 지원가능하도록 설정
                            browsers: ['> 1% in KR']
                        },
                        //디버그 모드에서 로그 확인가능
                        debug: true
                    }],
                    '@babel/preset-react'
                ],
                plugins: [
                    'react-refresh/babel'
                ]
            }
        }]
    },

rules: 적용할 규칙
rules > test: 적용할 대상
rules > loader: 정확히 모르겠지만 여기선 바벨을 적용하기 위해 필요한 과정
rules > options > presets: 적용할 프리셋
rules > options > plugins: 플러그인

참고로 presets에는 ['@babel/preset-env', '@babel/preset-react'] 이렇게만 작성해도 된다.
위와 같이 각 프리셋에 세부설정을 하고 싶을 때 [ [프리셋, {세부옵션}], 프리셋, ... ] 이런식으로 사용한다.
targets에 browsers 옵션은 여기에서 확인할 수 있다.



webpack 실행

고생해서 설치에 설정까지 다했으면 실행을 해봐야하지 않겠나

$ webpack

command not found 같은 느낌으로 오류가 난다면 아래 두가지 방법을 이용하자

1. package.json에 script 지정

{
  ...,

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack"
  },
  "author": "HoJangMan",
  "license": "ISC",
  
  ...,
}

scripts 부분에 "dev": "webpack"을 추가해주고 터미널에 아래와 같이 실행하면 된다.

$ npm run dev

2. npx webpack

뭔지 아직도 모르겠지만, 마법의 세글자 npx..., 실행하면 마법같이 잘 된다.

오류가 나면 오류 내용이 보이니까 고쳐주고, 성공적으로 끝나면
output에 지정했던 곳에 js 파일이 생성될 것이다. ( 위의 경우 ./dist/app.js )


+코드 수정할 때마다 자동으로 실행하기

코드를 수정하고, webpack으로 빌드(?)하고 결과 확인하고...
여간 귀찮은 일이 아니다.

이를 위해 몇가지 설치와 설정 절차를 밟아보도록 하자

먼저 아래 커맨드로 필요한 녀석들을 설치

1. $ npm i -D react-refresh @pmmmwh/react-refresh-webpack-plugin
2. $ npm i -D webpack-dev-server

그리고 webpack.config.js 파일로 이동해서 최상단에 설치한 모듈 로드

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

그리고 아래처럼 plugins와 devServer 설정

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

module.exports = {
    ...,

    entry: {
        ...
    }
    module: {
        ...
    }

    plugins: [
        new RefreshWebpackPlugin()
    ]

    output: {
        ...
        publicPath: '/dist/',
    }

    devServer: {
        publicPath: '/dist/',
        hot: true,
    }
}

devServer의 publicPath는 output의 publicPath와 동일하게 설정
(사실 output의 publicPath가 언제 어떻게 들어갔는지 잘 기억이 나지 않는다.)

마지막으로 package.json에 scripts를 수정해줘야 한다.
"dev": "webpack serve --env development"를 추가

{
  ...,

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack serve --env development"
  },
  "author": "HoJangMan",
  "license": "ISC",
  
  ...,
}

$ npm run dev 를 실행하면 서버가 실행되고, localhost:8080에 접속하면 결과를 볼 수 있다. 서버가 동작하고 있는 동안에는 파일을 수정하면 바로바로 결과를 확인할 수 있으니 엄~청 편하다.





간단히 정리하려고 했지만 꽤 길어진 것 같은 느낌이 든다.

webpack, 보기보다 좋은 녀석으로 보인다. 좀 더 관심을 가져보도록 하자.


이건 방금 알게 된건데, 조금 충격이다.

webpack에 대해 조금이라도 이해하면 create-react-app의 구조에서 뭔가를 이해할 수 있을 줄 알았다.
확인해보니, 하나도 모르겠다. webpack의 web 도 찾아볼 수 없다.

왜 그런가 하니, create-react-app에서 webpack.config.js를 숨겨놓았고
이를 확인하려면 eject를 해야한다. ($ npm run eject)

실행하면 config와 scripts 폴더가 생성되고, config 폴더를 보면 익숙한 파일 명을 찾을 수 있다.
webpack.config.js를 들어가보면 말도 안되게 긴 코드가 반겨주는데
또 그 속에서 익숙한 녀석들을 찾을 수 있다. entry, module, output 등..

뭔가 묘한 느낌이 든다.
마치 연예인의 방귀냄새를 맡은 느낌. 뭐야 같은 사람이잖아?

대단히 어려운 방법으로 만들어진 것만 같았던 create-react-app이
내가 (조금이라도) 아는 내용을 기반으로 만들어졌다는 사실을 눈으로 확인했기 때문인가 보다.

복잡하고 어려운 코드가 많지만, 큰 틀은 아주 약간 이해할 수 있었고,
create-react-app 이라는 녀석이 왜 편한지 3% 정도는 공감할 수 있겠다.

0개의 댓글