본문으로 바로가기

Webpack Guide for beginner #2

category Web Tech/Webpack 2019. 11. 19. 10:44

Webpack 환경 설정 맛보기

앞서 Webpack의 전반적 이해와 Webpack 사용에 필요한 선수 지식에 대해 알아보았으며, 이번 장부터는 Webpack에 대한 기본 환경 구성부터 진행해 보도록 하겠습니다.

 

사용자 코드작성과 번들 js

 

 

프로젝트 초기 설정

이제부터 새로운 프로젝트를 초기화하고, Webpack 을 설치해 보도록 하겠습니다.

아직까지 node.js 설치를 하지 않았다면 설치 후에 진행 바랍니다.

Webpack 기본(일반적) 구성 절차

  1. webpackwebpack-cli 전역 설치
  2. npm init 으로 package.json 생성
  3. src/index.jsindex.html 생성
  4. 사용자 js 와 html 추가
  5. webapck.config.js 파일 생성

webpack, webpack-cli-global 로 설치한 후 package.json 을 생성해도 되고 package.json 을 생성한 후 webpack 을 설치해도 무방합니다.

 

우선 로컬 디렉토리 내의 본인의 새로운 프로젝트 폴더를 생성하고, 몇 가지 파일을 생성해 보도록 합니다.

$ mkdir webpack-task
$ cd webpack-task
$ npm init -y

CLI 명령어를 이용하여 디렉토리를 구성해도 되고 편한대로 새로운 프로젝트 네이밍으로 폴더를 구성한 후 npm init -y 를 진행해도 됩니다.

 

다음과 같이 아래 명령어를 수행합니다.

$ npm i webpack webpack-cli -global
$ npm i webpack webpack-cli --save-dev 

webpack은 웹팩의 핵심 패키지로 Webpack v3까지는 webpack만 설치하였으나 Webpack v4부터는 webpack-cli 도 같이 설치해야 합니다. webpack-cli는 터미널에서 webpack 커맨드를 실행할 수 있게 해주는 커맨드라인 도구이며, 두 개의 패키지 모두 개발할 때만 필요한 의존성이므로 --save-dev 로 설치하도록 합니다.

그리고 webpack 설치는 webpack.config.js 파일에서 webpack 모듈을 불러다 사용하기 위함도 있습니다.

로컬 설치를 진행하면 node_modules 폴더가 생성되면서 하위 폴더에 다수의 다수 모듈들이 설치되어 있을 것입니다.

 

바로 위에서 수행했던 명령어는 아래와 같이 수행할 수도 있습니다.

$ npm i -g webpack webpack-cli && npm i -D webpack webpack-cli
$ npm i webpack webpack-cli -g && npm i webpack webpack-cli -D

옵션 플래그인   -global(-g), --save-dev(-D) 는 install 바로 뒤에 타이핑해도 되고 마지막 패키지명 뒤에 입력하실 수 있습니다.

 

설치된 패키지를 확인하기 위해 package.json을 살펴보면 다음과 같습니다.

{
  "name": "webpack-task",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.35.3",
    "webpack-cli": "^3.3.5"
  }
}

webpack, webpack-cli는 실제 서비스에 배포되는 것이 아니라 개발에 필요한 도구일 뿐이기 때문에 --save-dev로 설치하면 devDependencies에 그 내용이 추가된 것을 확인하실 수 있습니다.

 

다음으로 간단한 index.html, index.js 그리고 webpack.config.js 파일을 생성하고 다음과 같이 작성합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>Webpack Task</title>
</head>
<body>
	<header>
		<h1>Webpack 학습하기</h1>
	</header>
	<div>
		<p>
			사실 웹팩 설정은 복잡하기로 악명 높지만 다양한 업무를 처리해 줄 수 있는 장점과
            계속해서 빠르고 쉽게(?) 개선되고 있습니다.
		</p>
	</div>
	<script src="dist/bundle.js"></script>
