프론트엔드 빌드 시스템에 대해서 알아보자! (feat. Webpack)

📌 웹팩을 사용하기 전, 알고 있으면 좋은 배경 지식들

웹팩을 사용하기 전, Node.js & NPM이 필요합니다. 해당 도구들에 대한 배경 지식이 있으면 웹팩을 다루는데 도움이 됩니다. 해당 배경 지식이 있는 분들은 웹팩으로 바로 넘어가셔도 좋습니다.

✨ Node.js

브라우저 밖에서도 자바스크립트를 실행할 수 있는 환경을 의미합니다.

✨ NPM(Node Package Manager)

자바스크립트 라이브러리를 설치하고 관리할 수 있는 패키지 매니저입니다.

주요 명령어

npm init: 명령어 실행 시, package.json 파일이 생성됩니다.
npm init -y: 명령어 실행 시, package.json 파일이 생성됩니다.
npm install ${라이브러리 이름}: 해당 명령어로 라이브러리 설치 시, 해당 프로젝트에 node_modules 폴더가 생깁니다. 그리고 라이브러리가 설치되어 있는 것을 확인할 수 있습니다. (참고로 install 명령어는 i로 축약할 수 있습니다)
주요 옵션: —-save-dev & —-global
npm uninstall ${라이브러리 이름}: 해당 라이브러리와 관련된 라이브러리 모두 삭제합니다.

NPM은 왜 사용하며, 어떤 장점이 있을까?

라이브러리를 HTML 중간에 삽입한다면(CDN 방식) 직접 찾아야 합니다. 이렇게 되면 버전 관리가 어렵고, 라이브러리 의존성이 엮였을 때 문제가 생깁니다. 따라서 NPM을 사용해서 package.json 한 곳에서 관리한다면 좀 더 용이합니다.
CDN 방식은 일일이 직접 태그를 찾아서 들고 와야 하기 때문에 번거롭습니다. NPM을 사용한다면 명령어 한 줄로 쉽게 추가할 수 있습니다.

✨ 자바스크립트 모듈 관련된 도구들

Path

파일 경로를 안전하게 설정하기 위해 사용하는 모듈입니다.
var path = require('path');
JavaScript

AMD & Common.js

자바스크립트의 모듈화 라이브러리의 선두 주자입니다.
Common.js : 브라우저 뿐만 아니라 서버 사이드 개발에서도 사용하기 용이하도록 만들어졌습니다. node.js에서 사용 가능합니다. (require, module exports를 사용합니다)
AMD : 비동기 모듈에 대한 표준안입니다. 모듈이 로딩될 때까지 동기로 기다리지 않고, 비동기 모듈 방식으로 효과를 발휘할 수 있습니다. (define(), require()를 사용합니다)

ES6 Modules

import & export는 자바스크립트의 코드를 모듈화 할 수 있는 기능입니다. 모듈화는 다른 파일에 있는 자바스크립트 기능을 특정 파일에서 사용할 수 있는 것을 의미합니다.
export 변수, 함수 : 다른 파일에서 가져다 쓸 변수나 함수의 앞에 export라는 키워드를 붙입니다. export된 파일은 임포트로 불러서 사용할 수 있습니다.
import { 불러올 변수 or 함수 이름 } form '파일 경로'; : 익스포트된 변수나 함수를 중괄호 {}에 선언하고, 파일 경로를 명시하면 됩니다.
ES6 기본 문법들이 최신 브라우저에서 지원되지만, import & export는 아직 보조 도구가 필요합니다. 이 점을 주의해야 합니다.

📌 Webpack

최신 프론트엔드 프레임워크에서 가장 많이 사용되는 모듈 번들러(Module Bundler)입니다. 하나의 웹 서비스를 구성하는 파일들을 해석한 다음 하나의 파일로 합쳐주는 역할을 합니다. 웹팩은 자바스크립트만 관계되어 있다고 생각하면 안 됩니다. 웹에서 사용하는 모든 자원에 대해 영향을 미칠 수 있는 강력한 도구입니다.

✨ '용어' 헷갈리지 말자

모듈이란?

특정 기능을 갖는 작은 코드 단위를 의미합니다.

모듈 번들링이란?

여러 자원들을 하나의 파일로 병합 및 압축 해주는 '동작'을 모듈 번들링이라고 합니다.

모듈 번들러란?

웹 애플리케이션을 구성하는 자원(HTML, CSS, JS 등)을 각각의 모듈로 보고 이를 조합해서 하나의 결과물을 만드는 '주체'입니다.

✨ 무엇을 해결하려고 했을까?

