webpack

웹팩은 분산되어 있는 파일들을 하나로 모아서 간단하게 사용할 수 있도록 만들어 주는 모듈 번들러입니다.
단순히 파일을 합치는 것 뿐만 아니라
미니파이 시켜서 파일 사이즈를 줄여주기도 하고
사용하지 않는 변수를 알아서 제거해 메모리 사용량을 줄여주기도 하는 등
그 밖에 다 나열하기 힘들 정도로 다양한 기능을 간단한 설정만으로 사용할 수가 있습니다.
웹팩과 같은 번들러로 parcel, gulp 가 있다.
웹팩4 가 나왔다. 웹팩 핸드북

** webpack 기본 사용방법

웹팩을 어떻게 설치하고 사용하는지 알아보겠습니다.

  1. node.js 설치합니다.
    https://nodejs.org/ko/ 로 들어가서 LTS 버전을 설치합니다.
  2. npm init -y 로 package.json을 초기화시켜준다.
npm init -y
  1. webpack 설치합니다.
npm install webpack webpack-cli path --save-dev
  1. webpack.config.js을 만든다.
touch webpack.config.js
  1. webpack.config.js 안에 다음의 코드를 적는다.
const path = require('path');
module.exports = {
    context: __dirname,
    entry: './src/app.js',
    output: {
        path: path.resolve(__dirname, 'js'),
        filename: 'app.js'
    },
    module: {
    }  
};
  1. package.json 파일 scripts 항목에 webpack 실행 스크립트를 추가합니다.
...
"scripts": {
    "prod":"webpack --mode=production",
    "dev":"webpack --mode=development"
  },
...
  1. 이를 실험하기 위해 엔트리에 지정한 대로 프로젝트 폴더 루트에 src 폴더를 만들고 그 안에 app.js 파일을 만듭니다.
  2. jquery 설치합니다.
npm install jquery --save-dev
  1. 설치가 끝나면 src/app.js 에서 jquery를 가져오고 전역으로 사용할 수 있도록 만듭니다.
import $ from 'jquery';
window.$ = window.jQuery = $;
  1. 그 다음 npm run dev 를 실행시키면 output 에 지정했던 js 폴더 app.js에 jquery 관련 코드가 추가됩니다.

    간단하게 html 파일을 만들어 jquery가 제대로 추가됐는지 확인해보겠습니다.
    루트에 index.html을 만들고
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>hello</h1>
    <script src="./js/app.js"></script>
    <script>
        $(function(){
            console.log($('h1').text());
        })
    </script>
</body>
</html>

웹팩은 엔트리에 지정한 파일에 연관된 패키지들을 추적해서 모두 통합시켜줍니다.
여기까지 웹팩 기본사용 방법이다.

** webpack이 제공하는 기본기능

웹팩에서 제공하는 기본 기능과
웹팩을 사용하는 궁극적인 목표인 플러그인 사용방법에 대해 알아보겠다.

  • minify : 스페이스나 엔터와 같이 동작과는 연관이 없는 불필요한 문자들을 지워 파일사이즈를 줄여준다.
  • uglify : 변수명을 a,b와 같이 짧게 변경해서 파일 사이즈를 줄여주고 코드분석을 어렵게 해준다.
  • treeShaking : 사용하지 않는 변수를 지워 파일 사이즈를 줄여주고 메모리 사용량까지 줄여준다.
npm run prod

위 명령어를 실행하면,
단순히 웹팩에 production 모드를 주는 것만으로도
위 세가지 기능(minify, uglify, treeShaking)을 적용한 결과물이 만들어졌습니다.

개발과정에서는 코드분석을 해야하기 때문에 이 기능들을 적용하면 안되니 디벨롭 모드로 코드를 생성하고
개발이 끝난 뒤 운영 서버에 배포할 때는 코드 분석보다는 속도가 중요한 프로덕션 모드로 코드를 생성한 뒤 배포하면 됩니다.
웹팩은 프로덕션 모드를 실행하면 코드 실행에는 영향을 주지 않는 범위 안에서 알아서 최적화를 해줍니다.

여기까지 웹팩이 제공하는 기본 기능에 대해 알아봤습니다.

** webpack dev server 기본 사용방법