</body>
</html>
// index.js
console.log('Webpack 번들링 실행');
// webpack.config.js
// webpack 명령은 기본적으로 이 설정으로 시작
const path = require('path');

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    mode : 'development'
};

 

지금까지 폴더구성은 다음과 같습니다.

webpack=task
|---index.html
|---package-lock.json
|---package.json
|---webpack.config.js
|
\---node_modules
|     \-- 생략
|
\---src
     \--js
         \--index.js

 

webpack.config.js 구성파일을 알아보기 전에 아래 명령어를 먼저 실행해 보겠습니다.

$ webpack

위 명령어를 실행하면 dist/bundle.js 가 생성되는 것을 확인하실 수 있습니다.

 

그리고 번들링된 bundle.js 확인해 보면 다음과 같이 webpack 관련 코드와 하단에 index.js에서 작성했던 콘솔 코드를 확인할 수 있습니다.

/***/ "./src/js/index.js":
/*!*************************!*\
  !*** ./src/js/index.js ***!
  \*************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("console.log('Webpack 번들링 실행');\n\n//# sourceURL=webpack:///./src/js/index.js?");

/***/ })

실제 작업파일은 index.js이지만 서비스(배포)시에는 번들링된 자원을 사용할 것이기 때문에 index.htmlbundle.js를 불러와 사용해야 합니다.

 

이번에는 여전히 많이 사용하고 있는 jQuery라는 라이브러리를 불러다가 사용해 보는 예제를 진행해 보겠습니다.

앞서 진행한 것처럼 맛보기(?)이지만 이해를 하는데 도움이 되실 수 있습니다.

아래와 같이 jQuery 를 설치하고 index.js를 수정해 보도록 합니다.

$ npm i jquery --save
// index.js
console.log('Webpack 번들링 실행');

// require 는 NodeJS 에서 사용되고 있는 CommonJS 키워드이고,
// import 는 ES6(ES2015)에서 새롭게 도입된 키워드로
// 두 개의 키워드 모두 하나의 파일에서 다른 파일의 코드를 불러온다는 동일한 목적을 가지고 있음
import $ from 'jQuery';

(function () {

    $(document).ready(function() {
        $('p').text('jQuery 를 불러와 사용하고 있습니다.')
    });

})();

import $ from 'jQuery';는 node_modules 에 있는 jQuery를 불러와 $로 치환한다는 의미입니다.

다시 CLI 에서 webpack 명령어를 수행하면 index.html을 확인해 보면 문단 텍스트가 바뀌어 있는 것을 확인하실 수 있을 것입니다.

그리고 bundle.js에는 jquery와 사용자 스크립트가 함께 합쳐져 있을 것입니다.

 

ES6 Import/Export

ES6는 다른 프로그래밍 언어처럼 하나의 자바스크립트 모듈에서 다른 자바스크립트 모듈을 불러다 사용할 수 있도록 importexport와 키워드를 제공합니다.

 

npm install 시 특정버전 설치하기

$ npm i jquery@2.1.4 --save
# 특정버전을 설치하고자 하는 경우

$ npm i jquery@1 --save
# 1 버전대 중에 최신 버전을 설치하는 경우

 

 

 

 

webpack.config.js (웹팩 구성 파일)

이제부터 webpack 의 핵심 개념을 이해하기 위해서 구성 파일의 주요 속성인 Entry, Output, Loader, Plugins, mode 에 대해 알아보면서, 필요한 예제도 함께 진행해 보도록 하겠습니다.

 

entry 설정

번들을 설정하기 위한 진입점을 의미합니다.

다시말해, entry 속성은 웹팩에서 웹 자원을 변환하기 위해 필요한 최초 진입점이자 자바스크립트 파일 경로입니다.

  • String : 문자열이 들어오는 경우 시작시 로드되는 모듈로 해석
  • Array : 시작시 모든 모듈이 로드됩니다. 마지막 하나가 내보내집니다.
  • Object : 다중 항목 번들이 작성됩니다.

    key는 청크되는 파일의 이름이고, 값은 문자열 또는 배열이 가능합니다.

 

