ABOUT ME

-

오늘
-
어제
-
-
  • webpack을 활용해 맛깔나게 번들링 해보기
    Front-end 2020. 10. 22. 03:12

    webpack (웹팩)

    현재 웹 시장에서는 bundler(번들러)를 아주 유용하게 사용하고 있습니다. 대표적으로 webpack, parcel, rollup 등 많은 번들러들이 있는데요, 그 많은 번들러들 중 웹팩은 가장 많이 사용되고 있으며 최고의 자리를 지키고 있는 번들러입니다.

     

    최고의 자리를 지키는 이유에는 몇가지가 있는데 대표적인 이유는 바로 생태계가 넓으며, 광범위한 커스터마이징이 가능하다는 점입니다.

    가장 많이 사용되고있는 만큼 생태계는 그만큼 넓을 수 밖에 없고 plugin을 통해 특정 기능을 내가 원하는대로 커스터마이징 할 수 있다는 것이 가장 장점입니다.

     

    bundle (번들)

    bundle의 뜻이 무엇일까요? 

    바로 "묶음"입니다. 여기에 -er이 붙어주면 묶어주는 역할을 하는 bundler가 됩니다. 여기에 진행형이 붙는다면 bundling이 되겠죠?

    즉, 묶어주는 것을 말하는데요 이 역할을 webpack이라는 도구가 해주게 됩니다.

    그렇다면 도대체 뭘 묶어주는걸까요?

    .

    .

    .

     

    바로 브라우저에서 사용할 파일들입니다.

    이 파일들은 HTML, CSS, JS, 이미지 등이 포함되는데 이는 전부 HTTP 통신을 통해 요청되어 리소스를 가져오게 됩니다.

    그렇다면 저 파일들이 적을 땐 크게 상관이 없지만 규모가 커져서 파일의 요청이 많아지게 된다면 통신량이 많아지게 되고, 이는 당연히 성능 저하의 큰 원인이 될 것입니다. 

     

    또한 Common.js와 AMD등을 통해 모듈이라는 개념이 등장하면서 이후 지속적으로 JS의 규모와 중요성이 대두되었고 이 또한 함께 관리해주어야 할 대상이 된것이죠...

     

    즉!! 이렇게 많은 파일모듈을 한데 모아서 사용할 수 있도록 해주도록 도와주는 것이 번들러이며, 번들러는 위와 같은 현상을 해결해줍니다. 또한 이런 기능 외에 번들러별로 가지고 있는 기능들을 활용하여 더욱 편리하고 효율적인 번들링을 할 수 있게 해줍니다.

     

     

    그래서 대표적인 웹팩을 통해 간단한 예제를 만들어보며 주요 기능에 대해 살펴보려고 합니다.

     

    전체 코드 보기

    프로젝트 구조

    웹팩이 5 버전이 추가됨에 따라 이전 버전인 4 버전으로 예제를 만들어보았습니다.

     

     

    프로젝트 생성

    먼저 예제를 구현할 프로젝트를 생성합니다.

    npm init -y

    package.json

    {
      "name": "webpack-example",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    

    최초 프로젝트를 생성하면 위와 같이 생성됩니다.

    그렇다면 웹팩을 프로젝트에 설치해야겠죠?

     

    webpack 설치

    웹팩을 활용하기 위해선 webpackwebpack-cli 두 가지가 필요합니다.

    결과물에서 동작하는게 아닌 영향을 주는 빌드에 활용되는 친구들이니 dev로 추가하겠습니다. 

     npm i --save-dev webpack@4.44.2 webpack-cli

    4.44.2 버전을 설치한 이유는 현재 웹팩이 5 버전으로 변경되었기 때문입니다. 아직 충분한 자료가 없기에 4.44.2 버전으로 예시를 만들어보겠습니다.

     

    설치가 완료되면 패키지에는 위 두 가지가 추가가 되어있을겁니다. 추가가 되었다면 루트 디렉토리에 webpack.config.js를 생성합니다.

     

    앞으로 알아볼 프로퍼티들은 전부 webpack.config.js에 추가되는 부분이니 이점 참고해주시면 됩니다. 

    자 이제 설치한 웹팩을 본격적으로 사용해보겠습니다.

     

    Entry

    entry는 웹팩이 파일을 읽기 시작하는 시작점입니다. 이 파일을 시작으로 하여 번들링을 진행합니다.

    module.exports = {
      entry: './src/index.js',
    };

    src/index.js를 시작점으로 하여 번들링을 하겠다는 것을 의미합니다.

    이제 시작을 했으니 끝이 있어야겠죠?

     

    Output

    빌드가 되서 최종적으로 번들링 파일이 나오는 지점을 설정합니다. 여기서는 pathfilename을 통해 경로와 파일명을 정할 수 있습니다.

    const path = require('path');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
    };
    

    dist란 폴더의 경로에 bundle.js라는 파일명으로 나온다는 의미입니다.

     

    시작과 끝 설정을 했으니 이제 진짜 파일이 나오는지 테스트를 해봐야겠죠?

    package.json

    {
      "name": "webpack-example",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "webpack": "^4.44.2",
        "webpack-cli": "^4.1.0"
      }
    }
    

    scripts에 build라는 명령어를 만들고 webpack을 입력해줍니다.

    build를 실행하게 되면 프로젝트에서는 webpack.config.js를 읽고 작성한대로 번들링을 해줄 것입니다.

    src/index.js

    console.log('hello webpack!!');
    

    그리고 src폴더와 index.js를 만들어 간단한 콘솔 하나를 찍어줍니다.

     

     

    npm run build

    위 명령어를 입력하고 잠깐 기다리면...!

    .

    .

    .

     

    위와 같은 안내창이 뜨면서 성공했다는 희소식을 들려줍니다.

    이제 정말 dist 폴더 내에 bundle.js라는 파일이 생성됐나 볼까요??

    .

    .

    .

     

     

    짜잔!!!! 진짜로 나왔습니다....

    아까 index.js에서 작성했던 콘솔이 있었는데 정말 번들링 된 파일에 들어가있는지 확인해볼까요?

    .

    .

    .

     

    dist/bundle.js

    파일의 맨 끝에 보면 아까 작성했던 콘솔이 잘 들어가 있습니다.

     

    여기까지의 기능만 보면 웹팩과 같은 번들러가 등장하기 전 browerify의 기능이 여기까지였습니다.

    웹팩이 제공하는 기능들을 더 살펴보겠습니다.

     

    Loader

    Loader(로더)는 개발자가 사용하기 편하도록 만들어 놓은 기능인데요, 하나의 모듈로 만들어 내는데에 기존에는 JS 파일들만 읽어내지만 특정 파일을 지정 그리고 특정 이펙트를 주어 해당되는 파일을 원하는데로 결과물에 반영할 수 있습니다.

     

    즉, 내가 원하는 파일을 선정하여 번들러가 파일을 읽어낼 때 특정 이펙트를 주어 번들링에 반영된다는 것입니다. 더 쉽게 말하자면 번들링의 과정에 영향을 미친다는 것입니다.

     

    대표적으로 CSS와 Babel이 있는데요, 이 두 가지를 예시로 살펴보겠습니다.

     

    먼저 CSS를 반영하기 위해서는 CSS 파일이 있어야 하기 때문에 src 디렉토리에 index.css 파일을 생성합니다.

    src/index.css

    .webpack {
      color: blue;
      font-size: 30px;
    }
    

    src/index.js

    그리고 CSS 파일을 index.js에서 import 해줍니다.

    import './index.css';
    console.log('hello webpack!!');

     

     

    이제 본격적으로 CSS관련된 로더를 사용하기 아래 두 가지를 설치합니다.

    npm i --save-dev css-loader style-loader

     

    그리고 아래와 같이 작성합니다.

    const path = require('path');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [{ test: /\.css$/, use: ['style-loader', 'css-loader'] }],
      },
    };
    

    module 내 rules 프로퍼티를 사용하는데 여기에는 배열로 2개 이상의 객체가 들어갈 수 있습니다.

    이 객체에서는 testuse 프로퍼티가 나뉘게 됩니다.

    • test: 규칙을 적용할 대상 (정규표현식 사용)
    • use: 특정 이펙트
    • exclude: 제외할 대상

     

    위 두가지를 활용하면 번들링 할 때 CSS를 함께 읽을 수 있습니다. 이게 어떻게 반영되는지는 추후 plugin에서 알 수 있게 됩니다.

     

     

    바벨(Babel)은 ES6 이상의 자바스크립트 문법을 트랜스파일링(transpiling)을 통해 하위 브라우저에서도 읽을 수 있는 ES5 이하의 문법으로 바꾸어주는 트랜스파일러(transpiler)역할을 합니다.

    바벨의 유래를 간단하게 설명하자면, 성경에서 나오는 바빌로니아의 바벨탑을 건축하면서 하늘에 다가가며 한 가지의 말을 사용하고 있었는데 예수가 이를보고 분노하여 언어를 제각각으로 만들고 다 흩뜨려 놓았다고 하는 유래가 있습니다.

     

    그래서 바벨의 의미는 현재 여러가지로 흩어져있는 문법을 하나로 통일해주는 역할을 한다고 보시면 됩니다.

     

    바벨을 사용하려면 아래 세 가지가 필요합니다.

    • babel-loader: js 파일을 읽을 때 core를 참조하여 트랜스파일링
    • @bable/core: 바벨의 중요 자료들
    • @bable/preset-env: 트랜스파일링을 어떤 문법으로 할지 지정  (기본은 ES5)

     

    npm install --save-dev babel-loader @babel/core @babel/preset-env

     

     

    설치가 완료 되었다면 아래와 같이 작성합니다.

    const path = require('path');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          { test: /\.css$/, use: ['style-loader', 'css-loader'] },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env'],
              },
            },
          },
        ],
      },
    };
    

    대상은 js 파일을 대상으로 하며 node_modules에 있는 파일들은 따로 트랜스파일링 할 필요가 없으니 exclude 해줍니다.

    또한 로더는 바벨을 사용할 것이고 기본 preset(ES5)로 적용할 것이기 때문에 기존 그대로 가져와 사용해줍니다.

     

    이렇게 되면 작성한 ES6가 빌드 후 전체 ES5 문법으로 변경되어 번들링됩니다.

     

    plugin

    플러그인은 여러가지 추가적인 기능들을 활용하여 번들링을 할 수 있는데요, 로더와 가장 큰 차이점으로는 로더는 번들링되는 과정에 대해 영향을 미치지만, 플러그인은 번들링된 결과에 대해 영향을 줍니다.

     

    대표적으로 HtmlWebpackPlugin을 통해 살펴보겠습니다. 이는 HTML 파일을 번들링된 js 파일에 자동으로 적용 후 파일을 함께 생성해줍니다. 그러기 위해선 src 폴더에 index.html을 예시로 하나 생성해줍니다.

    src/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>webpack</title>
    </head>
    <body>
        <span class="webpack">webpack</span>
    </body>
    </html>

     

    먼저 외부 플러그인이기 때문에 설치를 해야겠죠?

    npm i --save html-webpack-plugin

    설치를 완료했으면 아래와 같이 작성합니다.

     

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          { test: /\.css$/, use: ['style-loader', 'css-loader'] },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env'],
              },
            },
          },
        ],
      },
      plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
    };
    

    설치한 플러그인을 가져온 후 new 생성자를 통해 생성합니다. 여러가지 프로퍼티가 있지만 template를 통해서 번들링 될 대상을 선택해줍니다.

     

    그리고 다시 빌드를 통해 번들링을 하면 index.html 파일이 생성 되었을 것입니다.

     

    그럼 이제 저 index.html 을 실행하여 기존에 찍었던 콘솔이 브라우저에 나오는지 확인해볼까요?

    .

    .

    .

     

    !!!!!!!!!!!

     

     

    번들링 된 js 파일을 자동으로 적용해줘서 콘솔이 잘 나오는건 알겠는데... 갑자기 아까 파일을 생성하고 import 했던 CSS까지 적용이 되어있습니다. 이게 무슨일일까요?

    dist/bundle.js

    번들링 된 js 파일을 살펴보면, push 메소드를 통해 아까 선언한 css가 적용되어있는 것을 확인할 수 있습니다.

    즉, style-loadercss-loader를 사용하면 로더를 통해 번들링 되는 과정에서 HTML 파일에 스타일이 직접 작성 된다는 것을 알 수 있습니다.

     

    이 방법 외에 MiniCssExtractPlugin을 통해 CSS 파일을 만드는 방법도 물론 존재하니 필요에 의해서 커스터마이징 해도 됩니다.

     

     

    지금까지 완전 간단한 예제를 만들어 보며 웹팩의 핵심기능을 통해 번들링을 해보았습니다. 이보다 훨씬 더 많은 기능들이 있으니 개발자의 필요에 따라 커스터마이징 하며 다루면 되겠습니다.

    댓글