Webpack Part 3. Plugin

Eye0n·2020년 12월 4일
0

webpack

목록 보기
3/6

webpack 공식 홈페이지와 김정환님의 프론트엔드 개발환경 이해를 참고하여 작성했습니다.

Plugin

loader가 파일 단위로 처리하는 반면 plugin은 번들된 결과물을 처리한다. 번들된 자바스크립트를 난독화 한다거나 특정 텍스트를 추출하는 용도로 사용한다.

plugin은 arguments/options을 사용할 수 있으므로
webpack configuration에서plugins속성값을 new instance로 줘야한다.

webpack.config.js

//HtmlWebpackPlugin is installed via npm
const HtmlWebpackPlugin = require('html-webpack-plugin'); 

//to access built-in plugins
const webpack = require('webpack'); 

const path = require('path');

module.exports = {
  ...
  plugins: [ // new Instance로 속성값 주기
    new webpack.ProgressPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

자주 사용하는 플러그인

  • BannerPlugin
  • DefinePlugin
  • HtmlWebpackPlugin
  • MiniCssExtractPlugin
  • CleanWebpackPlugin

1. BannerPlugin

생성 된 각 chunk의 상단에 배너를 추가합니다.
결과물에 빌드 정보나 커밋 버전같은 걸 추가할 수 있다.

  • Usage

    webpack.config.js

    import webpack from 'webpack';
    
    // string
    new webpack.BannerPlugin({
      banner: 'hello world' // 배너 정보 문자열
    });
    
    // function
    new webpack.BannerPlugin({
      banner: (yourVariable) => { return `yourVariable: ${yourVariable}`; }
    });
  • Placeholders

    Since webpack 2.5.0, placeholders are evaluated in the banner string:

    new webpack.BannerPlugin({
      banner: 'fullhash:[fullhash], chunkhash:[chunkhash], name:[name], filebase:[filebase], query:[query], file:[file]'
    });

2. DefinePlugin

DefinePlugin을 사용하면 컴파일 타임에 구성 할 수있는 전역 상수 문자열를 만들 수 있습니다. 이 전역 상수 문자열를 통해development와 production 빌드간에 서로 다른 동작을 하도록 설정할 수 있다.

환경을 CLI로 조작할려면 NODE_ENV=develop || production을 해당 명령 앞에 적어주면 된다. 하지만
window환경에서는 에러가 난다. 이를 해결하기 위해 cross-env패키지를 설치해 줘야한다. 그다음 개발환경을 조작하는 명령 앞에 cross-env NODE_ENV=NODE_ENV=develop || production을 붙여 주면된다. 필자는 package.json파일에 script를 추가해줬다
npm i cross-env
package.json

"scripts": {
    "build": "webpack --progress",
    "prodbuild": "cross-env NODE_ENV=production npm run build"
  },
  • Usage

    DefinePlugin몇가지 규칙이 있다.

    • value가 string이면 코드 조각처럼 사용된다.
    • vaule가 string이 아니면 문자열화 된다.(func도 포함)
    • value가 Object이면 모든 key는 동일한 방식으로 정의된다.
    • key 앞에 접두사 typeof를 지정하면 typeof 호출에 대해서만 정의된다.
    //webpack.config.js
    const webpack = require("webpack")
    module.export = {
      ...
      plugins:[
          new webpack.DefinePlugin({ 
          //*전역 상수*
          PRODUCTION: JSON.stringify(true),
          VERSION: JSON.stringify('5fa3b9'),
          BROWSER_SUPPORTS_HTML5: true,
          TWO: '1+1',
          'typeof window': JSON.stringify('object'),
          'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
        });
      ]
    }
    ---------------------------------------------
    
    //app.js
    // 전역 상수 활용
    console.log('Running App version ' + VERSION);
    
    if(!BROWSER_SUPPORTS_HTML5) require('html5shiv');
    
    if (!PRODUCTION) {
      console.log('Debug info');
    }
    
    if (PRODUCTION) {
      console.log('Production log');
    }

3. HtmlWebpackPlugin

HtmlWebpackPlugin은 웹팩 번들을 제공하는 HTML 파일 생성을 단순화합니다.

  • entry point가 있으면 생성된 HTML파일에 <script>tags를 삽입해준다.

  • output point에 css파일이 있으면 (MiniCssExtractPlugin로 인해 css가 추출된 경우) 생성된 HTML파일의 <header><link>tags를 삽입해준다

htmlWebpackPlugin option 링크

npm install --save-dev html-webpack-plugin

var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');

module.exports = {
  ...
  plugins: [new HtmlWebpackPlugin()]
};

npm run build를 해주면 dist/index.html파일을 생성한다.

// src/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>webpack App</title>
  </head>
  <body>
    <script src="index_bundle.js"></script>
  </body>
</html>

환경을 CLI로 조작할려면 NODE_ENV=develop || production을 해당 명령 앞에 적어주면 된다. 하지만
window환경에서는 에러가 난다. 이를 해결하기 위해 cross-env패키지를 설치해 줘야한다. 그다음 개발환경을 조작하는 명령 앞에 cross-env NODE_ENV=NODE_ENV=develop || production을 붙여 주면된다. 필자는 package.json파일에 script를 추가해줬다
package.json

"scripts": {
    "build": "webpack --progress",
    "prodbuild": "cross-env NODE_ENV=production npm run build"
  },

Build 전

src/index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>타이틀<%= env %></title>
  </head>
  <body>
    ...
    <!-- <script src="main.js"></script> -->
  </body>
</html>

title tag에 ejs문법을 <%= env %>을 사용하여 전달받은 env 값을 출력한다. HtmlWebpackPlugin은 이러한 변수에 데이터를 주입시켜 동적으로 HTML 코드를 생성한다.
뿐만 아니라 웹팩으로 빌드한 결과물을 자동으로 로딩하는 코드를 주입해 준다.

HtmlWebpackPlugin option

  • template // 템플릿 경로를 지정
  • templateParameters // 템플릿에 주입할 파라매터 변수 지정
  • HtmlWebpackPlugin option 링크

webpack.config.js:

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports {
  plugins: [
    new HtmlWebpackPlugin({
       // 템플릿 경로를 지정
      template: './src/index.html',
      
      // 템플릿에 주입할 파라매터 변수 지정
      templateParameters: {
        env: process.env.NODE_ENV === 'development' ? '(개발용)' : '',
      },
      minify:
        process.env.NODE_ENV === "production"
          ? {
              collapseWhitespace: true, // 빈칸 제거
              removeComments: true // 주석 제거
            }
          : false,
      hash: process.env.NODE_ENV === "production"
    })
  ]
}

이렇게 설정하고 development build를 해주면 아래 코드와 같이 새로운 scripttag가 삽입된다. 또한 ejs문법 부분에 (개발용)문자열이 적용된 것도 볼 수 있다

development Build 후

npm build

<!DOCTYPE html>
<html>
  <head>
    ...
    <title>검색(개발용)</title>
  </head>
  <body>
    ...
  <!-- <script src="dist/main.js"></script> -->
  <script type="text/javascript" src="main.js"></script></body>
</html>

production Build 후

title태그에서 (개발용)이 없는 것을 볼 수 있다.
script태그가 추가되었다.

npm prodbuild

<!DOCTYPE html>
<html>
  ...
    <title>검색</title>
  </head>
  <body>
    ...
    <script type="text/javascript" src="main.js?d130f7718ede01c57909"></script>
  </body>
</html>

4. MiniCssExtractPlugin

개발 환경에서는 CSS를 하나의 모듈로 처리해도 상관없지만 프로덕션 환경에서는 분리하는 것이 효과적이다.
스타일시트가 점점 많아지면 번들된 파일의 용량도 커지기 때문에 별도의 css파일로 만들어 역할에 따라 파일을 분리하는게 좋다.
여러 작은 파일을 동시에 다운로드하는 것이 큰 파일 하나 받는 것보다 빠르다.

번들된 js파일에서 css를 별도의 파일로 추출한다.
css를 포함하는 js파일 당 1개의 css파일을 생성한다.

MiniCssExtractPlugin의 결과로 인해 css파일이 생기면 HtmlWebpackPlugin에서 css에 대한 link태그를 html에 삽입하게 된다.

npm install --save-dev mini-css-extract-plugin

style.css

body {
  background: green;
}

component.js

import './style.css';

개발환경일때 설정

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        // MiniCssExtractPlugin.loader 설정
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
  plugins: [new MiniCssExtractPlugin()],
};

MiniCssExtractPlugin은 css에 적용하기 위해서 loader가 필요한데 이것이 바로 MiniCssExtractPlugin.loader이다 loader이기 때문에 module.rules에 추가되어야한다.

배포환경일때 설정

배포환경 조건에 따라 설정을 해주기위해 plugin에filter(Boolean)을 사용했다.

webpack.config.js

const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

process.env.NODE_ENV = process.env.NODE_ENV || "development";

module.exports = {
  mode: process.env.NODE_ENV,
  ...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          // 배포 환경일 경우에만 적용
          process.env.NODE_ENV === "production"
            ? MiniCssExtractPlugin.loader // 프로덕션 환경
            : "style-loader", // 개발 환경
          "css-loader",
        ],
      },
    ],
  },
  plugins: [
    ...
    , 
    // 배포 환경일 경우에만 적용
    process.env.NODE_ENV === "production" &&
      new MiniCssExtractPlugin({ filename: "[name].css" }),
  ].filter(Boolean),
};

5. CleanWebpackPlugin

빌드 이전 결과물을 제거하는 플러그인이다.
output엔트리에 해당되는 파일들을 모두 삭제한다.
Cleaning up the /dist folder

npm install -D clean-webpack-plugin

const { CleanWebpackPlugin } = require("clean-webpack-plugin")

module.exports = {
  ...
  plugins: [new CleanWebpackPlugin()],
}

Reference

프론트엔드 개발환경의 이해
Webpack 공식 홈페이지

0개의 댓글