정리정리정리

웹팩(Webpack) 이란, 웹팩 간단 정리 및 리액트(React) 기본 개발환경 세팅. [2] 본문

Javascript

웹팩(Webpack) 이란, 웹팩 간단 정리 및 리액트(React) 기본 개발환경 세팅. [2]

_JSPark 2017. 6. 27. 22:40

자바스크립트 외의 리소스


웹팩의 가장 독특한 특징 중 하나는 모든 종류의 파일을 모듈로 취급할 수 있다는 점이다.

즉, 적절한 로더가 있으면 자바스크립트 코드뿐만 아니라 CSS, 글꼴을 비롯한 어떤 파일이라도 모듈로 취급할 수 있다.

CSS 관련 로더를 설치한다면 웹팩은 @import 문과 CSS의 URL 값을 분석하고 모든 의존성 트리를 추적한 후 모듈들을 빌드하고 전처리한후 번들로 만들어낼 수 있다.




스타일시트


웹팩은 스타일시트를 처리하는 css-loaderstyle-loader라는 두 가지 로더를 제공한다. 두 로더는 각기 다른 작업을 처리한다.

css-loader는 @import와 url 문을 찾고 해석하며, style-loader는 계산된 모든 스타일 규칙을 페이지로 추가한다.

이러한 두 로더를 함께 이용해 스타일시트를 웹팩 자바스크립트 번들에 넣을수 있다.

먼저 npm을 이용해 css-loader와 style-loader를 설치한다.


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


업데이트 된 webpack.config.js

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨

},

{

test : /\.css$/,

loader : "style-loader!css-loader"

}

]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


// 로더 구성에서 느낌표("!")는 각기 다른 로더를 동일한 파일 형식(동일한 확장자)으로 연결하는데 사용된다.


새로 추가할 main.css 파일

html {

box-sizing : border-box;

-ms-text-size-adjust : 100%;

-webkit-text-size-adjust : 100%;

}


*, *:before, *:after {

box-sizing : inherit;

}


body {

margin : 0;

font-family : 'helvetica Neue', Helvetica, Arial, sans-serif;

}


h1, h2, h3, h4, h5, h6, p, ul {

margin : 0;

padding : 0;

}


웹팩은 구성 파일에 정의된 한 엔트리 파일에서 시작해 import, require, url 등의 명령을 따라 전체 의존성 트리를 빌드한다는 것은 앞서 정리 했었다. 위에서 만든 main.css 파일도 어플리케이션에서 임포트야해 웹펙이 이를 찾아낼수 있다.



업데이트 된 main.js

import React from 'react';

import {render} from 'react-dom';
import Greeter from './Greeter';

import './main.css';

render(<Greeter />, document.getElementById('root'));


기본적으로 CSS룰은 별도의 CSS 번들 파일에 포함되지 않고 자바스크립트 파일과 같은 번들에 포함된다.

개발중에는 이 방식이 도움이 되지만 이후에 실무용 설정에서는 CSS파일을 별도로 생성하도록 설정하는 법을 정리한다.




CSS 모듈


CSS 모듈을 정리하기 전에 모듈의 의미를 다시한번 정의해본다면, 모듈은 장황하고 많은 의미가 한번에 집중되어 있던 코드를 명시적으로 선언된 의존성을 가진 작고 깔끔한 독립적 단위로 분할하는 방법이다. 때문에 모듈간 의존성 관리와 로드 순서는 웹팩과 같은 최적화 도구의 도움을 받아 자동으로 처리할 수 있다.


자바스크립트 개발이 발전하는 동안 대부분의 스타일 시트는 여전히 전역 선은을 가득 포함하는 일체형으로 작성되는 경우가 많아 새로운 구현과 유지 관리를 아주 어렵고 복잡하게 만들었다.


CSS 모듈 기법은 이러한 스크립트 모듈의 장점을 CSS 구현하기 위해 시작됐다. CSS 모듈을 이용하면 모든 클래스 이름과 애니메이션 이름의 범위가 기본적으로 로컬이된다. 웹팩은 CSS 로더에서 이를 기본 지원한다. 