1. 파일 단위 자바스크립트 모듈 관리 필요성

자바 스크립트는 기본적으로 전역 범위를 가집니다. 어디서든 접근이 가능하다는 의미입니다. 이러한 부분에서 장점도 있지만, 복잡한 애플리케이션인 경우 문제가 발생할 수 있습니다. 예를 들자면 같은 이름의 변수가 의도치 않은 값을 할당할 수 있습니다. 이로 인해 큰 버그로 이어질 수 있습니다. 따라서 파일 단위로 모듈화가 필요합니다. 이를 해결하기 위해 AMD, Common.js와 같은 라이브러리가 등장했고, 웹팩은 이 두 가지 모두 지원합니다.

2. 웹 개발 작업 자동화 도구

웹 서비스를 개발하고 배포할 때 아래와 같은 작업을 매번 해야 했습니다.
1.
HTML, CSS, JS 압축
2.
이미지 압축
3.
CSS 전처리기 변환
이를 자동화하기 위해 Grunt, Gulp 같은 도구들이 등장했습니다. 웹팩은 이런 도구를 포함하고, 더 많은 작업을 수행할 수 있습니다.

3. 웹 애플리케이션의 빠른 로딩 속도와 높은 성능

웹 사이트 로딩 속도에 따라서 사용자 이탈까지 발생할 수 있습니다. 이를 개선하기 위한 대표적인 방법은 파일을 서버로 요청하는 횟수를 줄이는 것입니다. 그래서 지연 로딩(Lazy Loading)이 등장했습니다. 웹팩은 이를 채용하여 파일이 필요할 때 요청합니다. 즉, 미리 로딩하지 않고 필요할 때마다 요청하기 때문에 초기 로딩 속도를 향상시킬 수 있습니다.

✨ 웹팩 명령어 간소화하기

webpack.config.js 파일은 매번 명령어로 entry, output 등 여러 옵션을 사용하지 않고, 해당 파일에서 기본 설정을 할 수 있습니다. 그러면 아래와 같이 기존 명령어를 간소화할 수 있습니다.
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --mode=none --entry=src/index.js --output=public/output.js" },
JavaScript
package.json
//webpack.config.js module.exports = { mode: 'none', entry: './src/index.js', output: './public/output.js' }; //package.json "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack" },
JavaScript

✨ 웹팩 적용하기 전과 후로 '네트워크 요청 횟수' 비교하기

크롬 개발자 모드의 '네트워크'를 통해 어떤 변화가 있는지 확인 가능합니다. 가장 큰 변화는 '네트워크 요청 횟수' 입니다. 웹팩은 여러 자원을 하나의 파일로 합칩니다. 즉, 여러 자원을 묶은 파일만 요청하기 때문에 네트워크 요청 횟수를 줄일 수 있습니다.
웹팩 적용하기 전, 요청 횟수 → 3회
웹팩 적용한 후, 요청 횟수 → 1회
만약에 지구 반대편에 있는 곳에서 요청한다면 어떻게 될까요? 네트워크 상황이 좋지 않은 경우 지연 시간이 발생하게 됩니다. N개의 자원을 요청했을 때, 지연시간에 의해 시간이 더 걸리게 됩니다. 따라서 네트워크 요청 횟수를 줄이는 것은 중요합니다. 참고로 브라우저별로 HTTP 요청 횟수는 제약되어 있기 때문에 이에 대한 최적화는 꼭 필요합니다.

✨ 웹팩3에서 4로 달라진 점은 무엇일까?

mode

웹팩 4부터 모드(mode)라는 개념이 추가되었습니다. 모드는 아래 3가지가 있습니다.
1.
none: 설정 안 함
2.
development: 개발 모드
3.
production: 배포 모드
각 실행 모드에 따라 결과물도 달라지는데 그에 맞게 웹팩에서 최적화하기 때문입니다. 참고로 기본 값은 production 모드로 설정되어 있습니다.

ETC

빌드 속도가 빨라졌습니다.
CommonsChunkPlugin이 deprecated 되고, SplitChunksPlugin으로 대체되었습니다.

✨ 웹팩 주요 속성 4가지

entry

웹팩에서 자원을 변환하기 위해 필요한 최초 진입점입니다. (자바스크립트 파일 경로) 웹 애플리케이션의 전반적인 구조와 내용이 담겨져 있어야 합니다. 따라서 애플리케이션을 동작시킬 수 있는 내용들이 담겨 있어야 합니다. 참고로 싱글 페이지 애플리케이션은 일반적으로 엔트리 포인트가 하나이지만, 멀티 페이지 애플리케이션인 경우 엔트리 포인트가 여러 개가 될 수 있습니다.

