Webpack

빡기·2020년 3월 28일
0

Webpack?

자바스크립트 모듈 번들러

  • 웹 애플리케이션 제작 시 여러가지 구성자원(HTML, CSS ,JS)를 각각의 모듈로 조합해서 하나 혹은 몇개의 파일로 변환해주는 도구
  • 의존 모듈이 하나의 파일로 번들링되므로 별도의 모듈 로더가 필요없음
  • 자바스크립트 코드가 많아지면 하나의 파일로 관리하는데 한계가 존재,그렇다고 여러개 파일을 브라우져에서 로딩하는 것은 그만큼 통신 비용을 치뤄야하는 단점이 있다. 뿐만 아니라 각 파일은 서로의 스코프를 침범하지 않아야 하는데 잘못 작성할 경우 변수 충돌의 위험성도 있다
    => 위의 처럼 통신 비용 및 변수 충돌 위험성을 해결 가능

webpack 설정 단계 설명

1. npm init -y

2. npm i --save react react-dom

  • react :리액트 라이브러리
  • react-dom : browser, dom, webapp 관리

3. babel 관련 설치

npm install --save-dev @babel/core babel-loader @babel/preset-react @babel/preset-env babel-eslint
  • babel이 7로 업데이트 되면서 babel-core -> @babel/core로 수정
  • @babel/core : 리액트는 es6를 사용하므로 여러 브라우저에서 사용가능하도록 es5문법으로 바꿔줌
  • @babel/preset-react : jsx -> javascript
  • @babel/preset-env : es6 -> es5
    사실 babel은 그 자체로는 아무것도 하지 않는다
    preset과 plugin을 추가하지 않는다면 babel은 아무것도 하지 않는다

    babel-preset-env 추가설명
  • babel-loader : 자바스크립트 파일을 babel preset/plugin과 webpack을 사용하여 es5로 컴파일 해주는 plugin
    jsx -> javascript 로 컴파일
    html webpack plugin

4.webpack 설치

--save-dev : 개발환경에서만 사용되는 라이브러리라는 것을 명시

npm install --save-dev webpack webpack-dev-server webpack-cli html-webpack-plugin
  • webpack : 모든 리액트 파일을 하나의 컴파일된 하나의 자바스크립트 파일에 넣기 위해
  • webpack-dev-server : live reload
  • webpack-cli : build 스크립트를 통해 webpack 커맨드를 사용하기 위해
  • html-webpack-plugin : 나중에 webpack.config.js에서 사용할 플러그인

Plugins(컴파일러)

Webpack의 핵심 기능

  • babel plugins에서는 번들로 babel preset이 함께 온다
  • 사실 babel은 그 자체로는 아무것도 하지 않는다. 만약 preset과 - plugin을 추가하지 않는다면 babel은 아무것도 하지 않는다
  • babel 자체로는 아무것도 안함(plugins이 사실상 compile 작업 역할)
  • 매번 plugin 패키지 설치을 통하여 기존에 있던 수동적인 방식인 .babelrc에 추가하는 방법에서 plugin 패키지 설치를 통하여 좀 더 효율적으로 관리 가능
  • preset으로 plugin 그룹 한번에 설치
  • 공식 preset 사용 (@bable/core)

Preset에 대해

  • plugin의 집합
  • plugin이 필요할 때마다 매번 webpack에서 설정하는 것은 귀찮은 일이므로 plugin들을 모아놓은 preset을 한번에 추가하여 관리

원래 동작은 css loader에 의해 css파일에서 css코드들을 부릅니다. 그리고 csso loader에 의해 최적화 작업과 text를 추출하는 plugin에 의해 style.css라는 파일에 원하는 css 코드를 담습니다

webpack 설정이 들어가면, text plugin에 의해 css 파일에서 css 코드를 추출하고 webpack 안의 csso plugin에 의해 중복되는 코드를 최적하여 style.css에 담음(webpack plugin이 좀더 밀도 있는 작업을 진행)

5. sass 로더 설치

npm --save-dev install node-sass style-loader css-loader sass-loader

webpack.config.js 안에 modules에 추가

module: {
    rules: [
      {
        test: /\.js$/, 
        exclude: /node_module/, 
        use: {
          loader: "babel-loader", 
        },
      },
      {
        test: /\.scss$/,
        use: [
          "style-loader", 
          "css-loader", 
          "sass-loader", 
        ],
        exclude: /node_modules/,
      },
    ],
  },