여러가지 entry 유형 살펴보기

다음 코드는 문자열(String)을 작성하는 경우입니다.

// webpack.config.js
module.exports = {
    entry: './src/myfolder/file.js'
};

위 코드는 웹팩을 실행했을 때 src/myfolder 폴더 밑의 file.js을 대상으로 웹팩이 빌드를 수행하는 코드입니다

다음 코드는 아래와 같이 작성할 수도 있습니다.

// webpack.config.js
module.exports = {
    entry: {
        main: './src/myfolder/file.js'
    }
};

다음 코드는 배열(Array)이 사용되는 경우입니다.

module.exports = {
    entry: {
        main: ['./src/myfolder/file_01.js', './src/myfolder/file_02.js']
    }
};

배열을 전달하면 multi-main entry가 생성됩니다.
여러개의 의존성 파일을 하나의 chunk로 모으고 이들의 의존성 그래프를 생성하고 싶을때 유용하게 사용할 수 있지만 이것은 (라이브러리 같은) 하나의 엔트리 포인트를 갖는 어플리케이션 혹은 툴을 빠르게 설정할때 좋은 선택이지만, 확장성이 떨어집니다.

 

Entry 파일에는 어떤 내용이 들어가야 하나?

entry 속성에 지정된 파일에는 웹 애플리케이션의 전반적인 구조와 내용이 담겨져 있어야 합니다. 웹팩이 해당 파일을 가지고 웹 애플리케이션에서 사용되는 모듈들의 연관 관계를 이해하고 분석하기 때문에 애플리케이션을 동작시킬 수 있는 내용들이 담겨져 있어야 합니다.

예를 들어, 블로그 서비스를 웹팩으로 빌드한다고 했을 때 코드의 모양은 아래와 같을 수 있습니다.

js
// index.js
import LoginView from './loginView.js';
import UI from './ui.js';
import Posting from './posting.js';

function initApp() {
  loginView.init();
  UI.init();
  Posting.init();
}

initApp();

위 코드는 해당 서비스가 싱글 페이지 애플리케이션(SPA)이라고 가정하고 작성한 코드입니다. 사용자의 로그인 화면, 로그인 후 진입하는 메인 화면, 그리고 게시글을 작성하는 화면 등 웹 서비스에 필요한 화면들이 모두 index.js 파일에서 불려져 사용되고 있기 때문에 웹팩을 실행하면 해당 파일들의 내용까지 해석하여 파일을 빌드해줄 것입니다.

위와 같이 모듈 간의 의존 관계가 생기는 구조를 디펜던시 그래프(Dependency Graph)라고 합니다.

 

앞에서 살펴본 것처럼 엔트리 포인트는 1개가 될 수도 있지만 아래와 같이 여러 개가 될 수도 있습니다.

entry: {
  login: './src/loginView.js',
  main: './src/mainView.js'
}

위와 같이 엔트리 포인트를 분리하는 경우는 싱글 페이지 애플리케이션이 아닌 특정 페이지로 진입했을 때 서버에서 해당 정보를 내려주는 형태의 멀티 페이지 애플리케이션에 적합합니다.

 

웹팩 구성 파일인 webpack.config.js 해당 네이밍으로 정의해야 웹팩이 인식합니다.

네이밍을 다르게 설정하고 싶을 경우 예를 들어 빌드용으로 사용하는 경우 webpack.config.prod.js라고 네이밍을 정의한다면 명령 프롬프트에서 실행할 때 webpack --config webpack.config.prod.js으로 실행해야 합니다. 이는 이후에 다시 다루도록 하겠습니다.

 

output 설정

 여기서 entry와 연계하여 output을 살펴보도록 하겠습니다.

output은 결과물을 내는 설정으로 생성한 번들을 저장할 위치를 지정할 수 있습니다.

즉, output은 웹팩이 어디에 번들을 만들어 낼것인지, 어떤 이름으로 파일들을 어떻게 만들 것인지에 대한 것을 정의할 수 있습니다.