output

웹팩을 돌리고 난 결과물의 파일 경로를 의미합니다. 참고로 객체 형태로 옵션을 추가합니다.
filename : 웹팩으로 빌드한 파일 이름을 의미합니다. 해당 속성의 옵션의 예시는 아래와 같습니다.
'[name].bundle.js' : 파일 이름에 entry 속성을 포함하는 옵션
'[id].bundle.js' : 파일 이름에 웹팩 내부적으로 사용하는 모듈 ID를 포함하는 옵션
'[name].[hash].bundle.js' : 빌드마다 고유 해시 값을 붙이는 옵션
'[chunkhash].bundle.js' : 각 모듈 내용을 기준으로 생성된 해시 값을 붙이는 옵션
path : 해당 파일의 경로를 의미합니다.
var path = require('path'); module.exports = { output: { filename: 'bundle.js', path: path.resolve(__dirname, './dist') // './dist/bundle.js'와 동일합니다. } }
JavaScript
webpack.config.js

loader

웹 애플리케이션을 해석할 때 자바스크립트 파일이 아닌 웹 자원들을 변환할 수 있도록 도와주는 속성입니다. (HTML, CSS, 이미지, 폰트 등) 해당 속성은 module이라는 이름을 사용합니다. 실제로 적용해보면 css 파일에 있는 코드들이 자바스크립트 파일로 들어가게 됩니다.
아래 코드를 해석해보면 아래와 같습니다.
"모든 css 파일에 style-loader부터 시작해서 css-loader까지 적용하겠습니다."
module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'], } ] },
JavaScript
loader를 적용하지 않으면 에러가 발생하는데 왜 그럴까요? CSS 파일을 웹팩을 적용한다고 가정해보겠습니다. 일반적으로 자바스크립트 파일 안에 CSS를 넣을 수 없습니다. 그러나 loader를 사용하면 CSS 파일을 해석하고, 자바스크립트 안에 넣을 수 있습니다.
참고로 로더의 순서도 중요합니다. 예로 들자면 style-loader와 css-loader의 순서를 바꾼다면 에러가 발생합니다. 기본적으로 오른쪽에서 왼쪽 순서로 진행됩니다. 이 점을 꼭 유의해야 합니다.
css-loader : CSS가 웹팩으로 들어갈 수 있게 도와주는 역할을 합니다.
style-loader : 웹팩 안에 들어가 있는 스타일을 헤더 안에 넣어주는 역할을 합니다.
로더 종류가 많기 때문에 좀 더 알아보고 싶으시다면 아래 링크를 참고하시길 바랍니다.

plugin

추가적인 기능을 제공하는 속성입니다. 플러그인은 해당 결과물의 형태를 바꾸는 역할을 한다고 보면 됩니다. 배열을 사용하며 각 요소들은 아래와 같이 객체 인스턴스만 추가할 수 있습니다.
var webpack = require('webpack'); var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { plugins: [ new HtmlWebpackPlugin(), new webpack.ProgressPlugin() ] }
JavaScript
플러그인 종류가 많기 때문에 좀 더 알아보고 싶으시다면 아래 링크를 참고하시길 바랍니다.

요약

Entry : 웹팩을 실행할 대상 파일 혹은 진입점입니다.
Output : 웹팩의 결과물에 대한 정보를 입력하는 속성, 일반적으로 filename, path를 정의합니다.
Loader : CSS, 이미지와 같은 자바스크립트가 아닌 파일을 웹팩이 인식하도록 도와주는 속성입니다. (오른쪽에서 왼쪽 순으로 적용됩니다)
Plugin : 웹팩으로 변환한 파일에 추가적인 기능을 더하고 싶을 때 사용하는 속성입니다.

✨ Webpack Dev Server

개발하는 과정에서 쓰이는 도구입니다. 웹팩의 빌드 대상 파일이 변경되었을 때, 웹팩으로 빌드한 후 브라우저를 새로고침 해줍니다. 이로 인해 개발 생산성을 향상시킬 수 있습니다.
웹팩 데브 서버를 실행하면 빌드한 결과물이 보이지 않습니다. 왜 그럴까요? 메모리에 저장되기 때문입니다. 파일 입출력보다 메모리 입출력이 더 빠르고, 컴퓨터 자원이 덜 소모될 수 있습니다. 따라서 크롬 브라우저의 네트워크를 보면 bundle.js 파일을 요청하고 있지만, 눈으로 확인할 수 없는 것이 메모리에 저장되기 때문입니다.

📌 참고 자료

TOP