자바스크립트나 css 변경시 npm run dev를 입력하고 브라우저에 가서 refresh를 반복하는 것은 매우 비효율적이다.
webpack dev server 는 코드 변경을 감지해서 웹팩을 자동으로 실행시켜 주는데,
웹팩을 실행시켜 변경한 코드를 반영한 결과파일이 만들어지면
브라우저를 자동으로 reload 시켜주기도 하고
가능할 경우 바로 reload 없이 바로 적용시켜주기도 합니다.

webpack dev server 설치 방법

webpack dev server 설치

npm install webpack-dev-server --save-dev

webpack.config.js 수정

const path = require('path');

module.exports = {
    context: __dirname,
    entry:'./src/app.js',
    output:{
        path:path.resolve(__dirname, 'js'),
        publicPath:'/js/',
        filename:'app.js',
    },
    module:{
    },
    devServer:{
        contentBase:path.resolve(__dirname, 'html'),
        port:9000
    }
};
/* 
publicPath:'/js/', 번들링한 결과물을 웹서버에서 배포할 기본 path 
contentBase:path.resolve(__dirname, 'html'), 웹서버가 사용할 디렉토리
port:9000  웹서버가 사용할 포트  
*/

package.json 수정

webpack dev server 를 실행하는 스크립트를 넣어줍니다.

{
  "name": "npm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "prod": "webpack --mode=production",
    "dev": "webpack --mode=development",
    "watch":"webpack-dev-server --mode=development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "path": "^0.12.7",
    "webpack": "^4.41.4",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.1"
  }
}

webpack dev server 사용 방법

npm run watch 명령어를 실행합니다.

npm run watch

확인해보기 위해 html폴더를 만들고 그 아래 index.html에 다음과 같이 넣는다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script src="http://localhost:9000/js/app.js"></script>
</body>
</html>

src/app.js 에는

console.log("test");

라고 적고 http://localhost:9000/ 에서 실시간 변경을 확인한다.

스타일을 로드하기 위해 css-loader style-loader를 설치하고

npm install css-loader style-loader --save-dev

webpack.config.js module를 아래와 같이 수정합니다.

const path = require('path');

module.exports = {
    context: __dirname,
    entry:'./src/app.js',
    output:{
        path:path.resolve(__dirname, 'js'),
        publicPath:'/js/',
        filename:'app.js',
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                exclude:/node_modules/,
                loader:['style-loader', 'css-loader']
            }
        ]
    },
    devServer:{
        contentBase:path.resolve(__dirname, 'html'),
        port:9000
    }
};

src 폴더 아래에 app.css 를 만든다.

body{background:red;}

src 폴더 아래 app.js 에서

import './app.css';

npm run watch 실행시킨다.

npm run watch

src/app.css 에서 변경한 내용이 실시간으로 적용된 것을 확인할 수 있다.
package.json 에서

"watch":"webpack-dev-server --mode=development --hot"

hot 옵션을 주면 브라우저 reload 없이 변경사항을 반영해주는 hot reload가 동작합니다.

Webpack 의 주요 설정

  • Entry, Output, Loader, Plugins, Resolve

Webpack 이란?

  • 서로 연관 관계가 있는 웹 자원들을 js, css, img 와 같은 스태틱한 자원으로 변환해주는 모듈 번들러

Webpack 을 사용하는 이유 & 배경

  1. 새로운 형태의 Web Task Manager - 기존 Web Task Manager (Gulp, Grunt) 의 기능 + 모듈 의존성 관리 - 예) minification 을 webpack default cli 로 실행 가능
    webpack -p
    
  2. 자바스크립트 Code based Modules 관리
    • 자바스크립트 모듈화의 필요성 : AMD, Common js, ES6(Modules)
    • 기존 모듈 로더들과의 차이점 : 모듈 간의 관계를 청크 (chunk) 단위로 나눠 필요할 때 로딩
    • 현대의 웹에서 JS 역할이 커짐에 따라, Client Side 에 들어가는 코드량이 많아지고 복잡해짐
    • 복잡한 웹 앱을 관리하기 위해 모듈 단위로 관리하는 Common JS, AMD, ES6 Modules 등이 등장
    • 가독성이나 다수 모듈 미병행 처리등의 약점을 보완하기 위해 Webpack 이 등장
  • import export
  • 타임라인 간소화

