[Webpack5] 플러그인

상민·2022년 7월 24일
0
post-thumbnail

플러그인

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


커스텀 플러그인 만들기

  • my-webpack-plugin.js

class MyPlugin {
  apply(compiler) {
    compiler.hooks.done.tap("My Plugin", (stats) => {
      console.log("MyPlugin: done");
    });
  }
}

module.exports = MyPlugin;

플러그인이 동작하면 MyPlugin: done 문자열이 출력되도록 했다

이제 해당 플러그인을 webpack.config.js에 설정해보자

  • webpack.config.js

const path = require("path");
const MyWebpackPlugin = require("./my-webpack-plugin");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        type: "asset", // 40KB(default) 미만은 inline, 이상은 resource로 대처
        parser: {
          dataUrlCondition: {
            maxSize: 20 * 1024, // 기준을 20KB 로 변경
          },
        },
      },
    ],
  },
  plugins: [new MyWebpackPlugin()],
};

로더를 module이라는 객체에 넣었다면, 플러그인은 plugins라는 배열에 추가하면 된다
배열 안에 만든 플러그인 클래스의 생성자를 new 키워드를 사용해서 생성해주면 된다

npm run build 명령어를 통해 결과를 확인해보자

npm run build
> webpack-babel-practice@1.0.0 build
> webpack

