Javascript를 모듈화하면 브라우저에서 여러개로 쪼개진 js파일을 개별적으로 로드하느라 네트워크 비용이 많이 들어감
위의 문제점들을 해결하기 위해 Webpack은 쪼개져있는 모듈들을 하나의 묶음 파일로 만들어줌
Gulp, Grunt와의 차이점
gulp, grunt는 태스크 관리 툴로서 자체적으로 수행하는건 태스크 관리 뿐이다.
여러가지 플러그인들을 사용해서 transfile, bundle, uglify 등을 처리한다.
반면에 webpack은 모듈 번들러로써 번들링 기능이 기본이고, 번들링 과정에서 필요한 기능들을 플러그인으로 추가하는 형태이다.
Browserify라는 모듈 번들러도 존재하지만, 기능이 부족하고 설정이 복잡해서 잘 사용되지 않는 것으로 보임
태스크 관리 툴은 좀 더 범용적으로 사용할 수 있지만 기능에 제한이 있고,
모듈 번들러는 범위가 좁은 대신 기능이 강력하다고 생각하면 편하다.
Dependency Tree
Webpack은 모듈간의 의존관계를 분석할 수 있는 기능이 존재한다.
의존관계 분석 기능은 Webpack의 모든 기능의 기반이기 때문에 태스크 관리 툴과의 가장 큰 차이점이라고 볼 수 있다.
gulp 등 태스크 관리 툴은 의존 관계를 분석하는 기능이 없기 때문에 단순한 파일 변환 및 묶기 기능만을 수행할 수 있다.
gulp-webpack, webpack-stream 등의 플러그인을 사용해서 모듈 번들링을 수행할 수 있지만, gulp를 계속 사용해야만 하는 이슈가 없다면 Webpack으로 전환하는게 낫지 않을까..?
gulp-browserify라는 비 Webpack 모듈 번들링 용 플러그인이 존재하기는 하지만, 현재 블랙리스트에 올라서 사용이 지양되고 있다고 한다.
Webpack은 Chunk의 Hash값을 파일 명에 붙여줌으로써 Long Term 캐시를 노리는 기능을 제공한다.
내용이 바뀌지 않은 Chunk는 Hash값도 그대로이므로 브라우저와 서버에 캐시된 데이터를 사용할 수 있는 것이다.
Webpack의 Chunk Hash 기능을 사용하면 내용이 변경 된 js 파일만 새로 다운받을 수 있게 된다.
Code Splitting
Webpack의 기초 용도는 수많은 모듈 js 파일들을 하나로 묶어서 브라우저 환경에 대응하기 위함이지만,
모든 것을 다 묶어버리면 아래의 문제들이 발생하므로 적절한 단위로 js 파일을 분할해주는 것이 좋다.
너무 큰 js파일은 브라우저의 단일 파일 캐시 한도에 의해 로컬 캐싱되지 않을 수 있음
한 개 모듈의 수정으로 전체 파일 내용이 변경되므로 캐시의 효력이 떨어짐
페이지 최초 로딩이 너무 오래 걸림
watch가 느려짐
Split Chunks Plugin
위의 문제들을 해결하기 위한 방법 중 한가지는 공용으로 사용되는 모듈들을 분리해서 별도의 묶음 파일로 사용하는 것이다.
잘 변하지 않고 크기가 크다면 더더욱 별도의 묶음 파일로 분리해야한다.
Split Chunks Plugin은 이런 모듈들을 독립적인 js 파일로 분리해주는 역할을 수행한다.
주로 사용되는 용도
공통적으로 쓰는 외부 라이브러리를 지정해서 vendor.js 를 만들기
내부 모듈 중 공통적으로 사용되는 것들을 묶어서 common.js 를 만들기
JS 지연 로딩(require.ensure() | import())
Split Chunks Plugin로 js 파일을 분리하더라도 한 페이지에서 그것을 모두 로딩하게 된다면, 초기 로딩 속도에 막대한 지장을 끼친다.
SPA(single-page application) 같이 entry point가 하나인 경우 한 페이지에 모든 script 태그가 들어가게 되므로 더더욱 그렇다.
Webpack에서는 이러한 문제를 해결하기 위해, 필요한 순간에 개별로 bundling 된 모듈을 비동기로 로딩하는 기능을 제공한다.
require.ensure() & import() 공통 기능
지연된 로딩을 사용하는 모듈의 의존관계도 개별 bundle로 생성
지연된 로딩을 사용한 모듈의 의존관계를 하나로 묶어서 bundle 생성
require.ensure()
레거시, Webpack Only
polyfill 없이 사용 가능
import()
ECMA 2015 표준
Promise polyfill 필요
논리적인 지연 로딩 가능(실제로는 하나의 번들)
Tree Shaking(Webpack2부터 지원됨)
지금까지 모듈을 모으고 나누고 압축하고 난독화하고 주석제거하는 등 많은 최적화 방식을 알아봤다.
그런데 마지막으로 한가지 더 최적화할 수 있는 구석이 있다.
바로 실제로 사용되지 않는 부분을 아예 제거해버리는 것!
(Webpack이 알아서 다 해주는 것이 아니고, 신경써서 잘 써야한다!)
(진짜 제대로 쓰려면 올바른 형태의 모듈로 개발해야한다. 사용하는 라이브러리들도 모두 올바른 형태여야한다..!)
등장 배경
Webpack1, ES 5에서는 모듈의 '정적'인 의존관계 스펙이 commonjs밖에 없음
정적인 의존관계라 함은 이미 의존관계 분석 후 하나로 합쳐진 것(지금까지 설명한 모듈 번들링)을 의미함
기존에는 모듈의 일부만 사용하더라도 모든 내용을 가져와서 합쳐야 했음
commonjs는 서버사이드를 전제로 하고 만들어진 방식이라서 브라우저를 위한 모듈화에서 사용하려니 용량에 대한 문제가 발생함
ES2015+ Native Import의 등장으로 모듈의 일부를 가져올 수 있게 됐고, Webpack2에서 이를 지원한다!
작동 방식
Webpack이 ES2015+ Native Import를 통해 실제 사용되는 부분만 export 시킴
import하고, 해당 객체가 사용되지 않을 때 export 하지 않음
import Alphabet from "alphabet";
모듈의 일부만 import 됐을 때, 그를 제외한 나머지는 export 하지 않음
import {a} from "alphabet";
부분 import가 추천되는 이유는, 전체를 받은 후 일부를 쓰면 전체가 Reachable한 상태라서 전체 export 돼버리기 때문
번들링 후에도 코드는 남아있지만 Unreachable 상태(export를 안했으므로)
UglifyJS가 dead code들을 제거해줌
Webapck의 Unreachable 코드는 물론이고, 직접 개발한 js들의 Unreachable 코드도 모두 지워줌
사용법
Webpack2에서 import를 사용하더라도 babel preset es2015를 사용하고 있다면, ES5 코드로 변환시켜버림(import -> require())
import lodash from 'lodash';
// => var lodash = require('lodash'); // babel에 의해 변환된 commonjs 방식
import { assign } from 'lodash'; // ES2015+ Native Import 방식
// => var assign = require('lodash').assign; // babel에 의해 변환된 commonjs 방식, 일단 전체를 가져와야함
아래와 같은 처리로 변환을 방지해야함
javascript //babel 설정 presets: [ [["es2015", { "modules": false }]] ]
이렇게 번들링을 하더라도 실제 소스코드는 남아있고 export만 되지 않은 상태인데, UgilfyJS 플러그인의 compress.unused : true 옵션을 사용하면 모두 제거됨
그러나..
아직 많은 라이브러리들이 ES2015+ 스타일에 맞춰 제공하고 있지 않음
직접 개발한 모듈이라도 ES2015+ 스타일대로 개발합시다.
watch
Webpack watch가 수행되면 대상 파일들에 대해 감시가 시작되고, 파일에 변경이 일어나면 해당 파일만 다시 작업(loader, plugin 등)한 후 재 번들링을 수행해줍니다.
성능이 좋은 이유
필요한 부분만 재 작업함(모듈 의존관계로 어느 것들이 다시 번들링돼야 하는지 알 수 있기 떄문)
기본적으로 모듈들이 메모리에 캐시돼있기 때문에, 의존관계가 맺어져있는 모듈들이 다시 작업될 필요가 없음(watch 기본 옵션)
매번 전체를 돌리는게 아니고 수정된 부분만 돌림(의존성 트리가 있기 때문에 가능!)
주의사항
전역적으로 쓰이는 모듈은 Commons-Chunk-Plugin으로 분리해서 번들링 작업이 수행되는 범위를 최대한 줄여야함
webpack이란 무엇인가
자바 스크립트 애플리케이션을 위한 모듈 번들러
Gulp, Grunt와의 차이점
gulp, grunt는 태스크 관리 툴로서 자체적으로 수행하는건 태스크 관리 뿐이다. 여러가지 플러그인들을 사용해서 transfile, bundle, uglify 등을 처리한다. 반면에 webpack은 모듈 번들러로써 번들링 기능이 기본이고, 번들링 과정에서 필요한 기능들을 플러그인으로 추가하는 형태이다.
태스크 관리 툴은 좀 더 범용적으로 사용할 수 있지만 기능에 제한이 있고, 모듈 번들러는 범위가 좁은 대신 기능이 강력하다고 생각하면 편하다.
Dependency Tree
Webpack은 모듈간의 의존관계를 분석할 수 있는 기능이 존재한다. 의존관계 분석 기능은 Webpack의 모든 기능의 기반이기 때문에 태스크 관리 툴과의 가장 큰 차이점이라고 볼 수 있다. gulp 등 태스크 관리 툴은 의존 관계를 분석하는 기능이 없기 때문에 단순한 파일 변환 및 묶기 기능만을 수행할 수 있다.
webpack.config.js
gulp에 gulpfile.js가 있다면 Webpack에는 webpack.config.js가 있다.
Entry(엔트리 포인트라고 표현하기도 함)
Output
Loaders
https://webpack.js.org/configuration/module/#rule-loader
Plugins
최적화
Chunk Hash
Webpack은 Chunk의 Hash값을 파일 명에 붙여줌으로써 Long Term 캐시를 노리는 기능을 제공한다. 내용이 바뀌지 않은 Chunk는 Hash값도 그대로이므로 브라우저와 서버에 캐시된 데이터를 사용할 수 있는 것이다. Webpack의 Chunk Hash 기능을 사용하면 내용이 변경 된 js 파일만 새로 다운받을 수 있게 된다.
Code Splitting
Webpack의 기초 용도는 수많은 모듈 js 파일들을 하나로 묶어서 브라우저 환경에 대응하기 위함이지만, 모든 것을 다 묶어버리면 아래의 문제들이 발생하므로 적절한 단위로 js 파일을 분할해주는 것이 좋다.
Split Chunks Plugin
위의 문제들을 해결하기 위한 방법 중 한가지는 공용으로 사용되는 모듈들을 분리해서 별도의 묶음 파일로 사용하는 것이다. 잘 변하지 않고 크기가 크다면 더더욱 별도의 묶음 파일로 분리해야한다.
Split Chunks Plugin은 이런 모듈들을 독립적인 js 파일로 분리해주는 역할을 수행한다.
주로 사용되는 용도
JS 지연 로딩(require.ensure() | import())
Split Chunks Plugin로 js 파일을 분리하더라도 한 페이지에서 그것을 모두 로딩하게 된다면, 초기 로딩 속도에 막대한 지장을 끼친다. SPA(single-page application) 같이 entry point가 하나인 경우 한 페이지에 모든 script 태그가 들어가게 되므로 더더욱 그렇다.
Webpack에서는 이러한 문제를 해결하기 위해, 필요한 순간에 개별로 bundling 된 모듈을 비동기로 로딩하는 기능을 제공한다.
require.ensure() & import() 공통 기능
require.ensure()
import()
Tree Shaking(Webpack2부터 지원됨)
지금까지 모듈을 모으고 나누고 압축하고 난독화하고 주석제거하는 등 많은 최적화 방식을 알아봤다. 그런데 마지막으로 한가지 더 최적화할 수 있는 구석이 있다. 바로 실제로 사용되지 않는 부분을 아예 제거해버리는 것! (Webpack이 알아서 다 해주는 것이 아니고, 신경써서 잘 써야한다!) (진짜 제대로 쓰려면 올바른 형태의 모듈로 개발해야한다. 사용하는 라이브러리들도 모두 올바른 형태여야한다..!)
등장 배경
작동 방식
사용법
Webpack2에서 import를 사용하더라도 babel preset es2015를 사용하고 있다면, ES5 코드로 변환시켜버림(import -> require())
javascript //babel 설정 presets: [ [["es2015", { "modules": false }]] ]
그러나..
watch
Webpack watch가 수행되면 대상 파일들에 대해 감시가 시작되고, 파일에 변경이 일어나면 해당 파일만 다시 작업(loader, plugin 등)한 후 재 번들링을 수행해줍니다.
성능이 좋은 이유
주의사항