config 파일에 output이 설정되어 있지 않다면 기본 값은 ./dist/main.js입니다. 생성된 번들 파일들이 ./dist 디렉토리 밑으로 들어가게 됩니다.

다음의 코드는 기본 엔트리 포인트output을 설정한 것 입니다.

module.exports = {
    // 웹팩 v4부터는 mode 필수
    // mode 는 production, development, none 3가지 옵션이 존재
    // mode 의 production 은 각 설정마다 내장된 최적화 옵션을 자동으로 설정하여 준다
    mode : 'development',

    entry : './src/js/index.js',
    output: {
        // filename 으로 생성된 번들링을 어느 경로에 생성할 지를 설정
        // __dirname 은 node 에서 제공하는 node 파일의 경로를 담고 있는 변수
        // __이 붙어 있는 변수들은 항상 무엇인가를 담고있는 특별한 변수들임
        // path 에는 절대 경로 설정(절대값으로 static(정적)으로 사용)
        path: __dirname,
        // bundling 된 결과 파일의 이름
        filename: 'dist/biuld.js'
    }
};

최소한 filename은 지정해줘야 하며 일반적으로 위와 같이 path 속성을 함께 정의합니다.

여기서 filename 속성은 웹팩으로 빌드한 파일의 이름을 의미하고, path 속성은 해당 파일의 경로를 의미합니다. 그리고 path 속성에서 사용된 path.resolve() 코드는 인자로 넘어온 경로들을 조합하여 유효한 파일 경로를 만들어주는 Node.js API입니다.

 

위 코드에서 사용한 path 라이브러리의 자세한 사용법은 여기를 참고하세요.

 

앞서 위에서 엔트리 포인트를 배열로 구성했듯이 객체로도 구성할 수 있습니다.

먼저, module1.js, module2.js 파일 생성 후 아래와 같다고 가정해 봅니다.

// module1.js
console.log('module1 실행');
// module2.js
console.log('module2 실행');

 

Multi Entry & output

다음의 코드는 다중 엔트리 포인트와 그에 따른 output 설정입니다.