7. font 및 image 파일 로더 설치

npm install --save-dev file-loader

webpack.config.js 안에 modules에 추가

 module: {
    rules: [
      ...
      {
        test: /\.(gif|png|jpe?g|svg)$/i,
        exclude: /node_modules/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf|)$/,
        exclude: /node_modules/,
        use: [
          'file-loader'
        ]
      }
    ]
  },

9. webpack.config.js

const path = require('path')                                        // core nodejs 모듈 중 하나, 파일 경로 설정할 때 사용
const HtmlWebpackPlugin = require('html-webpack-plugin')            // index.html 파일을 dist 폴더에 index_bundle.js 파일과 함께 자동으로 생성, 우리는 그냥 시작만 하고싶지 귀찮게 index.html 파일까지 만들고 싶지 않다.!!

module.exports = {                                      // moduel export (옛날 방식..)
    entry: './src/index.js',                            // 리액트 파일이 시작하는 곳
   
  // devserver 설정
   devServer: {
    hot: true,
     // 부분 리로드(컴포넌트 일부수정 부분)
    inline: true,
     // 전체 페이지 리로드
     // hot, inline, open 등 여기서 선언 했으면 아래 package.json에서 script부분에서 빼도 된다!!
    port: 3000,
    host: 'localhost',
  
  },
    output: {                                           // bundled compiled 파일
        path: path.join(__dirname, '/dist'),            //__dirname : 현재 디렉토리, dist 폴더에 모든 컴파일된 하나의 번들파일을 넣을 예정
        filename: 'index_bundle.js'
    },
    module: {                                           // javascript 모듈을 생성할 규칙을 지정 (node_module을 제외한.js 파일을 babel-loader로 불러와 모듈을 생성
        rules: [
            {
                test: /\.js$/,                          // .js, .jsx로 끝나는 babel이 컴파일하게 할 모든 파일
                exclude: /node_module/,                 // node module 폴더는 babel 컴파일에서 제외
                use:{
                    loader: 'babel-loader'				// babel loader가 파이프를 통해 js 코드를 불러옴
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html'                // 생성한 템플릿 파일
        })
    ]
}

코드 설명

  • path :파일의 경로를 지정
  • __dirname : 노드 변수로 현재 모듈의 디렉토리를 리턴합니다.
  • HtmlWebpackPlugin :컴파일 이후 index.html 파일을 생성
    template에 지정된 index.html에 모든 static 파일들을 긁어모은 index_bundle.js 파일을 <script src='index_bundle.js'></script> 형식으로 연결
  • module.export : 출력할 모듈
  • entry : 컴파일 할 파일, index.js
  • output : 컴파일 이후 파일, __dirname/dist/index_bundle.js
  • module :모듈의 컴파일 형식
    es6 문법을 es5으로 바꾸기 위해 webpack이 js, jsx를 포함한 모든 파일을 babel을 통하여 컴파일
  • plugin : 사용할 plugins
    여기서는 htmlwebpackPlugin을 사용하여 index.html과 index_bundle.js에 연결해 줌
  • html-webpack-plugin
    html-webpack-plugin은 script 태그안에 넣은 webpack 번들 파일과 함께 html5 파일을 생성
    HTMLWebpackPlugin이 index.html의 script 태그안에 컴파일된 bundle 파일을 심어줌
    new HtmlWebpackPlugin()을 위의 예시처럼 그냥 사용하는 것도 좋지만 이렇게 템플릿을 만들어 놓으면 커스터마이징 하기 편리

총정리

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin()
  ]
}

--- 
  
// 위의 코드가 dist/index.html파일을 생성
// index_bundle.js가 webpack에 의해 컴파일, 번들화된 하나의 js 파일
  
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Webpack App</title>
  </head>
  <body>
    <script src="index_bundle.js"></script>
  </body>
</html>

다음은 웹페이지의 가장 기본이 될 index.html 파일을 src/index.html 경로로 아래와 같이 생성

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My React App</title>
</head>
<body>
    <div id="app"></div>				// 템플릿
</body>
</html>