MyPlugin: done
assets by status 1.17 MiB [cached] 1 asset
asset main.js 52.8 KiB [compared for emit] (name: main)
runtime modules 2.42 KiB 8 modules
javascript modules 10.7 KiB
  modules by path ./node_modules/ 8.66 KiB
    modules by path ./node_modules/style-loader/dist/runtime/*.js 5.75 KiB 6 modules
    modules by path ./node_modules/css-loader/dist/runtime/*.js 2.91 KiB
      ./node_modules/css-loader/dist/runtime/noSourceMaps.js 64 bytes [built] [code generated]
      + 2 modules
  modules by path ./src/ 2.05 KiB
    ./src/app.js 181 bytes [built] [code generated]
    ./src/app.css 1.11 KiB [built] [code generated]
    ./node_modules/css-loader/dist/cjs.js!./src/app.css 779 bytes [built] [code generated]
asset modules 24.8 KiB (javascript) 1.17 MiB (asset)
  ./src/nyancat.jpeg 24.7 KiB [built] [code generated]
  ./src/bg.png 42 bytes (javascript) 1.17 MiB (asset) [built] [code generated]
webpack 5.73.0 compiled successfully in 143 ms

콘솔에 MyPlugin: done이 잘 출력되는것을 확인할 수 있다

로더가 여러개의 파일에 대해서 각각 실행했다면 플러그인은 번들 파일에 대해서 한번 실행된다


번들된 결과 처리하기

그러면 어떻게 번들 결과에 접근할 수 있을까?

  • my-webpack-plugin.js

class MyWebpackPlugin {
  apply(compiler) {
    // compiler.hooks.done.tap("My Plugin", (stats) => {
    //   console.log("MyPlugin: done");
    // });

    compiler.hooks.emit.tapAsync("My Plugin", (compilation, callback) => {
      const source = compilation.assets["main.js"].source();
      console.log(source);
      callback();
    });
  }
}

module.exports = MyWebpackPlugin;

compilation 객체를 이용해서 webpack이 번들링한 결과인 main.js에 접근할 수 있다

npm run build를 실행하면 콘솔에 번들 결과인 main.js의 내용이 출력되는 것을 확인할 수 있다


자주 사용하는 플러그인


BannerPlugin

BannerPlugin은 결과물에 빌드 정보나 커밋 버전같은 걸 추가할 수 있다
webpack이 기본적으로 제공하는 플러그인이다

  • webpack.config.js

const webpack = require('webpack');
  ...
plugins: [
    new webpack.BannerPlugin({
      banner: "이것은 배너입니다.",
    }),
  ],
  ...

webpack에서 기본으로 제공하는 플러그인 이므로 webpack 모듈을 사용한다
plugins 배열에 new 키워드로 BannerPlugin 생성자를 호출하는데 생성자에 객체를 전달할 수 있다
객체에 banner: "이것은 배너입니다."를 입력하고 build를 해보자

npm run build 명령어를 입력하여 번들링 후 번들 결과인 main.js에서 확인해보면
상단에 "이것은 배너입니다." 라는 주석이 추가된 것을 확인할 수 있다

  • webpack.config.js

  ...
const webpack = require("webpack");
const ChildProcess = require("child_process"); // 터미널 명령어를 실행할 수 있음
  ...
 plugins: [
    new webpack.BannerPlugin({
      banner: `
        month: "long",
         Build Date: ${new Date().toLocaleDateString("ko", {
          day: "numeric",
           year: "numeric",
        })}
        Commit Version: ${ChildProcess.execSync("git rev-parse --short HEAD")}
        Author: ${ChildProcess.execSync("git config user.name")}
      `,
    }),
  ],
  ...

main.js 최상단에 빌드날짜, 커밋버전, 작성자 같은 정보를 추가할 수 있다


DefinePlugin

애플리케이션은 개발환경과 운영환경으로 나눠서 운영한다
같은 소스 코드를 두 환경에 배포하기 위해서는 이러한 환경 의존적인 정보를 소스가 아닌 곳에서 관리하는 것이 좋다
배포할 때마다 코드를 수정하는 것은 곤란하기 때문이다

웹팩은 이러한 환경 정보를 제공하기 위해 DefinePlugin을 제공한다

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

빈 객체를 전달해도 기본적으로 넣어주는 값이 있다.
노드 환경정보인 process.env.NODE_ENV 인데 웹팩 설정의 mode에 설정한 값이 여기에 들어간다
현재는 development를 설정했기 때문에 애플리케이션 코드에서 process.env.NODE_ENV 변수로 접근하면 development 값을 얻을 수 있다

이 외에도 직접 환경변수를 넣을 수 있다

  ...
plugins: [
    new webpack.DefinePlugin({
      TWO: "1+1",
    }),
  ],
  ...
  • src/app.js

import "./app.css";
import nyancat from "./nyancat.jpeg";

document.addEventListener("DOMContentLoaded", () => {
  document.body.innerHTML = `
    <img src="${nyancat}" />
  `;
});

console.log(process.env.NODE_ENV);
console.log(TWO);

HtmlTemplatePlugin

HtmlTemplatePluginHTML 파일을 후처리하는데 사용한다
빌드 타임의 값을 넣거나 코드를 압축할 수 있다

먼저 패키지를 다운로드 한다

npm i -D html-webpack-plugin

이 플러그인으로 빌드하면 HTML파일로 아웃풋에 생성될 것이다
index.html도 웹팩으로 빌드할 것이기 때문에 index.html 파일을 src/index.html로 옮긴고 기존에 빌드된 main.js파일을 로드하는 script태그를 삭제한다

  • webpack.config.js

   ...
const  HtmlWebpackPlugin = require("html-webpack-plugin");
   ...
plugins: [
   ...
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      templateParameters: {
        env: process.env.NODE_ENV === "development" ? "(개발용)" : "",
      },
    }),
   ...
  ],

template에 index.html경로를 전달해준다
빌드 후 dist폴더를 확인해보면 index.html파일이 생성되었다
index.html파일을 확인해보면 script태그가 생성되어 있는것을 확인할 수 있다

HtmlTemplatePlugin을 사용하면 빌드 과정에 HTML도 포함하기 때문에 좀 더 의존적이지 않은 코드로 HTML을 만들 수 있다

  • src/index.html

   ...
<title>Document<%= env %></title>
   ...

templateParameters를 통해 개발환경 모드에 따라 HTML에 값을 전달해 줄 수도 있다
터미널에 NODE_ENV=development npm run build를 입력하고 dist/index.html를 확인해보자

  • dist/index.html

   ...
<title>Document(개발용)</title>
   ...

HtmlTemplatePlugin은 HTML을 압축하고 주석을 제거하는 기능도 있다

src/index.html에 주석을 추가하고 webpack.config.js에서 주석 제거와 빈칸 제거를 해보겠다

  • webpack.config.js

   ...
new HtmlWebpackPlugin({
      template: "./src/index.html",
      templateParameters: {
        env: process.env.NODE_ENV === "development" ? "(개발용)" : "",
      },
      minify: {
        collapseWhitespace: true, // 빈칸 제거
        removeComments: true, // 주석 제거
      },
    }),
   ...

minify 객체에 collapseWhitespaceremoveCommentstrue로 설정해주고 빌드를 해보자

빌드 결과를 확인해보면 다음과 같다

  • dist/index.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Document(개발용)</title><script defer="defer" src="main.js"></script></head><body></body></html>

주석이 제거되었고 코드가 한줄로 나열되어 있는 것을 확인할 수 있다

minify:
  process.env.NODE_ENV === "production"
    ? {
        collapseWhitespace: true, // 빈칸 제거
        removeComments: true, // 주석 제거
      }
    : false,

위와 같이 개발환경에서는 적용하지 않고 배포환경에서만 적용하도록 할 수 있다


CleanWebpackPlugin

CleanWebpackPlugin빌드 이전 결과물을 제거하는 플러그인이다
ouput경로에 남아 있을 수 있는 과거 파일을 제거해준다

먼저 패키지를 설치해준다

npm i -D clean-webpack-plugin
  • webpack.config.js

   ...
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
   ...
     plugins: [
        ...
    new CleanWebpackPlugin(),
  ],
   ...

webpack.config.js를 위와 같이 설정하고 output폴더인 /dist에 임의의 파일인 foo.js를 생성하자

생성 후 빌드해보면 dist폴더에 foo.js가 삭제된 것을 확인할 수 있다


MiniCssExtractPlugin

스타일시트가 점점 많아지면 하나의 자바스크립트 결과물로 만드는 것은 부담일 수 있다
번들 결과에서 스타일시트 코드만 뽑아서 별도의 CSS 파일로 만들어 역할에 따라 파일을 분리하는 것이 좋다
브라우저에서 큰 파일 하나를 내려받는 것 보다 여러 개의 작은 파일을 동시에 다운로드 하는 것이 더 빠르다

개발 환경에서는 CSS를 하나의 모듈로 처리해도 상관없지만 프로덕션 환경에서는 분리하는 것이 효과적이다
MiniCssExtractPluginCSS를 별도 파일로 뽑아내는 플러그인이다

먼저 패키지를 설치한다

npm i -D mini-css-extract-plugin
  • webpack.config.js

   ...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
   ...
   plugins: [
        ...
 	new MiniCssExtractPlugin({filename: '[name].css'}),
  ],
   ...
   

filename을 [name].css로 설정하여 원본 파일명을 가지도록 했다
MiniCssExtractPlugin은 굳이 개발환경에서는 적용할 필요는 없으므로 모드에 따라 적용시키도록 한다

  • webpack.config.js

   ...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
   ...
   plugins: [
        ...
 	...(process.env.NODE_ENV === "production"
      ? [new MiniCssExtractPlugin({ filename: "[name].css" })]
      : []),
  ],
   ...
   

이 플러그인은 다른 플러그인과 다르게 로더 설정도 해야한다

MiniCssExtractPlugin을 사용하려면 style-loader 대신에 자체적으로 제공하는 로더를 사용해야 한다

  • webpack.config.js

   ...
module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          process.env.NODE_ENV === "production"
            ? MiniCssExtractPlugin.loader
            : "style-loader",
          "css-loader",
        ],
      },
   ...

NODE_ENV를 production으로 빌드를 해보자

 NODE_ENV=production npm run build

dist폴더에 main.css가 생성된 것을 확인할 수 있다

dist/index.html에 link태그로 main.css를 불러오는 코드가 추가되었다


참고: https://jeonghwan-kim.github.io/series/2019/12/10/frontend-dev-env-webpack-basic.html
https://wnsah052.tistory.com/188

profile
FE Developer

0개의 댓글