인프런 캡틴판교 - 프론트엔드 개발자를 위한 웹팩 강의를 듣고 정리한 내용입니다.
프론트엔드 프레임워크에서 가장 많이 사용되는 모듈 번들러
프로그래밍 관점에서 특정 기능을 가지는 작은 코드 단위
웹팩에서의 모듈은 자바스크립트 모듈에만 국한되지 않고 웹 어플리케이션을 구성하는 모든 자월을 의미한다. 어플리케이션 제작에 필요한 모든 파일들이 각각 모듈에 해당한다.
웹 어플리케이션을 구성하는 여러 자원들을 하나의 파일로 병합 및 압축해 주는 동작 빌드, 번들링, 변환은 모두 같은 의미이다.
1) 파일 단위의 자바스크립트 모듈 관리의 필요성 변수를 중복 선언하거나 의도치 않은 값을 할당하는 문제가 발생할 수 있기 때문
2) 웹 개발 작업 자동화 도구 (Web Task Manager)
웹 서버에 배포할 때 <HTML, CSS, JS 압축 / 이미지 압축 / CSS 전처리기 변환> 등의 일을 자동화해 주는 도구의 필요성 증가 ➡️ Grunt
, Gulp
등장
3) 웹 어플리케이션의 빠른 로딩 속도와 높은 성능 웹 사이트의 로딩 속도를 높이기 위해 처음에는 웹 태스크 매니저 또는 Lazy Loading을 활용했다. 웹팩은 필요할 때에 해당 자원을 요청하자는 철학을 가지고 있다.
1) 자바스크립트 변수 유효 범위 문제 ES6의 Modules 문법과 웹팩의 모듈 번들링으로 해결한다.
2) 브라우저별 HTTP 요청 숫자의 제약 브라우저에서 서버로 보낼 수 있는 HTTP 요청 수가 제한되어 있기 때문에 요청 숫자를 줄이는 것이 성능 향상 면에서나 사용자 측에서나 중요한 문제로 떠올랐다. ➡️ 웹팩을 이용하여 여러 개의 파일을 하나로 합치면 브라우저별 HTTP 요청 횟수 제약을 피할 수 있다.
3) 사용하지 않는 코드의 관리
4) Dynamic Loading & Lazy Loading 미지원
웹팩의 Code Splitting
기능을 이용해 원하는 모듈을 원하는 타이밍에 로딩할 수 있다.
Node.js: JavaScript 실행 환경 npm: 자바스크립트 라이브러리를 관리해 주는 도구
npm init -y
위 명령어를 실행하면 package.json
파일이 생성되고 기본값을 바로 넣어 줌
npm install jquery
node_modules
폴더가 생성되고, 그 안에 jquery
폴더도 만들어짐
라이브러리를 코드 중간에 삽입하는 경우, 어떤 라이브러리가 설치되어 있는지 알기 위해서는 모든 <script>
태그를 찾아봐야 한다는 불편함이 있다.
➡️ package.json
을 사용하면 라이브러리와 버전을 관리하기 쉽다.
라이브러리 페이지를 찾아가서 cdn을 불러오는 것보다 npm install
로 설치하는 게 훨씬 편리하다.
npm install gulp
위 명령어를 실행해 보면 node_modules
폴더에 수많은 폴더가 생기는데, 이는 gulp
라는 라이브러리가 다른 많은 라이브러리들을 사용하여 함께 설치되었기 때문이다.
npm uninstall gulp
위 명령어를 실행하면 gulp
와 함께 설치되었던 라이브러리들도 모두 제거된다.
npm install gulp --global
전역 설치하는 경우 node_modules
폴더에 추가되지 않는다.
mac os 기준
/usr/local/lib/node_modules
1) 지역 설치
npm install jquery
npm install jquery --save-prod
--save-prod
는 기본값이기 때문에 위 두 명령어는 결과가 같다.
또한 install
대신i
를 사용해도 된다.
2) 전역 설치 시스템 레벨에서 사용할 자바스크립트 라이브러리를 설치할 때 사용한다.
npm install gulp --global
npm install gulp -g
명령어 실행 창에 해당 라이브러리 이름을 입력하면 명령어를 인식한다.
npm 지역 설치에 자주 사용되는 옵션 두 가지
npm install jquery --save-prod
npm install jquery --save-dev
npm i jquery
npm i jquery -D
dependencies는 npm i jquery jquery-ui
와 같이 실행되었을 때,
devDependencies는 npm i vue -D
와 같이 실행했을 때 추가된다.
구분해서 설치하는 이유는, dependency는 어플리케이션의 로직과 연관 있는 라이브러리들이 추가되고, devDependency는 webpack
, js-compression
, sass
등과 같은 개발 보조 라이브러리들이 설치된다.
npm 지역 설치 시 해당 라이브러리가 배포용인지, 개발용인지 구분해야 한다.
배포용 라이브러리는 npm run build
실행 시 최종 어플리케이션 코드 안에 포함이 되지만, -D
로 옵션을 주어 설치한 라이브러리는 빌드 후 배포할 때 어플리케이션 코드에서 빠지게 된다.
개발할 때에만 사용하고 배포할 때에는 빠져도 좋은 라이브러리들
webpack
빌드 도구eslint
코드 문법 검사 도구imagemin
이미지 압축 도구아래 명령어로 package.json
파일 생성 후 웹팩과 lodash
라이브러리 설치
npm init -y
npm i webpack webpack-cli -D
npm i lodash
index.html
파일과 src
폴더 아래에 index.js
생성
<html>
<head>
<title>Webpack Demo</title>
<script src="https://unpkg.com/lodash@4.16.6"></script>
</head>
<body>
<script src="src/index.js"></script>
</body>
</html>
import _ from 'lodash';
function component() {
var element = document.createElement('div');
/* lodash is required for the next line to work */
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}
document.body.appendChild(component());
index.html
를 다음과 같이 수정
<html>
<head>
<title>Webpack Demo</title>
</head>
<body>
<script src="dist/main.js"></script>
</body>
</html>
package.json
에 웹팩 빌드 명령어 추가
"scripts": {
"build": "webpack --mode=none"
}
npm run build
명령어 실행 후 라이브 서버로 실행
프로젝트 루트 레벨에 webpack.config.js
생성 후 아래 내용 추가
// `webpack` command will pick up this config setup by default
var path = require('path');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
};
package.json
수정
"scripts": {
"build": "webpack"
npm run build
실행하여 빌드 확인!
웹팩의 빌드(파일 변환) 과정을 이해하기 위해서는 아래 4가지 주요 속성에 대해 알아야 한다.
일단 이전에 작성했던 webpack.config.js
파일은 다음과 같다.
var path = require('path');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
};
말 그대로 웹 자원을 변환하기 위해 필요한 “최초 진입점”이자 자바스크립트 파일 경로
module.exports = {
entry: './src/index.js',
};
위와 같이 되어 있으면 웹팩 실행 시 index.js
를 대상으로 빌드를 수행한다는 뜻이다.
따라서 entry
로 지정한 파일에는 웹 어플리케이션의 전반적인 구조와 내용을 담고 있어야 한다.
entry: {
login: './src/LoginView.js',
main: './src/MainView.js'
}
위와 같이 엔트리 포인트를 2개 이상 사용하는 방식은 멀티 페이지 어플리케이션에 적합하다.
웹팩 사용 후 결과물의 파일 경로를 의미한다.
옵션은 객체 형태로 추가해야 하며, 일반적으로 filename
과 path
속성을 함께 정의한다.
var path = require('path');
module.exports = {
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './dist'),
},
};
위 코드에서 path.resolve()
는 인자로 넘어온 경로를 조합하여 유효한 파일 경로를 만들어 주는 Node.js의 API이다. 즉, ./dist/bundle.js
에 결과물을 저장한다는 뜻이다!
filename
속성에는 여러 옵션을 넣을 수 있다.
output: {
filename: '[name].bundle.js';
filename: '[id].bundle.js';
filename: '[name].[hash].bundle.js';
filename: '[chunkhash].bundle.js';
}
entry
속성을 포함웹팩이 웹 어플리케이션을 해석할 때 JS 파일이 아닌 웹 자원(HTML, CSS, Images, Fonts)들을 변환할 수 있도록 도와주는 속성 - module
이라는 이름 사용
module.exports = {
module: {
rules: [],
},
};
🏷 CSS Loader 적용하기
css-loader
설치 후 webpack.config.js
파일을 다음과같이 변경한다.
npm i css-loader -D
module.exports = {
entry: './app.js',
output: {
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['css-loader'],
},
],
},
};
test
: 로더를 적용할 파일 유형 (보통 정규식 사용)user
: 해당 파일에 적용할 로더의 이름🏷 자주 사용되는 로더 종류
🏷 로더 적용 순서
특정 파일에 대해 여러 로더를 사용하는 경우, 적용 순서에 주의해야 한다.
로더는 기본적으로 오른쪽에서 왼쪽 ⬅ 순으로 적용된다.
module: {
rules: [
{
test: /\.scss$/,
use: ['css-loader', 'sass-loader'],
},
];
}
위 코드는 scss 파일을 sass로더로 전처리 한 다음, 웹팩에서 css 파일을 인식할 수 있도록 css 로더를 적용한다.
웹팩의 기본적인 동작에 추가적인 기능을 제공하는 속성이다.
플러그인의 배열에는 생성자 함수로 생성한 객체 인스턴스만 추가될 수 있다.
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [new HtmlWebpackPlugin(), new webpack.ProgressPlugin()],
};
HtmlWebpackPlugin
: 웹팩으로 빌드한 결과물로 HTML 파일 생성ProgressPlugin
: 웹팩의 빌드 진행률을 표시mode
속성은 웹팩으로 빌드할 때 development
, production
, none
모드를 설정할 수 있다.
module.exports = {
mode: 'none',
};
코드 변경 후 저장하면 웹팩 빌드 후 브라우저를 자동으로 새로고침 해 준다.
"scripts": {
"dev": "webpack serve",
"build": "webpack"
}
웹팩 데브 서버를 실행하여 빌드한 결과물은 메모리에 저장되고 따로 파일로 생성되지는 않는다. 따라서 개발 완료 후 명령어를 이용해 파일로 생성해야 한다.
실무에서 가장 흔히 사용되는 속성! CORS 에러를 해결할 수 있다.
실제 브라우저에서는 localhost:8080/api/login
으로 요청했지만, 서버에서는 domain.com
에서의 요청으로 받아들이기 때문에 CORS 에러가 발생하지 않는다!
// webpack.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'domain.com',
changeOrigin: true,
},
},
},
};
브라우저를 새로고침 하지 않아도 웹팩으로 빌드한 결과물이 웹 어플리케이션에 반영되도록 도와주는 설정이다.
module.exports = {
devServer: {
hot: true,
},
};
배포용으로 빌드한 파일과 원본 파일을 서로 연결시켜 주는 기능이다.
서버에 배포 시 웹 자원을 압축하는데, 이 파일에서 에러가 난다면 소스맵을 이용하여 원본 소스 파일을 확인할 수 있다.
// webpack.config.js
module.exports = {
devtool: 'cheap-eval-source-map',
};
module.exports = {
mode: 'none',
entry: '',
// ...
};
none
: 설정 안 함development
: 개발 모드production
: 배포 모드 (default)웹팩으로 개발 시 보통 2가지 경우로 나누어 작업한다.
// webpack.config.js
module.exports = (env) => {
let entryPath =
env.mode === 'production' ? './public/index.js' : './src/index.js';
return {
entry: entryPath,
output: {},
// ...
};
};
// package.json
{
"build": "webpack",
"development": "npm run build -- --env.mode=development",
"production": "npm run build -- --env.mode=production"
}
함수에 있는 env
인자는 환경변수를 의미하고, 웹팩을 실행할 때 옵션으로 넘겨 줄 수 있다. 혹은 두 번째 방법 처럼 npm 커스텀 명령어로도 사용할 수 있다.
webpack --env.a=10
{
"build": "webpack --env.a=10"
}
여러 개의 웹팩 설정 파일을 하나로 병합해 준다. (보통 개발용과 배포용으로 나누어 설정하기 때문)
앞서 있던 예시처럼 실행 모드에 따라 조건문으로 작성할 수도 있지만, 파일을 분리하는 방식을 권장한다.
파일 분리 전, 개발용과 배포용 설정 파일에서 공통으로 쓰이는 부분을 먼저 분리한다. 보통 아래와 같은 방식으로 구분한다!
webpack.common.js
공통 설정 파일에는 entry
, output
, plugins
같이 실행 모드에 관계 없이 항상 들어가는 코드를 추가한다.
// webpack.common.js
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
},
plugins: [new CleanWebpackPlugin(), new HtmlWebpackPlugin()],
};
webpack.dev.js
개발용 설정 파일에는 개발자 도구나 웹팩 데브 서버 설정을 추가한다. 또한 webpack-merge
라이브러리 설치 후 webpack.common.js
파일을 로딩하여 병합한다.
// webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: { contentBase: './dist' },
});
webpack.prod.js
배포 전 웹 리소스 최적화를 위한 설정을 추가한다.
// webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});