개발자가 할 일은 "modules" 쿼리 문자열을 전달해 이 기능을 활성화하는 것이 전부다. 기능을 활성화 하면 CSS에서 클래스 이름을 이를 소비하는 컴포넌트 단위 코드의 로컬 범위로 내보낼 수 있다. 즉, 여러 다른 컴포넌트에 동일한 이름의 클래스가 있어도 걱정할 필요가 없다.



업데이트 된 webpack.config.js CSS 모듈 활성화

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : "style-loader!css-loader?modules" //?modules로 css module 기능 활성화

}

]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


새로운 Greeter.css 파일(모듈단위에서 사용할 css파일)

.root {

background-color : #eee;

padding : 10px;

border : 3px solid #ccc;

}


업데이트 된 Greeter.js

import React, {Component} from 'react';

import config from './config.json';

import style from './Greeter.css';  //Greeter 컴포넌트에서 사용할 로컬범위의 CSS


class Greeter extends Component{

render() {

return (

<div className={style.root}>

{config.greetText}

</div>

);

}

}

export default Greeter


위 코드에서는 CSS 클래스를 style 변수로 임포트하고 JSX 요소에 개별적으로 CSS를 적용하는 방법을 설명하였다.

별도의 자체 CSS 모듈이 있는 다른 컴포넌트에서도 이름이 같은 CSS 클래스 이름을 충돌 없이 이용할 수 있다.

때문에 "root", "header", "footer" 등과 같이 아주 흔한 이름들을 CSS 스타일의 이름으로 사용해도 로컬 범위로 안전하게 이용할 수 있다.


CSS 모듈은 광범위한 주제이고, 이 밖에도 다양한 기능을 포함하고 있다. CSS 모듈에 대한 자세한 내용은 깃허브에서 제공하는 공식 설명서를 참고하면 된다. https://github.com/css-modules/css-modules




CSS 프로세서


CSS 전처리기 종류인 사스(Sass), 레스(Less)는 CSS 포멧을 확장하는 방법을 통해 원래 CSS에는 없는 변수, 중첩, 믹스인, 상속 등의 개념을 이용해 CSS를 작성할 수 있게 해준다.

리액트의 JSX, Vue.js 같은 자바스크립트 확장구문들을 코드를 작성하고 바벨로 코드를 일반 자바스크립트로 컴파일 하는 개념과 비슷하게 CSS 프로세서는 프로그램을 이용해 CSS 확장구문들을 브라우저가 이해할 수 있는 일반 CSS 변환한다.


역시나 마찬가지로! 로더를 이용해 웹팩이 CSS확장구문들을 관리하게 할 수 있다.


대표적인 CSS 전처리기를 위한 웹팩로더이다.


Less Loader : https://github.com/webpack/less-loader


Sass Loader : https://github.com/jtangelder/sass-loader


Stylus Loader : https://github.com/shama/stylus-loader


PostCSS를 이용해 더 유연한 CSS 워크플로를 구현하는 방법도 있다.

PostCSS는 CSS확장언어가 아니라 CSS 변환을 위한 도구로써 CSS에 다양한 변환을 적용하는 개별 플러그인을 연결할 수 있다.


다음 예제에서는 CSS에 공급업체 접두사를 추가해주는 Autoprefixer 플러그인을 PostCSS에 적용해보기위해 PostCSS 로더를 설정해본다.

우선 npm을 이용해 PostCSS 와 Autoprefixer 플러그인을 설치한다.


npm install --save-dev postcss-loader autoprefixer


다음 PostCSS를 CSS 파일 포멧을 위한 새로운 로더로 추가하고,

PostCSS 를 위한 플러그인을 설정하는 섹션을 webpack.config.js 에 새로 만든다.


업데이트 된 webpack.config.js PostCSS 구성

module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : "style-loader!css-loader?modules!postcss-loader//postcss 로더 추가

}

]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


새로 생성할 postcss 설정 정보를위한 postcss.config.js 파일 (여러가지 설정방법들이 존재한다)

module.exports = {

parser: false,

map: false,

plugins: {

'autoprefixer': {} //autoprefixer plugin

}

}


또는


module.exports = {

plugins: [

require('autoprefixer') //autoprefixer plugin

]

}




플러그인