자바스크립트 모듈화 문제란?

모듈 관리에 대해 script 태그로 JS 를 모듈화 하는 간단한 예제

<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="library1.js"></script>
<script src="module3.js"></script>
  • 상기 모듈 로딩 방식의 문제점 : 전역변수 충돌, 스크립트 로딩 순서, 복잡도에 따른 관리상의 문제
  • 이를 해결하기 위해 AMD 및 기타 모듈 로더들이 등장.

Webpack 의 철학

  1. Everything is Module 모든 웹 자원 (js, css, html) 이 모듈 형태로 로딩 가능
    require('base.css');
    require('main.js');
    
  2. Load only “what” you need and “when” you need
    초기에 불필요한 것들을 모두 로딩하지 않고, 필요할 때 필요한 것만 로딩하여 사용

Webpack CLI 설치

# webpack 4
npm i webpack-cli g

NPM(Node Package Manager)

  • js 개발자들이 편하게 개발할 수 있도록 js 라이브러리들을 모아놓은 열린 공간
  • front-end web apps, mobile apps, robots, routers 라이브러리들이 존재
  • Gulp, Webpack 모두 node 기반, NPM 을 사용하여 필요 라이브러리들을 로딩
  • 재사용 가능한 code를 module, package 라고 호칭
  • package.json : 해당 package에 대한 파일 정보가 들어가 있음
  • keyword로 패키지 검색 가능

Webpack 에 필요한 NPM 명령어

  • npm init 웹팩 초기 설정에 필요한 명령어로 package.json 파일을 생성
    npm init -y
    
  • npm install(i) 패키지명, 프로젝트에서 사용할 node module 설치 및 package.json 업데이트
  • Install it locally if you're going to require() it.
  • install it globally if you're going to run it on the command line.
    npm i jquery angular lodash ‐‐save
    
  • install --save vs install --save-dev
    # --save 는 앱이 구동하기 위해 필요한 모듈&라이브러리 설치. ex) react, vue
    //package.json
    "dependencies":{
    	"vue":"^2.3.3"
    	...
    },
    
    # --save-dev 는 앱 개발시에 필요한 모듈&라이브러리 설치. ex) test, build tool, live reloading
    //package.json
    "devDependencies": {
    	"gul":"^3.9.1",
    	...
    }
    

Webpack 명령어

  • webpack : 웹팩 빌드 기본 명령어 (주로 개발용)
  • webpack ‐p : minification 기능이 들어간 빌드 (주로 배포용)
  • webpack ‐watch(‐w) : 개발에서 빌드할 파일의 변화를 감지
  • webpack ‐d : sourcemap 포함하여 빌드
  • webpack ‐‐display‐error‐details : error 발생시 디버깅 정보를 상세히 출력
  • webpack ‐‐optimize‐minimize ‐‐define process.env.NODE_ENV="'production'" : 배포용

Webpack Getting Started

https://webpack.js.org/guides/getting-started
A Beginner’s Guide to Webpack 4 and Module Bundling

Basic Setup

  1. npm init 으로 package.json 생성
  2. webpack 전역 설치
    mkdir webpack-demo && cd webpack-demo
    npm init -y
    npm install webpack webpack-cli -g -D
    
  3. src/index.js 와 index.html 생성
    webpack-demo
    |- package.json
    + |- index.html
    + |- /src
    +   |- index.js
    
  4. js 와 html 에 코드 추가
    # src/index.js
    function component() {
    let element = document.createElement('div');
    
    // Lodash, currently included via a script, is required for this line to work
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    
    return element;
    }
    
    document.body.appendChild(component());
    
    # index.html
    <!doctype html>
    <html>
    	<head>
    		<title>Getting Started</title>
    		<script src="https://unpkg.com/lodash@4.16.6"></script>
    	</head>
    	<body>
    		<script src="./src/index.js"></script>
    	</body>
    </html>
    
  5. index.html을 `live-server' 실행하여 결과 확인

Creating a Bundle

  1. index.html의 위치를 dist폴더를 만들어 이동시킨다.
    webpack-demo
    |- package.json
    + |- /dist
    +   |- index.html
    - |- index.html
    |- /src
    	|- index.js
    
  2. lodash 설치
    npm install --save lodash
    
  3. src/index.js 에 import _ from 'lodash'; 추가
    # src/index.js
    import _ from 'lodash';
    function component() {
    	let element = document.createElement('div');    		
    	element.innerHTML = _.join(['Hello', 'webpack'], ' ');		
    	return element;
    }
    document.body.appendChild(component());
    
  4. dist/index.html 아래와 같이 수정
    # dist/index.html
    <!doctype html>
    <html>
    	<head>
    		<title>Getting Started</title>
    		<!-- <script src="https://unpkg.com/lodash@4.16.6"></script> -->
    	</head>
    	<body>
    		<script src="main.js"></script>
    	</body>
    </html>
    
  5. npx webpack 실행
    npx webpack
    
  6. index.html을 `live-server' 실행하여 결과 확인

