기타

[WEBPACK] 플러그인(Plugin)

보겸삼촌 2020. 2. 24. 14:13

1. 플러그인(Plugin)이란,

webpack으로 변환한 파일에 추가적인 기능을 더하고 싶을 때 사용

webpack의 기본적인 동작에 추가적인 기능을 제공

 

  로더가 파일 단위로 처리한다고 하면, 플러그인은 번들된 결과물을 처리함.

  즉, 번들된 js를 난독화 하거나 특정 텍스트를 추출하는 용도 등으로 사용됨

 

  

2. loader과 plugin의 차이점

# 차이점

   loader는 파일을 해석하고 변환하는 과정에 관여하여 모듈을 처리 

   plugin은 해당 결과물의 형태를 바꾸는 역할을 하므로 번들링된 파일을 처리한다는 점

 

따라서, 번들된 파일을 압축할 수도 있고 파일 복사, 추출, 별칭 사용 등의 부가 작업 가능, 파일별 커스텀 기능을 위해 사용함

 

3. plugin 만들기

  3.1. customplugin.js 생성

     /root/customplugin.js

/**
 * /root/customplugin.js
 */


//플러그인은 클래스로 제작함
//플러그인 작업이 완료되는 시점에 로그를 찍는 함수
class Customplugin{
    apply(compiler){
        compiler.hooks.done.tap('custom Plugin', stats => {
            console.log('custom plugin : done');
        })
    }
}

module.exports = Customplugin;

 

  3.2. webpack 설정 수정

     3.2.1. plugin require

     3.2.2. plugins 속성 추가, new 인스턴스 전달

/**
 * /root/webpack.config.js
 */

const path = require('path');
const CustomPlugin = require('./customplugin');

module.exports = {
    mode: 'development',
    entry: {
        main: './src/app.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve('./dist'),
    },
    module: {
        rules: [
            {
                test: /\.jpg$/,
                loader: 'url-loader',
                options:{
                    publicPath: './dist/',
                    name: '[name].[ext]?[hash]',
                    limit: 5000,    //5kb 미만의 파일만 data url로 처리
                }
            },
            { 
                test: /\.jpg$/, 
                loader: 'file-loader', 
                options:{
                    publicPath: './dist/',          //prefix를 output 경로로 지정
                    name: '[name].[ext]?[hash]',    //파일명 형식
                    
                    //publicPath: file-loader가 처리하는 파일을 모듈로 사용할 때, 경로 앞에 추가되는 문자열
                    //name: loader가 파일을 output에 복사할 때 사용하는 파일 이름
                }
            },
            { test: /\.css$/, use: ['style-loader', 'css-loader']},
        ],
    },
    plugins: [
        new CustomPlugin(),
    ]
}

 

  3.3. 확인

 

    : plugin은 번들링한 결과물을 대상으로 하기 때문에, 여기서는 main.js 하나 밖에 없으므로 한 번만 동작한 것임

 

 

 

4. 자주 사용하는 플러그인

플러그인 명 설명
BannerPlugin 결과물에 빌드 정보나 커밋 버전 내용 등을 추가할 수 있음
DefinePlugin 같은 소스를 다른 환경에 배포하기 위해 환경 의존적인 정보를 소스가 아닌 곳에서 관리하기 위해서 환경정보를 제공하기 위해 사용하는 플러그인
HtmlWebpackPlugin HTML 파일을 후처리 하는데 사용하며, 빌드타임의 값을 넣거나 코드를 압축함
CleanWebpackPlugin 빌드 이전의 결과물을 제거
MiniCssExtractPlugin 결과물에서 스타일 코드만 뽑아서 별도 css 파일로 만들어 역할에 따라서 파일을 분리하는 것이 좋을 때 사용, 브라우저에서 큰 파일 하나를 받는 것보다 여러 개의 작은 파일을 동시에 처리하는게 빠르기 때문.

 

  4.1. BannerPlugin 사용법

    4.1.1. 단순 생성자 함수에 전달하는 옵션 객체에 banner 속성에 문자열을 전달하는 방법

 

    /root/webpack.config.js

const webpack = require('webpack');

...

module.exports = {

...
   plugins: [
   new webpack.BannerPlugin({
        //생성자 함수에 전달하는 옵션 객체의 banner 속성에 문자열을 전달
        banner: '배너 내용입니다. 빌드 정보나 커밋버전 등을 추가할 수 있습니다.',
   }),
   ]
}

  

 

   4.1.2. 배너 정보를 별도 파일로 분리하는 방법

 

     4.1.2.1. banner.js 파일 생성

/**
 * /root/banner.js
 */

const childProcess = require('child_process');

module.exports = function banner() {
    // const commit = childProcess.execSync('git rev-parse --short HEAD') //커밋 해쉬
    const user = childProcess.execSync('git config user.name')            //빌드 유저 정보
    const date = new Date().toLocaleString();

    return (
        // `commitVersion: ${commit}` +
        `Build Date: ${date}\n` +
        `Author: ${user}`
    );
}

 

     4.1.2.2. webpack 설정파일 수정

const webpack = require('webpack');
const banner = require('./banner.js')

...

module.exports = {

	...

	plugins: [
        /** 배너 정보가 많으면 별도 파일로 분리해도 좋음.
             *  1. banner.js 파일을 생성해서 배너 정보를 담음
             *  2. 설정파일 상단에 const banner = require('./banner.js); 선언
             *  3. plugins 속성에 new webpack.BannerPlugin(banner);
             */
        new webpack.BannerPlugin(banner),
    ]
}

 

    4.1.2.3. 확인 (dist/main.js)

 

 

 

  4.2. DefinePlugin