웹팩은 플러그인을 통해 확장할 수 있다. 플러그인은 자기 자신을 빌드 프로세스로 주입하여 커스텀한 동작을 추가할 수 있게 해준다.

로더와 플러그인을 혼동하는 경우가 많은데, 둘은 완전히 다른 개념이다.


로더 : 웹팩이 빌드 프로세스 중에 "로드"하는 각 소스 파일을 하나씩 각각 처리.


플러그인 : 각각의 소스 파일이 아닌 빌드 프로세스 전체에 영향을 미친다.


웹팩은 기본 제공 플러그인을 다수 기본 포함하고 있지만 다양한 타사 플러그인도 이용할 수 있다.




플러그인 이용하기


웹팩이 기본으로 제공해주는 플러그인은 웹팩 구성 파일(webpack.config.js)에서 바로 임포트한 후 플러그인 객체의 인스턴스를 "plugins" 배열에 추가하면 되고 그 이외 플러그인들은 마찬가지로 npm을 이용해 설치 해주고 같은 과정으로 추가 하면된다.


웹팩이 기본으로 제공해주는 간단한 bannerPlugin 을 사용하는 과정이다.


업데이트 된 webpack.config.js 웹팩에서 기본제공하는 plugin 사용

var webpack = require('webpack'); //webpack이 기본으로 제공해주는 plugin 사용하기위해 import


module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/public', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : "style-loader!css-loader?modules!postcss-loader" //postcss 로더 추가

}

]

},


plugins : [

new webpack.BannerPlugin("Copyright Ju sung Park inc.") // webpack 플러그인을 위한 새로운 설정 섹션

],


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}




html-webpack-plugin


웹팩이 기본으로 지원하지않는 타사 플러그인 중에서 가장 유용한 것으로 html-webpack-plugin을 꼽을수 있다.


이 플러그인은 웹팩의 번들을 모두 포함하는 최종 HTML5 파일을 자동으로 생성해준다.

이 플러그인은 컴파일할때마다 변경되는 해시를 번들 파일 이름에 추가하는 실무용(production) 빌드시 특히 더 유용하다. (없다면 최종 빌드마다 매번 수동으로 바뀐이름의 번들파일들을...)


역시나 npm을 이용해 html-webpack-plugin을 간단하게 설치한다.


npm install --save-dev html-webpack-plugin


다음으로 지금까지 사용하던 예제 프로젝트의 구조를 약간 변경해야 한다.


1. public 폴더를 제거한다. HTML5 페이지가 자동으로 생성되므로 public 폴더에 직접 만들어 놓았던 index.html 파일이 필요가 없어졌다.

또한 CSS와 웹팩을 번들로 묶으므로 public 폴더 자체가 필요가 없어진다.


2. html-webpack-plugin 이 HTML5페이지를 만들때 사용할 템플릿 HTML 파일을 만든다. 어플리케이션을 포함할 최종 HTML 페이지를 만드는 대신 "app"폴더에 템플릿으로 사용할 HTML 파일을 만든다. 템플릿 파일은 커스텀 title과 head 태그를 비롯해 필요한 모든 HTML 요소를 포함한다. 

html-webpack-plugin은 내가 만들어 놓은 HTML 템플릿을기반으로 하여 필요한 모든 css, js, 매니페스트, 파비콘 파일을 자동으로 마크업에 삽입한다.


3. webpack.config.js를 업데이트한다. 새로운 플러그인 설정과 새로운 번들파일이 놓이게될 장소 (build가 될 폴더)를 지정한다.


새로 만든 /app/index.tmpl.html 파일

<!DOCTYPE html>

<html lang="ko">

<head>

<meta charset="urf-8">

<title>Webpack Sample Project</title>

</head>

<body>

<div id="root">

</div>

</body>

</html>



업데이트 된 webpack.config.js

var webpack = require('webpack'); //webpack이 기본으로 제공해주는 plugin 사용하기위해 import

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


module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry :  './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/build', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : "style-loader!css-loader?modules!postcss-loader" //postcss 로더 추가

}

]

},


// webpack 플러그인을 위한 새로운 설정 섹션

plugins : [

new webpack.BannerPlugin("Copyright Ju sung Park inc."),

new HtmlWebpackPlugin({

template : __dirname + "/app/index.tmpl.html"    // 템플릿이 있는 경로

})

],


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