module.exports = {
    module.exports = {
    mode : 'development', // 웹팩4부터는 mode(development||production)는 필수
    entry: {
        jaehee : './src/js/index.js',
        'module.chunk' : ['./src/js/module1.js', './src/js/module2.js'] // 배열 사용(오른쪽부터 왼쪽으로 읽어감)
    },
    output: {
        path : __dirname,
        filename : 'dist/[name].js' // 위에 지정한 entry 키의 이름에 맵핑되어 파일이 생성됨
    }
};

webpack 을 실행하면 dist 폴더 내에 jaehee.js, module.chunk.js 이 생성되어 있는 것을 확인하실 수 있습니다.

 

Output Name Options

앞에서 살펴본 filename 속성에 여러 가지 옵션을 넣을 수 있습니다.

결과 파일 이름에 entry 속성을 포함하는 옵션

output : {
    // 정적인 절대값으로 이름을 구성
    filename : '[name].js'
}

 

결과 파일 이름에 웹팩 내부적으로 사용하는 모듈 ID를 포함하는 옵션

output : {
    filename : '[id].bundle.js'
}

 

매 빌드시 마다 고유 해시 값을 붙이는 옵션

output : {
    // webpack 을 build 할 때마다 hash 값이 변하면서 output 파일이 계속 변경 생성
    filename : '[name].[hash].bundle.js'
}

 

웹팩의 각 모듈 내용을 기준으로 생생된 해시 값을 붙이는 옵션

output : {
    // chunk(덩어리)에 따라서  hash 값이 변하면서 output 파일이 계속 변경 생성
    filename : '[chunkhash].bundle.js'
}

 

 

 

Loader 설정

webpack 은 모든 파일을 모듈로 관리할 수 있다고 언급했습니다.
하지만 webpack 은 자바스크립트 파일만 읽어 올 수 있기 때문에, css(스타일시트)나 이미지 등을 webpack 이 읽을 수 있는 자바스크립트로 변경되어야 하는데, Loaderwebpack이 이해 할 수 있는 모듈로 변경해 주는 역할을 하게 됩니다.

즉, 로더(Loader)는 웹팩이 웹 애플리케이션을 해석할 때 자바스크립트 파일이 아닌 웹 자원(HTML, CSS, Images, 폰트 등)들을 변환할 수 있도록 도와주는 속성입니다.  이런 점에서 로더는 다른 빌드 툴들의 "tasks"와 유사하며, Typescript 같은 다른 언어를 자바스크립트로 변경하거나 인라인 이미지를 data URL 로 변경할 수도 있습니다. 심지어 로더는 CSS 파일을 자바스크립트 모듈에서 직접 import 할 수 있는 방법도 제공하고 있습니다.

그리고 일반적으로 웹팩을 사용하면 주로 babel 을 함께 사용하는 경우가 많은데, ES2015(ES6+) 이상의 문법을 IE 같은 구형 브라우저와 호환시키기 위해 사용하기도 하고, jsx 같은 react 문법을 컴파일하기 위해 사용하기도 합니다.

 

기본 사용은 다음과 같이 작성합니다.

// webpack.config.js
module.exports = {
  module: {
    rules: []
  }
}

엔트리나 아웃풋 속성과는 다르게 module라는 이름을 사용합니다

 

Loader 가 필요한 이유

웹팩으로 애플리케이션을 빌드할 때 만약 아래와 같은 코드가 있다고 가정해 보겠습니다.

// app.js
import './common.css';

console.log('css loaded');
/* common.css */
p {
  color: blue;
}
// webpack.config.js
module.exports = {
  entry: './app.js',
  output: {
    filename: 'bundle.js'
  }
}

위 파일을 웹팩으로 빌드하게 되면 아래와 같은 에러가 발생합니다.


 

CSS Loader 적용하기

여기서는 간단히 로더를 사용하여 css 파일을 로드하는 방법에 대해 알아보겠습니다.

다음과 같이 필요한 로더를 설치하도록 합니다.

$ npm i -D css-loader style-loader

 

로더들을 설치한 후 다음과 같이 파일 생성 및 작성해 봅니다.

html
<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>Webpack Task</title>
</head>
<body>
	<header>
		<h1>Webpack 학습하기</h1>
	</header>
	<div>
		<p>
			사실 웹팩 설정은 복잡하기로 악명 높지만 다양한 업무를 처리해 줄 수 있는 장점과
            계속해서 빠르고 쉽게(?) 개선되고 있습니다.
		</p>
	</div>
	<script src="dist/jaehee.js"></script>
	<script src="dist/module.chunk.js"></script>
</body>
</html>

앞서 번들링한 것을 확인해 보고 싶다면 module.chunk.js 도 import(선택사항)하면 됩니다.

 

css 를 불러오기 위해 index.js 파일에서 마치 JS 파일을 임포트하듯이 CSS 파일을 임포트 합니다. 아래와 같이 js 파일에서 import 하도록 합니다.

// index.js
import '../css/base.css'

console.log('Webpack 번들링 실행');

 

src/css/base.css 파일 생성 후 아래와 같이 간단히 css를 작성해 봅니다.

@charset "UTF-8";
body {
	color: red;
}

 

기존 webpack.config.js에 아래와 같이 추가하도록 합니다.

module.exports = {
    mode : 'development', // 웹팩4부터는 mode(development||production)는 필수
    entry: {
        jaehee : './src/js/index.js',
        'module.chunk' : ['./src/js/module1.js', './src/js/module2.js'] // 배열 사용
    },
    output: {
        path : __dirname,
        filename : 'dist/[name].js' // 위에 지정한 entry 키의 이름에 맵핑되어 파일이 생성됨
    },
    // 로더를 지정하기 위한 module 정의
    module: {
        rules: [ //module.rules 를 사용해 여러개의 로더 지정이 가능.
            {
                // test : 변환 할 파일을 지정
                // 정규 표현식으로 문자열 .css 확장자로 끝나는 것을 찾음.
                test: /\.css$/,
                // use : 해당 파일에 적용할 로더의 이름
                // 로더에서 모듈 로딩 순서는 배열의 요소 오른쪽에서 왼쪽으로 로딩하며 진행
                use: ['style-loader', 'css-loader']
            }
        ]
    }
};

위와 같이 구성하신 후 CLI에서 webpack을 실행한 후 index.html을 브라우저에서 확인하면 글자색이 빨간색으로 변경된 것을 확인하실 수 있을 것입니다.

 

module.rules 설정

webpack.config.jsmodule을 살펴보겠습니다.

module.rules 를 사용해 여러 개의 로더 지정이 가능하며, 이는 로더를 표시하는 방법으로 코드를 간결하고 깔끔하게 유지하는데 도움이 됩니다.

module.rule 내부에  test는 변환 할 파일을 지정하고,  use는 변환 할 파일에 지정할 로더를 설정합니다.

그리고 use 주석에도 설명해 놓았듯이 로더는 오른쪽에서 왼쪽으로 평가,실행되며, 위의 예시 코드에서는 css-loader를 거쳐 style-loader로 진행됨을 의미합니다.

다시 전체적으로 분석해 보자면, .css 확장자를 가진 모든 css 파일에 대해서 css-loader 를 통해 자바스크립트 파일로 번들링을 하고 style-loader 로 html 에 internal style 로 넣어주게 되는입니다.

그래서 index.html을 브라우저 개발자 도구의 소스보기에서 확인해 보면 아래와 같이 내부 스타일이 들어가 있는 것을 확인할 수 있습니다.

 

# 자주 사용되는 로더 종류

앞에서 살펴본 CSS 로더 이외에도 실제 서비스를 만들 때 자주 사용되는 로더의 종류는 다음과 같습니다.

 

# 로더를 여러 개 사용하는 경우

로더를 여러 개 사용하는 경우에는 아래와 같이 rules 배열에 로더 옵션을 추가해주면 됩니다.

module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.vue$/, use: 'vue-loader' },
      // ...
    ]
  }
}

