Webpack - 로더(Loader) & 플러그인(Plugin)

로더 (Loader)

[ 설명 ]

[ 로더(loader) 란 ? ]

  • 로더는 빌드 도구를 통한 빌드 과정에서 각 파일을 import 혹은 load할 때 모듈의 소스코드를 변형시키는 전처리 과정을 수행
  • Typescript 같은 다른 언어를 Javascript로 변환하고, imagedata url로 바꾸며, css파일importJS코드로 옮길 수 있음
    • webpack은 기본적으로 JS / JSON 파일만 이해할 수 있어서, other type의 파일을 convert 해줘야 한다
    • webpack은 모든 것을 하나의 모듈로 처리 (CSS파일, JS파일 등등)
  • webpack에서 로더의 적용은 배열 뒤 -> 앞 방향으로 적용한 순서대로 실행
  • 번들링된 결과에 hash값을 붙이는 것은, 브라우저가 로컬 캐시로 이전 데이터를 바라보지 않게 하기 위함
    • 빌드할 때 clean-webpack-plugin 플러그인을 통해 해시값이 바뀌면서 불필요하게 쌓이는 빌드 파일을 없앨 수 있다
  • webpack concepts : https://webpack.js.org/concepts/#loaders

[ 자주 사용되는 로더 ]

  • css-loader
  • style-loader
  • file-loader / url-loader
    • 둘 다 webpack5에서 Asset 파일을 처리하기 위해 내장된 모듈인 Asset Modules 에 기능이 통합됨
    • file-loader => type : asset/resource
    • url-loader => type : asset/inline
  • babel-loader

[ css-loader / style-loader ]

[ css-loader ]


[ style-loader ]


[ 적용 예시 ]

/* webpack.config.js */
{
    module: {
        rules: [
          /* css-loader + style-loader
             css-loader => style-loader 순서로 실행 */
          {
              test: /\.css$/,
              use : [
                  'style-loader',
                  'css-loader'
              ]
          }
        ]
    }
}

[ file-loader / url-loader ]

[ file-loader ]

  • 이미지 같은 파일(file)을 가져오는 코드를 해석하고 로드하는 목적으로 사용
  • 기본적으로 해당 파일도 번들 결과가 존재하는 output 경로에 복사
    • 실제 코드에서 새롭게 복사된 경로인 output에 존재하는 파일을 참조할 수 있도록 publicPath 옵션을 지정해야 한다
  • webpack5에서 Asset Modulestype : asset/resource 으로 사용 가능

[ url-loader ]

  • 네트워크 리소스 없이 이미지 리소스를 사용하는 Data Url Scheme 적용을 자동화 해주는 로더
  • 내부 로직 : 이미지를 base64 인코딩 + data url scheme 처리
  • 주로 크기가 작은 이미지들을 대상으로 사용하면 적합 -> 크기가 큰 이미지는 오히려 부담;
    • limit 옵션을 통해 특정 크기 이하의 파일을 대상으로 정할 수 있다
    • limit을 초과하는 파일들에 대해서 기본적으로 file-loader를 이용해 지정한 output 경로에 파일을 생성
  • webpack5에서 Asset Modulestype : asset/inline 으로 사용 가능

[ 적용 예시 - webpack 4 ]

/* webpack.config.js */
{
    module: {
        rules: [
          /* file-loader */
          {
              test: /\.(png|jpg|gif|svg)$/,
              loader: 'file-loader',
              options: {
                  // 파일을 사용할 때 로더에 의해 경로가 바뀔수 있어서 사용측의 기본 사용 path 지정
                  publicPath: './dist/',
                  // [원본파일].[확장자]?[해시값] -> 브라우저 로컬 캐시 무력화를 위해 캐시값 지정
                  name: '[name].[ext]?[hash]'
              }
          },
          /* url-loader */
          {
              test: /\.(png|jpg|gif|svg)/,
              loader: 'url-loader',
              options: {
                  publicPath: './dist/',
                  name: '[name].[ext]?[hash]',
                  // 20kb 보다 작은 파일만 url-loader 적용
                  limit: 20000, // 20kb
              }
          }
        ]
    }
}

[ 적용 예시 - webpack 5 ]

/* webpack.config.js */
{
  output: {
    filename: "[name].js",
    path: path.resolve("./dist"),
    assetModuleFilename: "images/[name][ext]", // asset/resource 와 /asset 에서만 적용
  },
 module: {
    rules: [
      /* png 파일을 assetModuleFilename 지정한 경로와 형식으로 결과물 생성 */
      {
        test: /\.(png)/,
        type: "asset/resource", // default 생성 파일 이름  : [hash][ext][query]
      },
      /* jpg 파일을 generator > filename 을 통해 custom한 경로와 형식으로 결과물 생성 */
      {
        test: /\.(jpg)/,
        type: "asset/resource",
        generator: {
          filename: "static/[name][ext]", // 생성 파일 이름 custom
        },
      },
      /* svg 파일을 data url scheme로 js 코드 내에 인라인으로 삽입 */
      {
        test: /\.(svg)/,
        type: "asset/inline",
      },
        ]
    }
}