//build 폴더는 실무용 배포 구성을 만들기 전에는 생성되지 않는다. 개발 중에는 번들 파일과 생성된 HTML이 모두 메모리에서 제공된다.




HMR (Hot Module Replacement)


웹팩이 널리 알려지는 데 기여한 특성중 하나로 HMR(Hot Module Replacement)가 있다. 말 그대로 HMR은 컴포넌트를 실시간으로 저정하고 확인할 수 있게 해주는 기능으로서, 개발자가 CSS 또는 JS를 수정하면 브라우저에서 페이지를 새로 고치지 않아도 변경 사항이 즉시 반영된다.


개발자는 웹팩의 HMR 기능을 활성화 해주기만 하면 되는데 활성화 하려면 다음 두 가지 구성을 수정해야 한다.


1. 웹팩 구성(webpack.config.js)HotModulereplacementPlugin을 추가한다.


2. 웹팩 개발 서버 구성(webpack.config.js 안의 devServer 섹션)"hot" 매개변수를 추가한다. 


자바스크립트 모듈들은 기본적으로 HMR의 대상이 아닌것에 주의! 해야한다.

자바스크립트 모듈들을 개발 중에 수정된 내용이 바로바로 교체할 수 있게(Hot replaceable) 만들려면 웹팩이 제공하는 API하나를 모듈에서 구현해주어야 한다. 이 API를 직접 사용해서 구현해도 된다. 그보다는 바벨을 이용하는 것이 실용적이다.


지금까지 정리했던 것처럼 바벨은 웹팩과 함께 작업하며 자바스크립트 파일을 변환하는 역할을 해왔다.

현재 예제 프로젝트 JSX를 일반 자바스크립트로 변환하고 ES6 코드를 현재 브라우저가 이해할 수 있는 자바스크립트로 변환하도록 구성되어 있다.


바벨 플러그인을 이용하면 웹팩을 통해 리액트 컴포넌트를 수정분이 사용중 바로 교체될수 있게 만드는데 필요한 코드를 추가하고 추가 변환을 수행하게 할수있다. (웹팩이 제공해주는 HMR의 API를 바벨이 구현해주고 있다.)


다시한번 정리해보면


1. 웹팩바벨서로 다른 별개의 도구이다. (바벨도 사실 독립적인 프로그램으로 사용할수 있다고 첫번째 글에 정리했었다)


2. 두 도구는 서로 협업이 뛰어나다.


3. 웹팩도 플러그인을 지원하고 바벨또한 플러그인을 통해 확장할 수 있다.


4. HMR은 컴포넌트의 코드를 수정할 때 브라우저에서 실시간으로 컴포넌트를 업데이트할 수 있는 웹팩 플러그인이며, 인터페이스만 구현되어 있기 때문에 제대로 작동하려면 모듈에 특수한 코드를 추가해야 한다.


5. 바벨react-transform-hmr 플러그인은 자동으로 모든 리액트 컴포넌트에 필요한 HMR 코드를 삽입해준다.


이제 웹팩구성(webpack.config.js)과 따로 만들어 놓았던 바벨구성(.babelrc) 를 수정해본다.


업데이트 된 webpack.config.js

var webpack = require('webpack'); //webpack이 기본으로 제공해주는 plugin 사용하기위해 import

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


module.exports = {

devtool : 'eval-source-map',

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry :  './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/build', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : "style-loader!css-loader?modules!postcss-loader" //postcss 로더 추가

}

]

},


// webpack 플러그인을 위한 새로운 설정 섹션

plugins : [

new webpack.BannerPlugin("Copyright Ju sung Park inc."),

new HtmlWebpackPlugin({

template : __dirname + "/app/index.tmpl.html"    // 템플릿이 있는 경로

}),

new webpack.HotModuleReplacementPlugin()    //webpack HMR 지원 플러그인

],


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true,

hot : true    // 웹팩 개발 서버 구성에 추가

}

}


다음 npm을 이용해 필요한 바벨 플러그인을 설치한다.


npm install --save-dev babel-plugin-react-transform react-transform-hmr


업데이트 된 .babelrc 파일

