[Webpack] Entry

함성준·2021년 7월 5일
0
post-thumbnail

Webpack - Entry

웹팩 도큐먼트 내용을 요약하기 위한 문서입니다.

사전 지식

Dependency Graph

웹팩은 설정에 정의된 엔트리 파일에서 시작해 연결된 이미지, 폰트파일, 자바스크립트, 스타일시트 파일들의 상호 의존성을 파악하여 의존성 그래프를 생성합니다. 생성된 그래프를 통해 하나의 번들 결과파일을 생성하게 되는데 한번에 하나의 리소스만 응답할 수 있는 HTTP 1.1 프로토콜 체제에서 성능상 유리하게 동작하게 됩니다.

Entry

웹팩의 관점에서 엔트리는 의존성 그래프를 생성하기 위한 시작점을 정의하기 위한 개념입니다. 단일 엔트리를 정의하거나 다중 엔트리도 정의할 수 있습니다. 실험삼아 웹팩을 설치하여 엔트리를 하나 작성해보도록 하겠습니다.

const path = require('path')

module.exports = {
    entry: path.resolve(__dirname, 'index.js')
}

위의 설정은 아래의 코드와 동일하게 동작합니다.

const path = require('path')

module.exports = {
    entry: {
        main: path.resolve(__dirname, 'index.js')
    }
}

이 상태로 바로 웹팩을 실행시켜보고 싶은 생각이 드는군요. 바로 한번 해보겠습니다.
dist 라는 폴더에 main.js 파일이 하나 생성되었습니다.

$ webpack && tree -I node_modules
.
├── dist
│   └── main.js
├── index.js
├── package-lock.json
├── package.json
└── webpack.config.js

하지만 하단의 경고가 하나 발생하네요. 확인해보니 mode 필드에 development, production 둘중 하나의 옵션을
작성해야 한다고 합니다.

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

두 종류의 옵션을 각각 부여한 상태로 웹팩을 실행시켜 보았습니다.

# mode: "development"
$ webpack
asset main.js 1.17 KiB [emitted] (name: main)
./index.js 26 bytes [built] [code generated]
webpack 5.39.1 compiled successfully in 50 ms

# mode: "production"
asset main.js 27 bytes [emitted] [minimized] (name: main)
./index.js 26 bytes [built] [code generated]
webpack 5.39.1 compiled successfully in 120 ms

번들링 과정을 거친 main.js 의 용량은 production 과정에서 추가된 minimize 과정을 수행하면서 더 작아졌고 더해진 작업으로 인해 빌드까지의 시간은 더 소요하게 되었네요. 결과 파일의 내부 소스도 모드별로 다른것을 확인할 수 있습니다.

이전에서, 다중 엔트리도 정의할 수 있다고 했었는데요, 엔트리에서 다른 파일과의 연결을 다음처럼 구성했다고 해보겠습니다. 그리고 웹팩을 실행시켜 보도록 해요.

$ tree -I node_modules
.
├── entryOne.js
├── entryTwo.js
├── folderOne
│   ├── moduleA.js
│   └── moduleB.js
└── folderTwo
    ├── moduleC.js
    └── moduleD.js

웹팩 설정 파일은 두개의 엔트리를 두었습니다.

  • entryOnefolderOnemoduleA, moduleB 를 임포트 합니다.
  • entryTwofolderTwomoduleC, moduleD 를 임포트 합니다.
const path = require('path')

module.exports = {
    mode: 'production',
    entry: {
        entryOne: path.resolve(__dirname, 'src/entryOne.js'),
        entryTwo: path.resolve(__dirname, 'src/entryTwo.js')
    }
}

어떻게 될까요 ? development 모드로 실행하면 이렇게 나옵니다.

/*
 * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
 * This devtool is neither made for production nor for readable output files.
 * It uses "eval()" calls to create a separate source file in the browser devtools.
 * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
 * or disable the default devtool with "devtool: false".
 * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
 */
/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ({

/***/ "./src/entryOne.js":
/*!*************************!*\
  !*** ./src/entryOne.js ***!
  \*************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _folderOne_moduleA__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./folderOne/moduleA */ \"./src/folderOne/moduleA.js\");\n/* harmony import */ var _folderOne_moduleB__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./folderOne/moduleB */ \"./src/folderOne/moduleB.js\");\n\n\n\n_folderOne_moduleA__WEBPACK_IMPORTED_MODULE_0__.default.fnA()\n_folderOne_moduleB__WEBPACK_IMPORTED_MODULE_1__.default.fnB()\n\n//# sourceURL=webpack://wp/./src/entryOne.js?");

/***/ }),

/***/ "./src/folderOne/moduleA.js":
/*!**********************************!*\
  !*** ./src/folderOne/moduleA.js ***!
  \**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n    fnA(){\n        console.log('fnA')\n    }\n});\n\n//# sourceURL=webpack://wp/./src/folderOne/moduleA.js?");

/***/ }),

/***/ "./src/folderOne/moduleB.js":
/*!**********************************!*\
  !*** ./src/folderOne/moduleB.js ***!
  \**********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n    fnB(){\n        console.log('fnB')\n    }\n});\n\n//# sourceURL=webpack://wp/./src/folderOne/moduleB.js?");

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 			}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
/******/ 		};
/******/ 	})();
/******/ 	
/************************************************************************/
/******/ 	
/******/ 	// startup
/******/ 	// Load entry module and return exports
/******/ 	// This entry module can't be inlined because the eval devtool is used.
/******/ 	var __webpack_exports__ = __webpack_require__("./src/entryOne.js");
/******/ 	
/******/ })()
;

production 모드로 실행시,

(()=>{"use strict";const n={fnB(){console.log("fnB")}};({fnA(){console.log("fnA")}}).fnA(),n.fnB()})();
  • entryOne 으로 시작한 엔트리는 자신이 임포트한 folderOne 의 파일과 연결하여 독자적인 의존 그래프를 생성했습니다.
  • entryTwo 으로 시작한 엔트리는 자신이 임포트한 folderTwo 의 파일과 연결하여 독자적인 의존 그래프를 생성했습니다.

결과적으로, 다중 엔트리를 두는 것은 의존 그래프를 다중적으로 생성하여 상호 독립적인 프로덕트 번들 파일을 생성할 수 있다는 이야기 입니다.

Entry Option Object

엔트리에 설정할 수 있는 옵션값을 확인해봅시다.

  • dependOn : 특정 엔트리가 로드되기 전에 로드해야할 대상을 의미합니다.

    • 만약 의존하는 모듈을 먼저 로드하지 않을 경우 실행되지 않습니다.
  • filename : 빌드 결과 파일의 이름을 지정합니다. 지정되지 않았을 경우 entry 오브젝트의 키로 파일 이름을 설정합니다.

  • import : 엔트리로 사용되는 파일의 경로를 입력합니다.

  • library : 라이브러리 제작시 사용되는 옵션입니다.

  • runtime : 런타임 청크를 생성하는 옵션입니다.

Additional

0개의 댓글