위에서 사용해본 css를 번들링하여 사용한 방법은 실무에서 흔히 사용하는 방법이 아닐 것입니다.

일반적으로 css 파일을 내부 스타일로 작성하기 보다 개별 css 파일을 import 하여 사용하는 것이 일반적입니다.

그렇다면 위와 같이 cssjaehee.js에 번들링 하지 않고, 빌드시에 별도의 .css 파일로 분리하여 import 해야 하는데 이때 이용할 수 있는 것이 plugins 입니다.   아래에서 Plugins에 대해 알아보겠습니다.

 

 

Plugin 설정

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

즉, Loader 는 모듈을 처리하지만, Plugin 은 번들링된 파일을 처리한다는 점에 차이점이 있습니다.

Plugin 은 번들된 파일을 난독화, 압축할 수도 있고 핫리로딩, 파일복사, 파일추출, 별칭사용 등의 부가적인 작업을 할 수 있습니다.

즉, 플러그인은 파일별 커스텀 기능을 사용하기 위해서 사용하는 것입니다.

플러그인 사용 방법은 인자와 옵션을 사용할 수 있고, plugins 속성에 new 인스턴스를 전달해야 합니다.

그리고 웹팩을 어떻게 사용하느냐에 따라 플러그인 사용법은 여러가지가 될 수 있습니다.

플러그인은 기본적으로 다음과 같이 선언합니다.

// webpack.config.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode : '',
    entry : {},
    output : {},
    module : {},
    plugins : [
        new HtmlWebpackPlugin(),
        new webpack.ProgressPlugin(),
        new webpack.optimize.UglifyJsPlugin()
        // ...
    ]
}