.babelrc 설정

  • babel-preset-env와 babel-preset-react와 같이 preset을 사용하고 싶으면 root폴더에 .babelrc을 생성하여 사용하고자할 preset을 설정
  • plugin들을 각각의 npm dependency를 가지고 있습니다. 하지만 설치시 매번 .bablrc에 설정을 해야하므로 그 두가지를 모두 해결해줄 preset을 사용하면됩니다. preset을 설치하고 설정하므로서 preset이 가진 plugin들을 설정할 필요없이 사용 가능
{
    "presets": [
        "@babel/env",
        "@babel/react"
    ]
}

@babel이 버전이 업데이트 되면서 더이상 babel-core 형태(-)의 dependency를 지원하지 않게되므로서 @babel/env 형태(/)를 사용해야 합니다.

babel-plugin-module-resolver 이용하여 절대경로 설정

npm i --save-dev babel-plugin-module-resolver
플러그인을 설치한 뒤 babelrc에 추가

// babelrc
{
  ...,
  "plugins": [
    ["module-resolver", {
      "root": ["./src"],
      "alias": {
        "test": "./test",
        "underscore": "lodash"
      }
    }]
  ]
}

추가로 index.js, App.js 설정

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './component/App'

ReactDOM.render(<App/>, document.getElementById('app'))    

// src/App.js

import React from 'react'

export default class App extends React.Component {
    render(){
        return(
            <div>
                <h1>My React App</h1>
            </div>
        )
    }
}

package.json 설정

"scripts": {
    "start":"webpack-dev-server --mode development --open --hot --inline",   
// webpack-dev-server, --open : 자동으로 브라우저 열어줌, --hot : hot realod 저장했을 때 자동적으로 reload 해줌
    "build":"webpack --mode production"     
// dist 폴더에 컴파일된 파일 다 넣어줌
  }

npm run build 실행

/dist 폴더가 생성되면서 index_bundle.js와 index.html이 생성

index.html을 먼저 보면 script 태그가 body안에 생성되어 있는 것을 확인 가능
webpack.config.js 파일의 plugins 에서 Htmlwebplugin의 도움으로 template: './src/index.html' 템플릿에 컴파일 된 번들 파일이 script 태그로 자동적으로 들어가게 되는 것


Entry

  • 웹팩에서는 모든 것이 모듈인데, 자바스크립트, 스타일시트, 이미지 등 모든 것을 자바스크립트 모듈로 로딩해서 사용
  • 아래 그림 처럼 로딩하는 모듈이 많아질 수록 모듈 간의 의존성은 증가
    의존성의 시작점을 웹팩에서는 Entry라고 함

```

// webpack.config.js
module.exports = {
  entry: {
    main: './src/main.js',
  }
}

Output

  • Entry에 설정한 자바스크립트 파일을 시작으로 의존되어 있는 모든 모듈을 하나로 묶을 것이다. 번들된 결과물을 처리할 위치는 output에 기록
  • dist 폴더의 bundle.js 파일로 결과를 저장할 것이다.
  • html파일에서는 번들링된 이 파일을 로딩하게끔 한다.

index.html:

// webpack.config.js
module.exports = {
  output: {
    filename: 'bundle.js',
    path: './dist'
  }
}

// index.html
<body>
  <script src="./dist/bundle.js"></script>
</body>

로더

  • 웹팩은 모든 파일(js, image, font, stylesheet)을 모듈로 관리한다고 하지만, 웹팩은 자바스크립트 밖에 모른다. 자바스크립트가 아닌 파일을 웹팩이 이해하게끔 변경해야하는데 로더가 그런 역할을 한다.
  • 한마디로 js 말고 다른 파일들을 js로 바꿔주는 역할을 한다.
  • style-loader css를 dom에 추가
  • sass-loader SASS파일을 CSS로 컴파일
  • babel-loader babel로 javascript 코드를 transpile
  • test에 로딩할 파일을 지정
  • use에 적용할 로더를 설정

babel 로더

  • ES6에서 ES5로 변환할 때 바벨을 사용할수 있는데 test에 ES6로 작성한 자바스크립트 파일을 지정하고, use에 이를 변환할 바벨 로더를 설정
  • 사용 babel 로더 사용 전 npm 설치
    npm install --save-dev @babel/core babel-loader @babel/preset-react @babel/preset-env
// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.js$/,
      exclude: 'node_modules',
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['env']
        }
      }
    }]
  }
}

참고사이트

profile
Front End. Dev

0개의 댓글