/*
├── images
│   └── times-circle.png
├── index.html
├── main.js
└── static
    └── default-image.jpg
*/

플러그인 (Plugin)

[ 설명 ]

[ 플러그인(Plugin) 이란 ? ]

  • Loader파일 단위로 처리하는 반면, Plugin번들링된 결과물을 처리
  • Loader함수로 정의하지만, Plugin클래스로 정의
  • Pluginbundle optimization / asset management / injection of environment 등으로 활용 가능
  • webpack concepts : https://webpack.js.org/concepts/#plugins
  • 자주 사용하는 플러그인
    • BannerPlugin
    • DefinePlugin
    • HtmlTemplatePlugin
    • CleanWebpackPlugin
    • MiniCssExtractPlugin

[ BannerPlugin ]

[ 설명 ]


[ 적용 예시 ]

/* webpack.config.js */
{
    plugins: [
        new webpack.BannerPlugin({
            banner: `
            Build Date : ${new Date().toLocaleString()}
            Commit version : ${childProcess.execSync('git rev-parse --short HEAD')}
            Author : ${childProcess.execSync('git config user.name')}
            `
        })
    ]
}


/* bundle.js - 결과물 */
/*!
 * 
 *             Build Date : 3/20/2022, 11:52:09 PM
 *             Commit version : ca82fa1
 *
 *             Author : hue
 */
... bundle js code

[ DefinePlugin ]

[ 설명 ]

  • compile time에 코드에 있는 특정 변수를 다른 이나 표현으로 바꿀 수 있다
    • phase 환경 마다 상이한 정보들을 관리할 때 유용한 플러그인
  • 생성시 빈 객채를 전달해도 기본적으로 process.env.NODE_ENV 값은 넣어준다
    • process.env.NODE_ENV = 'production'
    • process.env.NODE_ENV = 'development'
      (webpack.config.jsmode 값을 바라본다)
// mode=development
+ mode: 'development'
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }), // 자동 주입

// mode=production
+  mode: 'production',
- new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }), // 자동 주입

[ 적용 예시 ]

/* webpack.config.js */
{
    plugins: [
        new webpack.DefinePlugin({
            /* 웹팩의 빌드타임에서 사용가능한 전역 변수로 등록이 된다
               => 런타임에서는 접근이 불가, 하지만 빌드 타임에 전역으로 선언되어 전역 scope를 더럽힐 수 있음
               => 조심해서 사용
            */
            data: JSON.stringify('3+4'),
            api_domain: JSON.stringify('https://dev.api.domain.com')
        })
    ]
}

[ HtmlTemplatePlugin ]

[ 설명 ]


[ 적용 예시 ]

/* webpack.config.js */
{
    plugins: [
        new HtmlWebpackPlugin({
            // JS 파일을 넣을 html template 지정
            template: './src/index.html',
            // template 내부에서 ejs문법으로 지정된 변수에 값 매핑
            templateParameters: {
                env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
            },
            // 생성되는 HTML template를 최소화 하는 옵션
            minify: process.env.NODE_ENV === 'production' ? {
                collapseWhitespace: true, // 공백 제거
                removeComments: true, // 주석 제거
            } : false
        })
    ]
}

[ CleanWebpackPlugin ]

[ 설명 ]


[ 적용 예시 ]

/* webpack.config.js */
{
    plugins: [
        new CleanWebpackPlugin()
    ]
}

[ MiniCssExtractPlugin ]

[ 설명 ]

  • bundleJS코드 내부에 string으로 들어간 CSS코드추출별도의 파일로 분리해주는 third party 플러그인
  • JS 내부에 삽입되는 CSS 스타일 시트의 크기가 큰 경우 불러오는 데 오래 걸릴 수 있기에 분리해주는 것이 좋다
  • 주의 : style-loader 대신 별도로 제공하는 MiniCssExtractPlugin.loader 를 사용해야 한다
  • webpack guide : https://webpack.js.org/plugins/mini-css-extract-plugin

[ 적용 예시 ]

/* webpack.config.js */
{
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            /* prod phase에서만 MiniCssExtractPlugin.loader 적용 */
            process.env.NODE_ENV === "production"
              ? MiniCssExtractPlugin.loader
              : "style-loader",
            "css-loader",
          ],
        },
      ]
    },
    plugins: [
        // prod phase에서만 css파일을 분리해서 js에 적용하도록 설정
        ...(process.env.NODE_ENV === 'production' ? [new MiniCssExtractPlugin({filename: '[name].css'})] : [])
    ]
}

좋은 웹페이지 즐겨찾기