Link Search Menu Expand Document

Webpack

  • 최신 자바스크립트 자원들을 사용하여 웹 개발을 하다보면 반드시 마주치게 되는 도구가 Webpack이다.

Webpack?

  • At its core, webpack is a static module bundler for modern JavaScript applications.
  • 해석해보면 웹팩은 자바스크립트 모듈 번들러…..
  • 현존하는 모든 브라우저에서 ES2015 표준 모듈시스템을 지원하지 않기 때문에, 이를 웹팩을 통하여 해결할 수 있다.
  • 진입지점으로부터 의존성 트리를 구축하고 이를 기반으로 번들링하여, 단일 파일 형태의 번들결과물을 얻을 수 있다.

설치 및 테스트

  webpack-study
 |- package.json
 |- index.html
 |- /src
   |- index.js

$ npm i -D webpack webpack-cli

  • 위와같은 폴더구조를 형성한 후 webpack과 cli 인터페이스를 설치해준다.
  • webpack 4.0 별도의 config파일이 필수가 아니기 때문에,webpack 명령어를 통해 간단히 번들 결과를 얻을 수 있다.
  • dist/main.js에 번들링 결과가 생성된다.
  • 번들 결과를 살펴보자.
    (() => {
    var e = {
        353: (e) => {
          e.exports = function () {
            console.log("first function excuted");
          };
        },
      },
      r = {};
    function t(o) {
      if (r[o]) return r[o].exports;
      var n = (r[o] = { exports: {} });
      return e[o](n, n.exports, t), n.exports;
    }
    (t.n = (e) => {
      var r = e && e.__esModule ? () => e.default : () => e;
      return t.d(r, { a: r }), r;
    }),
      (t.d = (e, r) => {
        for (var o in r)
          t.o(r, o) &&
            !t.o(e, o) &&
            Object.defineProperty(e, o, { enumerable: !0, get: r[o] });
      }),
      (t.o = (e, r) => Object.prototype.hasOwnProperty.call(e, r)),
      (() => {
        "use strict";
        t(353);
      })();
    })();
    
  • 번들링 결과물은 기본적으로 압축(Minify) / 난독화(Uglify)가 진행되어 읽기 쉽지는 않다. prettier를 사용해서 그나마 이쁘게 포장했다.
  • 읽지 말라고 번들링하는 것이고, 앞으로 개발과정에서 읽을 필요도 없을 것이지만 그럼에도 살펴보자.
  • 특징을 살펴보면 모든 함수들이 즉시실행함수(IIFE) 방식으로 짜여진걸 볼 수 있다.
  • 전체 자바스크립트 모듈들을 하나의 IIFE로 변화하여 스코프 충돌에 대한 이슈 없이 코드를 번들링 할 수 있게된다.

Webpack Config / Core Concepts

  • 위에 언급했듯 4.0 버전 이후 부터는 config파일이 필수가 아니지만, 상세한 설정을 위해서는 사용하는것을 권장하고 있다.

Entry

  • entry는 웹팩이 의존성 그래프를 그려나갈 진입지점이다.
  • entry하나 당, 페이지 하나를 의미하게 된다.
  • 따라서, SPA의 경우에는 단일 진입지점을 지정해주면 된다.
module.exports = {
  entry: {
    main: "./src/main.js",
  },
}
  • dependencies
    module.exports = {
    entry: {
      moment: ["moment"],
      lodash:"lodash",
      main: {
        dependOn: ["moment"],
        import: "./src/main.js",
      },
      index:{
         dependOn: ["moment","lodash"],
        import: "./src/index.js",
      }
    },
    };
    
  <script src="./dist/main.js"></script>
  <script src="./dist/moment.js"></script>
  • 위와 같이 dependOn 기능을 제공하고있다.
  • 번들을 나누는 경우 여러 번들에서 공통으로 사용되는 모듈을 분리 후, 공용으로 사용하는 기능이다.
  • moment는 초기 번들시에는 testapp에 포함되어있지 않고, runtime에 추가되어 사용된다.

Output

module.exports = {
  entry: {
    moment: ["moment"],
    main: {
      dependOn: ["moment"],
      import: "./src/main.js",
    },
  },
  output: {
    filename: "[name].js",
    path: path.resolve("./dist"),
  },
};
  • [name],[id],[contenthash] 등의 키워드를 사용할 수 있다.
  • path 속성에서는 절대경로를 사용하기 때문에, 일반적으로 path모듈을 사용한다.

Loader

  • webpack은 기본적으로 js와 json만 이해할 수 있다.
  • 따라서,Loader는 다른 형식의 파일들을 module의 형태로 인식하여, webpack의 의존성 그래프에 추가 및 app에서 사용가능하게 한다.
  • https://webpack.js.org/contribute/writing-a-loader/
  • loader를 만드는 가이드라인은 웹팩 홈페이지에 자세히 설명되어있다.
  • 가장 간단한 로더 가이드라인은 one parameter를 받아서 변환된 값을 return하는 모듈을 작성하는 것이다.
module.exports = function myloader(content) {
  console.log("myloader가 동작함")
  return content.replace("console.log(", "alert(")
}
  • loader를 사용할 때에는 module객체의 rules에 추가하면된다.(inline이나 cli에서 사용하는 방법도 있지만 자주 사용되지는 않는 것 같다.)
    module.exports = {
    module: {
      rules: [{ test: /\.txt$/, use: 'raw-loader' }],
    },
    };
    
  • test에는 로딩할 파일을 지정할 수 있고, use에는 적용시킬 로더를 설정하면 된다.

Plugins

  • loader는 번들링 과정의 모듈 변환에 사용된다면, plugin은 번들 최적화 등 번들 결과물에 관하여 조금 더 광범위한 작업을 수행한다.
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins

module.exports = {
  module: {
    rules: [{ test: /\.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
  • require 를 통해 플러그인을 불러온 후, new 키워드를 통해 플러그인에 넣어주면 된다.
class HelloWorldPlugin {
  apply(compiler) {
    compiler.hooks.done.tap('Hello World Plugin', (
      stats /* stats is passed as an argument when done hook is tapped.  */
    ) => {
      console.log('Hello World!');
    });
  }
}

module.exports = HelloWorldPlugin;
  • new 키워드를 사용하는 것을 보면 알 수 있듯이 pluginclass 형태로 정의한다.
  • 모듈이 파일 하나 혹은 여러 개에 대해 동작하는 반면 플러그인은 하나로 번들링된 결과물을 대상으로 동작 한다.라는 글을 봤는데, output을 여러개로 설정 후 번들링 해봐도 동작은 단 한번만 수행한다.
  • plugin

Mode

  • Mode객체는 webpack에 사전 설정된 built-in 최적화 설정들을 사용하기 위해 사용한다.
  • string = 'production': 'none' | 'development' | 'production'
  • DefinePlugin을 사용한다면 process.env.NODEENV에 설정한 Mode값이 들어가게 된다.
  • 설정하지 않으면 production으로 자동 설정해준다.

    Browser Compatibility

  • 작성중

    Babel

참고자료

  • https://velog.io/@sdong001/Webpack-%EC%9D%B4%EA%B2%83%EB%A7%8C%EC%9D%80-%EC%95%8C%EA%B3%A0-%EA%B0%80%EC%9E%90