프론트엔드 개발 환경 공부 #4 엔트리/아웃풋

jakeseo_me·2021년 9월 14일
0

웹팩에서 엔트리와 아웃풋이란?

기본적으로 웹팩은 개발자가 작성한 파일들을 번들링한다. 번들링이란, 내가 작성한 모든 파일을 1개의 자바스크립트 파일로 합치는 행위를 말한다.

파일을 합칠 때는 파일을 합치는 시작점이 되는 파일이 필요하고 이러한 파일을 시작점 혹은 엔트리 포인트(Entry point)라고 한다.

이전의 예제로 보면, app.js 파일이 엔트리 포인트가 될 수 있고, math.js 파일은 app.js가 사용하던 모듈로 인식되어 번들링 후에는 app.js 파일에 합쳐지게 될 것이다.

번들링 후에 탄생한 파일은 아웃풋(output)이라고 한다.

대략 위와 같이 그림을 그려볼 수 있다.

웹팩 사이트에서 이미지를 보면, 왼쪽을 Modules with dependencies라고 한다. 모듈은 또 다른 모듈을 의존하여 실제 구조는 상당히 복잡한데, 이것을 번들링하여 보통 하나의 js로 만들어준다.

그림에서는 맨 왼쪽 최상단에 있는 .js가 엔트리 포인트일 것이다.

프로젝트에 웹팩 설치해보기

    "dependencies": {
        "prettier": "^2.4.0",
        "webpack": "^4.41.5",
        "webpack-cli": "^3.3.10"
    }

실습을 웹팩 4버전으로 할 거라, 직접 package.json에 위와 같이 설치할 webpackwebpack-cli 버전을 입력했다.

웹팩의 옵션 알아보기

webpack-cli --help 명령 실행해보기

아래 두가지 명령어 중 하나로 webpack-cli --help 명령어를 실행해볼 수 있다.

  • node_modules/.bin/webpack --help
  • npx webpack-cli --help

node_modules/.bin 밑에 해당 명령어가 존재한다는 것도 알 수 있고, npx라는 명령어로 해당 위치를 찾아갈 필요 없이 cli를 쉽게 호출할 수 있다는 것도 알 수 있다.

npx가 무엇인지 궁금하다면 npx란 무엇일까? 링크를 참조해보자.
간략히 설명하자면, 패키지 중에는 실행을 위한 패키지와 이용을 위한 패키지가 있다. 실행을 위한 패키지의 경우 이전에는 global 옵션을 이용해서 설치했는데, 전역에서 이 패키지 저 패키지 설치하다보니 꼬이는 일이 부지기수였다. 그에 대한 해결책으로 나온 것이 npx이다.

먼저 패키지가 설치되어 있는지 확인하고 없다면 설치하고 실행하는 간단한 구조이다.

--help 명령어를 입력하면 위의 사진처럼 webpack-cli의 다양한 명령어를 구경할 수 있다.

명령어 살펴보기

--mode: 환경에 따라 development, production, none 중 하나를 고를 수 있다.
--entry: 이전에 말했던 엔트리 포인트를 지정할 수 있다.
--output: 결과물이 위치할 경로를 지정할 수 있다.

webpack으로 app_amd.js 번들링해보기

app_amd.js

이전에 모듈 방법에 대해 배울 때 AMD 방식으로 모듈을 이용한 app_amd.js가 있었다.

import * as math from "./math_amd.js";

console.log("1+2 = ", math.sum(1, 2));

math_amd.js

export function sum(a, b) {
    return a + b;
}

번들링 명령어 입력해보기

npx webpack-cli --mode development --entry ./src/app_amd.js --output ./dist/app.js

위에서 배운 옵션 3가지 --mode, --entry, --output을 이용하여 번들링해보았다.

위와 같은 화면이 뜨면서 번들링이 된다.

결과물 확인해보기

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./src/app_amd.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./src/app_amd.js":
/*!************************!*\
  !*** ./src/app_amd.js ***!
  \************************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _math_amd_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./math_amd.js */ \"./src/math_amd.js\");\n\r\n\r\nconsole.log(\"1+2 = \", _math_amd_js__WEBPACK_IMPORTED_MODULE_0__[\"sum\"](1, 2));\r\n\n\n//# sourceURL=webpack:///./src/app_amd.js?");

/***/ }),

/***/ "./src/math_amd.js":
/*!*************************!*\
  !*** ./src/math_amd.js ***!
  \*************************/
/*! exports provided: sum */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"sum\", function() { return sum; });\nfunction sum(a, b) {\r\n    return a + b;\r\n}\r\n\n\n//# sourceURL=webpack:///./src/math_amd.js?");

/***/ })

/******/ });

알수없는 괴물같은 js가 나타났다.

node 명령어로 결과물 실행해보기

결과가 잘 나온다.

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.0" />
        <title>테스트용</title>
    </head>
    <body>
        콘솔을 확인해봅시다.
        <script src="dist/app.js"></script>
    </body>
</html>

이제 type="module" 옵션은 필요 없다.

브라우저에서도 결과물을 잘 보여준다.

웹팩 설정파일 만들어보기

기존에는

npx webpack-cli --mode development --entry ./src/app_amd.js --output ./dist/app.js

위와 같이 긴 명령어를 이용해서 번들링을 해보았는데, 이렇게 긴 명령어를 치는 것도 귀찮고, 실수하기도 쉬우니 무언가 설정파일을 만들어서 자동화해보자.

--help 명령어에서 힌트 얻어보기

기본: webpack.config.js or webpackfile.js라고 되어있는 것을 볼 수 있다. 우리는 이 중 webpack.config.js 파일을 만들어보자.

webpack.config.js 작성하기

// node.js의 CommonJS 를 사용한 모듈화
const path = require("path");

module.exports = {
    mode: "development",
    entry: {
        main: "./src/app_amd.js",
    },
    output: {
        path: path.resolve("./dist"),
        // output 이름을 동적으로 나타낼 수 있는 효과가 있다.
        // entry는 하나가 아니라 여러 개일 수도 있어서,
        // entry가 여러 개라면 output도 여러 개다.
        filename: "[name].js",
    },
};

node js의 path 모듈을 사용하면 webpack.config.js 작성하기가 한결 쉬워서 path 모듈을 가져왔다.

module.exports는 이전에 배웠듯 nodejs가 공식으로 지원하는 CommonJS에서 사용하는 모듈화 방법이다.

이전에 --mode, --entry, --output으로 작성하던 부분을 json으로 나타내주었다.

  • path: path.resolve()는 경로를 상대경로로 편리하게 나타내기 위함이다.
  • filename: "[name].js"는 이름을 동적으로 설정한다는 뜻이다.
    • 위에서 입력한 main의 이름을 그대로 쓰게 만들 것이다. main.js가 그대로 나온다. 이렇게 하는 이유는 entry point가 여러 개 일 때 이름이 겹치지 않고 동적으로 잘 나타나게 하기 위해서이다.

package.json 에 명령어 등록하기

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
    }

위와 같이 "build": "webpack" 처럼 등록하면 npm run build를 입력했을 때 실행이 될 것이다.

웹팩을 실행하고 node명령어로 실행도 해보았다.

profile
대전에서 풀스택 웹개발자로 일하고 있는 Jake Seo입니다. 주로 Jake Seo라는 닉네임을 많이 씁니다. 프론트엔드: Javascript, React, Vue 백엔드: Spring Framework에 관심이 있습니다.

0개의 댓글