위와 같이 플러그인의 배열에는 생성자 함수로 생성한 객체 인스턴스만 추가될 수 있습니다.

 

위의 두 플러그인은 각각 아래와 같은 역할을 합니다.

  • HtmlWebpackPlugin : 웹팩으로 빌드한 결과물로 HTML 파일을 생성해주는 플러그인
  • ProgressPlugin : 웹팩의 빌드 진행율을 표시해주는 플러그인

 

 

컴파일된 CSS를 별도의 CSS 파일로 분리하는 방법

앞선 예제코드에서 로더를 사용하여 css(내부스타일)를 DOM에 주입하였다면 예제 코드를 수정하여 css 파일을 추출해 보는 방법을 진행해 봅니다.

먼저 css 파일을 추출하기 위한 플러그인을 설치하도록 합니다.

$ npm i --save-dev mini-css-extract-plugin

 

Webpack v3 까지는 extract-text-webpack-plugin을 사용했었으나 Webpack v4부터 css와 관련된 파일 분리는 mini-css-extract-plugin(Webpack 공식사이트)을 사용하도록 변경되었습니다.

 

 

설치가 끝났다면 기존 webpack.config.jsindex.html을 아래와 같이 수정하도록 합니다.

// webpack.config.js
const path = require( 'path' ); // 경로를 설정
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // node_modules 에서 불러옴

module.exports = {
    mode : 'development',
    entry: {
        jaehee : './src/js/index.js'
    },
    output: {
        path : path.resolve(__dirname, 'dist'),
        filename : '[name].js'
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                // MiniCssExtractPlugin 사용
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ],
                // exclude 는 제외할 폴더나 파일
                // 다른 모듈을 사용해서 컴파일하지 않도록 지정(안전성 확보)
                exclude: /node_modules/
            }
        ]
    },
    // 플러그인 설정
    plugins: [
        // 컴파일 + 번들링 CSS 파일이 저장될 경로와 이름 지정
        new MiniCssExtractPlugin({ filename: 'css/style.css' })
    ]
};

지금까지 outputpath에서 __dirname 을 사용했으나 앞으로는 nodeJS 에서 제공하는 path라는 모듈을 활용하도록 하겠습니다.

 

여기서 잠깐

  • path.join(path1, path2…)

    파라미터로 전달받은 경로를 이어서 하나의 경로로 만듭니다 :

path.join('/foo', 'bar', 'baz/asdf');
// Returns : 'foo/bar/baz/asdf'

 

  • path.resolve([from…], to)

    전달받은 경로의 절대 경로를 리턴합니다 :

path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
// 만약에 현재 디릭토리가 /home/myself/node 라고 가정한다면
// 리턴되는 값은 다음과 같이 유효하지 않은 값들을 가공하여 나오게 됩니다.
// '/home/myself/node/wwwroot/static_files/gif/image.gif'

 

path.join()은 자바스크립트의 내장 API 에 있는 join 과 비슷한 역할을 하지만 해당 API 가 동작하는 OS 의 파일 구분자를 이용하여 파일 위치를 조합하기 때문에 OS 별로 결과값이 다를 수 있습니다.

path.resolve()는 모듈을 해석하는데 있어 영향을 미치는 옵션으로 웹팩이 스스로 판단하여 경로나 확장자를 처리할 수 있게 도와주는 옵션입니다.

앞서 본 join() 같은 경우는 그냥 문자열을 합치는 거지만, resolve는 오른쪽에서 왼쪽을 파일 위치를 구성해 가며 유효한 위치를 찾습니다. 만약, 결과 값이 유효하지 않으면 현재 디렉토리가 사용되며 반환되는 위치 값은 항상 절대 경로(absolute URL)입니다.

resolve 를 사용하는 이유가 웹팩 번들링을 할 때 기타 복잡한 다수의 loader 가 있을 경우 복잡함으로 인해 유효하지 않은 위치가 있다면 자동으로 제거해주고 검증이 된 폴더 위치를 잡아주는 것이 resolve 의 특성이기 때문에 좀 더 안전한 번들링을 위해서 사용하는 측면이 있습니다.

 