{

"presets" : ["react", "es2015"],

"env" : {

"development" : {

"plugins" : [["react-transform", {

"transforms" : [{

"transform" : "react-transform-hmr",

"imports" : ["react"],                    // 리액트 네이티브를 이용할 때는 "react-native"

"locals" : ["module"]                    // 웹팩 HMR에 중요한 부분

}]


// 이 밖에 더 많은 변환을 배열에 추가 가능


}]]

}

}

}


다시 개발 서버를 실행하고 Greeter 모듈을 간단히 수정해보자. 브라우저를 새로 고치지 않아도 변경사항이 즉시 반영되는 것을 확인할 수 있다.




실무용 빌드


지금까지 웹팩을 이용해 프로젝트를 만들고 자바스크립트와 CSS 등의 모듈 파일들을 번들로 묶고 처리하는 개발환경을 구축해 보았다.

개발환경은 충분하지만 개발을 하고 실무(운영용)Production 에서 사용할 빌드 구성을 만들어야 하는데, 실무에서 사용하기 위해 만들어지는 번들 파일들에는 최적화, 축소, 캐싱, CSS 와 자바스크립트 파일의 분리를 비롯한 여러가지 부가적인 처리를 적용이 필요하다.


지금 까지 웹팩 구성파일(webpack.config.js) 에는 모든 설정이 다 적용되어 있다. (개발에서만 필요한 것들까지)

복잡한 설정과 구성이 필요한 프로젝트를 체계적으로 구성하고 관리하려면 웹팩 구성을 여러 파일로 분할하는 것이 좋다.

이어서 예제 프로젝트에 "webpack.production.config.js" 라는 파일을 새로 만들어 본다.


새로 만들어진 webpack.production.config.js

var webpack = require('webpack'); //webpack이 기본으로 제공해주는 plugin 사용하기위해 import

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


module.exports = {

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/build', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : "style-loader!css-loader?modules!postcss-loader" //postcss 로더 추가

}

]

},


plugins : [

new webpack.BannerPlugin("Copyright Ju sung Park inc."),

new HtmlWebpackPlugin({

template : __dirname + "/app/index.tmpl.html"    // 템플릿이 있는 경로

})

]

}


//devServer, HMR, devtool 설정이 빠짐.


위의 webpack.production.comfig.js 는 실무 빌드에 필요한 아주 기본적인 구성으로 원래 사용하던 웹팩 개발 구성(webpack.config.js)에서 devtool, devServer, HMR 구성을 제외 하고는 동일하다.

다음은 package.json 파일을 편집하여 실무용 환경에서 웹팩을 실행하고 앞서 새로 생성한 구성 파일을 할당하는 build 태스크를 만든다.


업데이트된 package.json

{

"name" : "webpack-sample-project",

"version" : "1.0.0",

"description" : "Sample webpack project",

"scripts" : {

"start" : "node_modules/.bin/webpack-dev-server --progress", (-config 옵션이 없으면 기본 webpack.config.js)

"build" : "NODE_ENV=production node_modules/.bin/webpack --config ./webpack.production.config.js --progress"

},

"author" : "",

"license" : "ISC",

"devDependencies" : {

.....

},

"dependencies" : {

...

}

}


//NODE_ENV는 Node.js가 제공해주는 현재 OS의 환경변수가 저장된 객체 process.env의 process.env.NODE_ENV 에 할당된다.

//환경변수이름으로 넘겨준 값은 process.env로 모두 접근할 수 있다.




최적화 플러그인


웹팩은 실무용 빌드를 생성하는 데 도움이되는 몇 가지 아주 유용한 최적화 플러그인을 제공한다. 또한 오픈 커뮤니티에서 제작하고 배포하여 npm을통해 설치하고 이용할 수 있는 다양한 플러그인이 있다.

다음은 실무용 빌드에 필요한 특성을 충족할 수 있는 웹팩 플러그인 이다.


OccurenceOrderPlugin : 웹팩은 모듈을 식별하기 위한 ID를 제공한다. 이 플러그인은 가장 자주 이용되는 모듈을 분석한 후 우선순위에 따라 가장 작은 ID를 할당한다.


UglifyJsPlugin : UglifyJS 는 자바스크립트 압축기/축소기다.