같은 소스를 다른 환경에 배포하기 위해 환경 의존적인 정보를 소스가 아닌 곳에서 관리하기 위해서

환경정보를 제공하기 위해 사용하는 플러그인

  : 빌드 타임에 결정된 값을 웹 애플리케이션에 전달할 때 사용하는 플러그인

 

 

    4.2.1. webpack 설정 수정

const webpack = require('webpack');

...

module.exports = {

	...

	plugins: [
        ...
        new webpack.DefinePlugin({}),
    ]
}

 

    4.2.2. /root/src/app.js 수정

import MainController from "./controllers/MainController.js";
import './style.css';


document.addEventListener("DOMContentLoaded", () => {
  new MainController();

  //definePlugin()
  console.log(process.env.NODE_ENV);
});

 

   4.2.3. build

   4.2.4. /dist/main.js를 확인해보면 결과 값으로 developement이 출력 됨을 확인할 수 있음

           브라우저에서 console을 확인해도 확인 가능

  4.2.5. 코드가 아닌 값을 입력하기 위해서는 문자열화 한 뒤 넘겨야 함

 

    4.2.5.1. webpack 설정 수정

/**
*  /root/webpack.config.js
*/

const webpack = require('webpack');

...

module.exports = {

	...

	plugins: [
        ...
        new webpack.DefinePlugin({
           VERSION: JSON.stringify('v.1.2.3'),
           MAX_COUNT: JSON.stringify(999),
           'api.domain': JSON.stringify('http://127.0.0.1'),
        }),
    ]
}

    4.2.5.2. /root/src/app.js 수정

import MainController from "./controllers/MainController.js";
import './style.css';


document.addEventListener("DOMContentLoaded", () => {
  new MainController();

  //definePlugin()
  console.log(process.env.NODE_ENV);
  console.log(VERSION);
  console.log(MAX_COUNT);
  console.log(api.domain);
});

    

 

 

  4.3. HtmlWebpackPlugin

HTML 파일을 후처리하고, 빌드 타임의 값을 넣거나 코드를 압축함

 

    4.3.1. plugin 설치

      [terminal] npm install html-webpack-plugin -D

 

 

    : 이 plugin으로 build하면 HTML 파일로 output에 생성될 것임

 

    4.3.2. webpack 설정파일 수정

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

...
module.exports = {
...
	   new HtmlWebpackPlugin({
            template: './src/index.html',   //템플릿 경로 지정
            templateParameters:{
                //템플릿에 주입할 파라미터 변수 지정
                env: process.env.NODE_ENV === 'development' ? '(개발용)' : '',
                //NODE_ENV=development이면 타이틀(개발용)
                //NODE_ENV=production이면 타이틀로 출력 됨
            },
            //운영환경에서는 파일을 압축하고 불필요한 주석 제거 필요
            minify: process.env.NODE_ENV === 'production' ? {
                collapseWhitespace: true,       //빈칸 제거
                removeComments: true,           //주석 제거
            }: false,
            //정적 파일을 불러올 때 쿼리문자열에 webpack 해시 값을 추가
            hash: true,
        })
}

 

    4.3.3. 각각 실행해보고 root/src/index.html 타이틀을 확인

 

      [terminal] NODE_ENV=production npm run build

      [terminal] NODE_ENV=development npm run build

 

    

 

  4.4. CleanWebpackPlugin

빌드 이전의 결과물을 제거하는 플러그인

    4.4.1. plugin 설치

      [terminal] npm install clean-webpack-plugin -D

 

 

    4.4.2. webpack 설정 수정

...
const CleanWebpackPlugin = require('clean-webpack-plugin');

...
module.exports = {
...
    new CleanWebpackPlugin(),
}

 

  

  4.5. MiniCssExtractPlugin

CSS를 별도 파일로 뽑아내는 플러그인

 

    4.5.1. 플러그인 설치

      [terminal] npm install mini-css-extract-plugin -D

 

 

     4.5.2. webpack 설정 수정

var MiniCssExtractPlugin    = require('mini-css-extract-plugin'); //컴파일 된 css 파일을 별도의 css 파일로 분리

...

module.exports = {

...
module: {
	rules: [
    	{
       			//test : 변환(load)할 파일을 지정
                //정규 표현식으로 문자열 .css 확장자로 끝나는 것을 찾음
                test: /\.css$/,
                //.css확장자를 가진 모든 css 파일에 대해서 css-loader를 통해서 자바스크립트
                //파일로 번들링을 하고 style-loader로 html에 internal style로 넣어주게 됨

                //방법 1. css를 내부스타일로 DOM에 주입하는 스타일
                //use : 해당 파일에 적용할 로더의 이름
                //로더에서 모듈 로딩 순서는 오른쪽에서 왼쪽 순
                // use: ['style-loader', 'css-loader']

                //방법 2. 컴파일된 css파일을 별도의 css로 분리
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ],
                //제외할 폴더나 파일
                //다른 모듈을 사용해서 컴파일 하지 않도록 지정(안전성 확보를 위함)
                exclude: /node_modules/

                //로더를 사용해서 컴파일 할 것을 지정
                //include: 
        }
        ...
    ],
    plugins:[
        //컴파일+번들링 된 CSS 파일이 저장될 경로와 이름 저장
        new MiniCssExtractPlugin( {filename: 'css/style.css'})
        //...
    ]

 

 

 

 

[참고] http://jeonghwan-kim.github.io/series/2019/12/10/frontend-dev-env-webpack-basic.html