ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • webpack 환경설정
    Webpack 2022. 3. 4. 11:23

     

     

    • npm init -y 로 package.json 생성해 줍니다.
      생성된 package.json 에서 아래처럼 dependencies를 추가해주고, 터미널에서 npm i 를 입력하여 해당 패키지에 들어가게 된 dependencies를 설치해주세요.
      혹은 첨부된 package.json을 다운 받으신 후 터미널에서 npm install 해주세요.

    package.json
    0.00MB
    package.json 내용

    • 이제 webpack, babel, handlebars, jquery, 각종 plugin, 각종 loader 등을 install 해줬습니다.
    • 프로젝트 root 레벨에 .babelrc 파일을 생성(babel사용)해주고, 하기와 같이 파일 내용을 작성 해줍니다.
    {
      "presets": [
        "@babel/preset-env"
      ]
    }

    Babel은 무엇이길래 .babelrc 라는 파일을 생성해준 건가요?

    Babel 공식 홈페이지(https://babeljs.io/)에서는 아래와 같은 문구로 설명해준다.

     

    Babel is a JavaScript compiler

     

    Q. Babel은 자바스크립트 컴파일러라고? 왜 자바스크립트를 다시 컴파일 하는 걸까?

    A. 모든 브라우저가 최신 자바스크립트 문법(ES6 이상)을 호환 하지는 못한다.

        Babel은 모든 브라우저가 이해할 수 있는 문법으로 컴파일 해주기 때문에

        ES6 이상의 최신 문법으로 코딩을 해도! 이제는 모든 브라우저에서 호환이 된다.

     

    *ES6 지원 브라우저 현황

    (https://caniuse.com/?search=es6)

     

     

    • 프로젝트 root 레벨에 webpack.config.js 파일을 생성(webpack 환경설정)해주고, 하기와 같이 파일 내용을 작성 해줍니다.
    const path = require('path');
    const webpack = require('webpack');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
    const TerserPlugin = require("terser-webpack-plugin");
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const HandlebarsPlugin = require("handlebars-webpack-plugin");
    
    module.exports = {
      mode: 'production',
      entry: {
        app: "./src/index.js",
        vendor: [
          "jquery"
        ]
      },
      output: {
        path: path.resolve(__dirname, "public"),
        filename: "[name].js",
        clean: true
      },
      devServer: {
        port: 9000
      },
      module: {
        rules: [
          {
            test: /\.s[ac]ss$/i,
            use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader']
          },
          {
            test: /\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/
          },
          {
            test: /\.(png|jpe?g|gif|webp)$/i,
            type: 'asset',
            generator: {
              filename: 'assets/images/[name][ext]'
            }
          },
          {
            test: /\.(woff|woff2|eot|ttf|otf)$/i,
            type: 'asset',
            generator: {
              filename: 'assets/fonts/[name][ext]'
            }
          },
          {
            test: /\.svg$/,
            loader: "svg-sprite-loader"
          }
        ]
      },
      optimization: {
        minimizer: [
          new CssMinimizerPlugin(), 
          new TerserPlugin()
        ]
      },
      plugins: [
        new webpack.BannerPlugin({
          banner: `Study build time : ${new Date().toLocaleTimeString()}`
        }),
        new MiniCssExtractPlugin({ filename: 'assets/css/style.css' }),
        new ImageMinimizerPlugin({
          minimizer: {
            implementation: ImageMinimizerPlugin.squooshMinify,
            options: {
              encodeOptions: {
                mozjpeg: {
                  quality: 85
                },
                webp: {
                  lossless: 1
                },
                avif: {
                  cqLevel: 0
                }
              }
            }
          }
        }),
        new webpack.ProvidePlugin({
          $: 'jquery',
          jQuery: 'jquery'
        }),
        new HtmlWebpackPlugin({
          title: 'main',
          template: path.join(path.resolve(__dirname, 'src'), 'index.html')
        }),
        new HandlebarsPlugin({
          entry: path.join(process.cwd(), "src", "handlebars", "**", "*.hbs"),
          output: path.join(process.cwd(), "public", "pages", "[path]", "[name].html"),
          data: path.join(__dirname, "handlebars.json"),
          partials: [path.join(process.cwd(), "src", "partials", "**", "*.hbs")],
          helpers: {
            isActive: function (value) {
              return value == ".";
            }
          }
        }),
      ],
      devtool: 'source-map'
    };

     

    다양한 속성들은 무엇을 뜻할까요?

    위처럼 설정한 webpack.config.js에 대해 부가 설명을 해봅시다.

     

    __dirtname: node.js에서 현재 실행 중인 JavaScript 파일 경로를 말합니다. webpack.config.js에서 썼으니까,
    `__dirname, 'src'` 는 webpack.config.js와 같은 경로에 있는 src 폴더를 가리킵니다.

    process.cwd(): 현재 작업 디렉토리를 반환합니다. 즉, node 명령을 호출한 디렉토리입니다.

    mode: 웹팩에 내장되어 있는 최적화 방법 중 어느 것을 사용할지 웹팩에게 알려주는 역할을 합니다.

    옵션은 3가지가 있으며(production, development, none), 값을 지정하지 않는 경우 production을 기본으로 설정하게 됩니다.

    production로 mode를 지정해줄 경우, css와 js 등 minimize 해주는 plugin이 동작하여 최적화된 배포 파일로 만들어 줍니다.

    평소 개발을 할 때는 webpack-dev-server를 사용하기 때문에 mode는 production로 지정해두면 될 것 같습니다.

    webpack guide에서 mode에 대해 더 알아보기

    entry: 애플리케이션 번들링을 시작할 지점을 의미합니다. 만약 배열을 값으로 전달하면, 배열에 담긴 모든 요소들이 번들링 됩니다.

    entry를 여러 개의 파일로 설정도 가능합니다.

    output: 웹팩으로 번들링하거나 로드하는 번들, 자산 그리고 기타 다른 것들을 어떻게, 어디에 내보내야 하는지 설정하는 옵션들을 가지고 있습니다.

    output에는 charset, library, path, filename 등의 옵션이 있습니다. 옵션에 대한 자세한 정보는 공식문서를 참고해주세요.

    Loader(module): 로더(Loader)는 웹팩이 웹 애플리케이션을 해석할 때 자바스크립트 파일이 아닌 웹 자원(HTML, CSS, Images, 폰트 등)들을 변환할 수 있도록 도와주는 속성입니다.

    plugin: 플러그인(plugin)은 웹팩의 기본적인 동작에 추가적인 기능을 제공하는 속성입니다. 로더랑 비교하면 로더는 파일을 해석하고 변환하는 과정에 관여하는 반면, 플러그인은 해당 결과물의 형태를 바꾸는 역할을 한다고 보면 됩니다.

     

     

     

    사용된 plugin은 무엇이 있을까요?

    각 플러그인의 기능을 요약해보았습니다.

     

    CleanWebpackPlugin(): output 으로 보내는 폴더 내에 있는 파일을 모두 삭제 해준 후 bundle 된 파일들을 넣어주게 됩니다.
    output에서 clean 속성으로 대체하였습니다.

    BannerPlugin(): build 되는 js 파일에 주석으로 banner를 넣을 수 있습니다.

    ProvidePlugin(): jQuery를 사용하기 위해서는  var $ = require("jquery") 처럼 추가로 각 파일마다 불러와줘야 했으나,

    해당 플러그인을 사용하면, 전역 $식별자가 발생할 때마다 자동으로 앞에 var $ = require("jquery")가 추가되도록 웹팩을 구성 할 수 있습니다 .

    MiniCssExtractPlugin(): style-loader, css-loader 만 사용할 경우에는 output에 css 파일이 따로 생성되지 않습니다.

    style-loader를 대체하며 html내의 style태그 대신 css 파일을 별도로 output에 지정한 폴더 경로에 결과물로 생성해줍니다.

    ImageMinimizerPlugin(): imagemin을 사용하여 이미지를 최적화합니다

    TerserPlugin(): javascript 번들 사이즈를 minify/minimize 하여 웹 성능을 높일 수 있습니다. webpack 공식문서에서 추천하는 uglify plugin 입니다.

    HtmlWebpackPlugin(): bundle한 css파일과 js파일을 각각 html 파일에 link 태그와 script태그로 추가해줘야 합니다. HtmlWebpackPlugin플러그인은 이것을 자동화해줍니다. 여러 개의 html 파일을 output에 넣어줘야 한다면 HtmlWebpackPlugin()를 각 html 파일들 경로에 맞게 코딩하여 반복해서 넣어주면 됩니다.

    HandlebarsPlugin(): 핸들바는 간단한 템플릿 언어 입니다. 템플릿과 입력 개체를 사용하여 HTML 또는 기타 텍스트 형식을 생성합니다. 핸들바 템플릿은 핸들바 표현식이 포함된 일반 텍스트처럼 보입니다. webpack에서 plugin을 사용하여 handlebars를 html로 output 합니다.

    Handlebars에 대한 가이드 바로가기

     

     

     

    • 프로젝트 root 레벨에 src 폴더를 만들어 줍니다.
      src 폴더 안에 index.js를 만들어 주고, 하기와 같이 파일 내용을 작성 해줍니다.
      위치는 상관 없으며 webpack.config.js의 entry에서 해당 파일의 위치를 설정해주면 됩니다.
      index.js를 index.bundle.js(output filename로 수정 가능)로 빌드 해주게 되는 것 이며,
      entry를 여러 개의 파일로 설정도 가능합니다.
    require('./assets/styles/index.scss'); //sass 연결
    
    //필요에 따라 js, css는 import, export로 추가해줄 수 있습니다.
    //import "tui-date-picker/dist/tui-date-picker.css";
    
    //해당 path에 있는 svg 파일들을 모두 require 하는 function
    function requireAll(r) {
      r.keys().forEach(r);
    }
    
    requireAll(require.context('./assets/images/svg', true, /\.svg$/));

    간단한 svg-sprite에 대한 원리 설명!

    1. svg 파일들을 모두 require하여 index.js에 들어감

    2. webpack.config.js에서 svg-sprite-loader로 svg 파일들을 sprite로 만들어서 번들되는 js파일에 넣어줌

    3. 모든 페이지에 svg sprite가 자동으로 뿌려지기 때문에,

    아래 코드로 svg를 바로 불러와서 사용할 수 있음,

    이미지명은 svg 파일명을 따라감

    <svg>
      <use xlink:href="#이미지명"></use>
    </svg>

     

     

    • package.json에 script를 추가해줍니다.
      터미널에 npm run build를 입력하면, 이제 webpack을 실행시켜 output 으로 지정해준 폴더에 결과물을 내보내 줄 수 있게됩니다. npm run watch는 dev 모드로 watch를 시켜줄 것이고,
      npm run dev는 webpack dev server를 실행시켜 localhost:9000 (webpack.config.js에서 9000으로 port를 설정해줬음)에서 vscode의 live server extension 과 비슷한 기능으로 실시간 수정된 부분을 바로 반영해줄 수 있게 된다. 
     "scripts": {
        "dev": "webpack-dev-server",
        "watch": "webpack --mode=development --watch",
        "build": "webpack"
      },
    
    
    * 위의 webpack.config.js 에 module.exports 에 있는 mode에 development라고 작성하였는데,
    package.json에서 webpack 실행 문구에 mode까지 함께 기재해주면 module.exports에서 기재하지 않아도 된다.

     

     

    webpack으로 bundle을 해줬을 때 최종적으로 아래와 같은 구조가 될 것입니다.

    'Webpack' 카테고리의 다른 글

    PostCss + Autoprefixer 추가하기  (0) 2022.04.13

    댓글

Designed by Tistory.