ExtractTextPlugin : 모든 CSS require/import 를 별도의 CSS 출력 파일로 옮겨서 자바스크립트에서 스타일을 인라인으로 포함할 필요가 없게 해준다.


이러한 플러그인을 모두 새로 만든 webpack.production.config.js 파일에 추가해 본다.

OccurrenceOrder와 UglifyJS 플러그인은 웹팩에서 기본 제공되므로 ExtractText 플러그인만 설치하고 가져오면 된다.


npm install --save-dev extract-text-webpack-plugin


업데이트 된 webpack.production.config.js

var webpack = require('webpack'); //webpack이 기본으로 제공해주는 plugin 사용하기위해 import

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

var ExtractTextPlugin = require('extract-text-webpack-plugin');


module.exports = {

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/build', // 번들 파일의 대상 경로

filename : 'bundle.js'        // 번들 파일의 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : ExtractTextPlugin.extract({

fallback:'style-loader',

use : [

             { loader : 'css-loader', options: { importLoaders:1, modules : true } },

        'postcss-loader'

 ]

})

}

]

},


plugins : [

new webpack.BannerPlugin("Copyright Ju sung Park inc."),

new HtmlWebpackPlugin({

template : __dirname + "/app/index.tmpl.html"    // 템플릿이 있는 경로

}),

new webpack.optimize.OccurrenceOrderPlugin(),

new webpack.optimize.UglifyJsPlugin(),

new ExtractTextPlugin("style.css")    // 이제 CSS 파일이 style.css 파일로 따로 만들어져 자바스크립트 번들처럼 배포됨.

]

}




캐싱


인터넷 인프라에서는 거의 모든 곳 (CDN, ISP, 네트워킹 장비, 웹 브라우저, 프록시 등)에 캐싱을 활용한다.

이러한 캐싱 인프라를 제대로 활용하는 간단하고 효과적인 방법 중 하나는 파일 내용 변화를 반영해 파일 이름을 고유하게 지정하는 것이다. 즉, 파일 내용이 바뀌면 파일 이름도 수정되어야 한다. 이렇게 하면 원격 클라이언트가 콘텐츠의 복사본을 유지하고 파일명이 다른 새로운 콘텐츠만을 요청할 수 있다.


웹팩은 [name], [id], [hash], [chunkhash] 같은 특수한 문자열 조합을 출력 파일 이름 구성에 추가하는 방법으로 번들 파일의 해시를 파일 이름에 추가할수 있다.


업데이트 된 webpack.production.config.js

var webpack = require('webpack'); //webpack이 기본으로 제공해주는 plugin 사용하기위해 import

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

var ExtractTextPlugin = require('extract-text-webpack-plugin');


module.exports = {

context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)

entry : './main.js',    // 엔트리 파일 위치.

output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐

path : __dirname + '/build', // 번들 파일의 대상 경로

filename : '[name]-[hash].js'        // 특수한 문자열은 조합한 번들파일 이름

},


module : {

loaders : [

{

test : /\.json$/,

loader : "json-loader"

},

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

//query 구문이 제거됨 .babelrc 로 이동

},

{

test : /\.css$/,

loader : ExtractTextPlugin.extract({

fallback:'style-loader',

use : [

             { loader : 'css-loader', options: { importLoaders:1, modules : true } },

        'postcss-loader'

 ]

})

}

]

},


plugins : [

new webpack.BannerPlugin("Copyright Ju sung Park inc."),

new HtmlWebpackPlugin({

template : __dirname + "/app/index.tmpl.html"    // 템플릿이 있는 경로

}),

new webpack.optimize.OccurrenceOrderPlugin(),

new webpack.optimize.UglifyJsPlugin(),

new ExtractTextPlugin("[name]-[hash].css")    // 이제 CSS 파일이 style.css 파일로 따로 만들어져 자바스크립트 번들처럼 배포됨.

]

}



웹팩은 모든 프로젝트 모듈을 처리하고 번들로 묶는 유용한 도구이다. 사실상 거의 표준으로 인정받고 있다.


웹팩 공식 문서 에서 자세하고 많은 내용을 찾을수 있다.















참고.


프로 리액트 - React.js를 이용한 모던 프런트엔드 구축.

0 Comments
댓글쓰기 폼