상단에서 require( 'path' )path 모듈을 불러오고 output에서 path.resolve(__dirname, 'dist') 로 경로를 지정하였으며, test 를 통해 load 할 파일을 지정하고[ MiniCssExtractPlugin.loader, 'css-loader'] 를 통해 오른쪽부터 왼쪽으로 수행하도록 설정했습니다.

그리고 exclude: /node_modules/ 로 제외할 폴더를 정의할 수 있으며, 여기서는 MiniCssExtractPlugin.loader, css-loader 이외의 기타 다른 모더,모듈로 컴파일이 되지 않도록 하기 위한 안전성 확보차원에서 정의하는 것입니다.

반대로 include로 꼭 이 로더를 사용해서 컴파일할 것들을 지정해 줄 수도 있습니다.

 

마지막으로 css 파일을 추출하기 위한 플러그인 설정을 위해 new MiniCssExtractPlugin({ filename: 'css/style.css' }) 를 작성합니다. 이때 옵션으로 컴파일과 번들링된 최종 파일이 저장될 경로로 번들링된 파일이름을 지정할 수 있습니다.

webpack.config.js 작성이 끝났다면 CLI에서 webpack을 실행해 보면 /dist/css/style.css 파일이 추출되어 있는 것을 확인할 수 있습니다.

 

그리고 index.html에 추출된 css를 사용하기 위해 import 시켜주도록 합니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>Webpack Task</title>
	<link rel="stylesheet" href="dist/css/style.css">
</head>
<body>
	<header>
		<h1>Webpack 학습하기</h1>
	</header>
	<div>
		<p>
			사실 웹팩 설정은 복잡하기로 악명 높지만 다양한 업무를 처리해 줄 수 있는 장점과
			계속해서 빠르고 쉽게(?) 개선되고 있습니다.
		</p>
	</div>
	<script src="dist/jaehee.js"></script>
</body>
</html>

index.html을 브라우저에서 확인하면 css가 적용된 것을 확인하실 수 있습니다.

 

 

Concepts Review

지금까지 살펴본 웹팩 4가지 주요 속성을 도식으로 나타내보면 다음과 같습니다.


위 도식을 보면서 지금까지 배운 내용을 정리하면 다음과 같습니다.

  1. Entry 속성은 웹팩을 실행할 대상 파일. 진입점
  2. Output 속성은 웹팩의 결과물에 대한 정보를 입력하는 속성. 일반적으로 filenamepath를 정의
  3. Loader 속성은 CSS, 이미지와 같은 비 자바스크립트 파일을 웹팩이 인식할 수 있게 추가하는 속성. 로더는 오른쪽에서 왼쪽 순으로 적용
  4. Plugin 속성은 웹팩으로 변환한 파일에 추가적인 기능을 더하고 싶을 때 사용하는 속성. 웹팩 변환 과정 전반에 대한 제어권을 갖고 있음

 

 

 

Conclusion

이번 장에서 웹팩의 주요 속성인 mode, entry, output, module, plugins 에 대해 알아보았습니다.

다음 장에서는 실제로 실무에 필요한 주요 환경 설정과 그에 따른 webpack Dev Server, SASS, 기타 로더, 플러그인 등을 다뤄보도록 하겠습니다.

 

 

Jaehee's WebClub

 

 

'Web Tech > Webpack' 카테고리의 다른 글

Webpack Guide for beginner #3  (0) 2019.11.19
Webpack Guide for beginner #2  (4) 2019.11.19
Webpack Guide for beginner #1  (2) 2019.11.19

댓글을 달아 주세요

  1. coco 2019.08.14 09:43

    정리가 잘된 글 감사합니다!
    기초 부터 다시봐야겠어요~ 즐겨찾기하고가요~

  2. 2020.01.23 11:42

    비밀댓글입니다

  3. 2020.02.20 15:16

    비밀댓글입니다