Using a Configuration

webpack4 버전부터는 configuration이 필요치 않지만, 대부분 프로젝트는 복잡한 설정이 필요하기 때문에, 이것이 webpack이 configuration file을 지원하는 이유입니다.

project

webpack-demo
  |- package.json
+ |- webpack.config.js
  |- /dist
    |- index.html
  |- /src
    |- index.js

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
};
npx webpack --config webpack.config.js

Webpack Entry

  • webpack 으로 묶은 라이브러리들을 로딩할 시작점 설정
  • a,b,c 라이브러리를 모두 번들링한 bundle.js를 로딩한다
  • 1개 또는 2개 이상의 엔트리 포인트를 설정할 수 있다.
var config = {
	entry: './path/to/my/entty/file.js'
	entry:{	// 앱로직용, 외부 라이브러리용
		app:'./src/app.js',
		vendors:'./src/vendors.js'
	}
	entry:{	// 페이지당 블러오는 js 설정
		pageone:'./src/pageone/index.js',
		pagetwo:'./src/pagetwo/index.js',
		pagethree:'./src/pagethree/index.js',
	}
}
// webpack.config.js
module.exports = {
	entry:{
		Profile: './profile.js',
		Feed: './feed.js'
	},
	output:{
		path: 'build',
		filename: '[name].js' // 위에 지정한 entry 키의 이름에 맞춰서 결과 산출
	}
};
// 번들파일 Profile.js를 <script src="build/Profile.js"></script>로 HTML 에 삽입

Webpack Output

  • entry 에서 설정하고 묶은 파일의 결과값을 설정
var path = require('path');
module.exports = {
	entry:{
		...
	},
	output:{
		path:path.resolve(__dirname, 'dist'),
		filename:'bundle.js'
		// filename:'[name].js'
	}
};

Output Name Options

output:{
	filename: '[name].js',
	filename: '[hash].js',
	filename: '[chunkhash].js',
}
  1. [name] : 엔트리 명에 따른 output 파일명 생성
  2. [hash] : 특정 webpack build 에 따른 output 파일명 생성
  3. [chunkhash] : 특정 webpack chunk 에 따른 output 파일명 생성

path.join()

  • 해당 API가 동작되는 OS의 파일 구분자를 이용하여 파일 위치를 조합한다.
path.join('/foo', 'bar', 'bax/asdf');
// Returns: '/foo/bar/baz/asdf'

path.resolve()

  • join()의 경우 그냥 문자열을 합치지만, resolve는 오른쪽에서 왼쪽으로 파일 위치를 구성해가며 유효한 위치를 찾는다.
  • 만약 결과 값이 유효하지 않으면 현재 디렉토리가 사용된다. 반환되는 위치 값은 항상 absolute URL 이다.
path.resolve('/foo/bar','./baz');
// Returns : '/foo/bar/baz'
path.resolve('/foo/bar','/tmp/file/');
// Returns : '/tmp/file'
path.resolve('wwwroot','static_files/png/', '../gif/image.gif');
// if the current working derectory is /home/myself/node,
// this returns '/home/myself/node/wwwroot/static_files/gif/image.gif'

Webpack Loader

Webpack Plugins

Webpack Resolve

Webpack Dev Server

Webpack Dev Middleware

Webpack 개발환경 설정