티스토리 뷰

Webpack - 웹팩 환경 세팅하기


| 시작하기에 앞서,


create-react-app 명령어로 리액트 프로젝트를 만들면 자동으로 웹팩 설정이 잡혀서 프로젝트가 만들어져서, 웹팩 관련한 설정을 알기가 쉽지 않다. 예전에는 create-react-app이 없을때는 리액트 프로젝트를 하기위해 웹팩 설정을 일일히 다해줬었다고 한다. 웹팩 관련한 설정은 어떤것이 있는지, 또 웹팩에 대해 더 상세히 파헤쳐보고자 직접 환경을 세팅해 보고 creact-react-app으로 만든 프로젝트를 eject 시켜 비교해보자.


http://jusungpark.tistory.com/52 참고


프로젝트 시작하기

  • 예제 프로젝트를 시작하기에 앞서 package.json 파일을 먼저 만들어준다.package.json 파일은 내가 만들 프로젝트 설정과 사용하는 패키지들 등의 다향한 정보를 포함하는 표준 npm 매니페스트이며, 개발자가 패키지 의존성을 지정하고 사용자가 실행할수 있는 스크립트 태스크들을 정의할 수 있게 해준다.

npm init
  • 웹팩을 프로젝트 의존성으로 추가하고 설치한다.


npm install --save-dev webpack
  • 프로젝트 구조를 만들자.

project

— node_modules

— app

— greeter.js

— main.js

— public

— index.html

— package.json

  • index.html에 내용을 넣어준다.

index.html


<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8"/>
   <title>Webpack Sample Project</title>
 </head>
 <body>
   <div id="root"></div>
   <script src="./bundle.js"></script>
 </body>
</html>

main.js


var greeter = require('./greeter.js'); //웹팩은 commonJS 모듈 require을 기본적으로 지원한다
document.getElementById('root').appendChild(greeter());

greeter.js


module.exports = function() {
 var greet = document.createElement('div');
 greet.innerHTML = "Hi there and greetings !";
 return greet;
}

webpack.config.js


  • 웹팩은 다양한 고급 옵션을 제공하며, 로드한 모듈들에 로더와 플러그인을 이용해 변환을 적용할 수 있게 해준다. 명령줄에서 모든 옵션을 지정하고 웹팩을 실행하는 것도 가능하지만, 작업하기 불편하고 매번 수동으로 입력하면 잘못된 입력의 가능성이 높아진다. 때문에 빌드와 관련된 모든 정보를 넣을 수 있는 간단한 자바스크립트 모듈인 구성 파일을 따로 정의하는 것이 좋다. 계속해서 예제 프로젝트의 구성 파일로 사용할 webpack.config.js 파일을 만들어 본다. 웹팩 구성 파일은 최소한 아래 처럼 엔트리 파일과 번들로 묶일 파일의 대상을 지정해야 한다.

module.exports = {
   context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)
   entry : './main.js',    // 엔트리 파일 위치.
   output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐
   path : __dirname + '/public', // 번들 파일의 대상 경로
   filename : 'bundle.js'        // 번들 파일의 이름
}
}


프로젝트 첫 빌드하기

  • 이제 빌드를 하기 위한 초기 설정이 끝났다. 아래 명령어로 빌드를 해보자.


node_modules/.bin/webpack

  • 처음 번들링이 시작되는 entry 포인트를 파악할 수 있고, 어떤 파일들이 번들링 되는지 파악이 가능하고 웹팩이 모듈 파일들을 bundle.js로 묶은 것을 확인 할 수 있다. 이제 index.html 파일을 열어보자.

  • 모듈이 잘 번들링 되어서 위와 같은 결과를 확인할 수 있다. 
태스크 실행 스크립트 추가하기
  • npm을 태스크 러너로 사용해 긴 스크립트를 npm start, npm run {지정한 이름} 과 같은 간단한 명령으로 대체할 수 있다. package.json 파일 안에 scripts 섹션을 추가하면 된다.
{
 "name": "ls",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "start" : "node_modules/.bin/webpack"//스크립트를 추가한다.,
   "test": "echo \"Error: no test specified\" && exit 1"
},
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "webpack": "^4.5.0",
   "webpack-cli": "^2.0.14"
}
}


소스맵 생성


웹펙을 구성하는데 몇 가지 옵션이 사용되는데, 가장 중요하고 많이 사용되는 소스맵 옵션이다.


패키지의 모든 자바스크립트 모듈을 하나 또는 여러개의 모듈들이 합쳐진 번들 파일로 만들어 브라우저에서 사용하면 많은 장점이 있지만 브라우저에서 디버깅할 때 원래 어떤 파일의 어떤 부분에서 문제가 생겼는지 찾기가 어렵다는 한 가지 분명한 단점이 있다.

이 문제를 해결하기 위해 웹팩의 소스맵(soruce map)을 이용할 수 있다.

소스맵은 번들 파일 내의 코드를 원래 소스 파일로 연결함으로써 브라우저 인스펙터에서 코드를 일고 디버그하기 쉽게 만들어 준다. 


표로 몇가지 빌드 시간이 가장 느린 것부터 빠른 것 순으로 옵션을 정렬해본다면 아래와 같다.


 devtool 옵션 

 설명 

 source-map

 모든 기능이 포함된 완전한 소스맵을 별도의 파일로 생성한다. 

 이 옵션은 최고 품질의 소스맵을 생성하지만 빌드 프로세스가 느려진다. 

 cheap-module-source-map

 별도의 파일에 컬럼 매핑을 제외한 소스 맵을 생성한다.

 컬럼 매핑을 생략하면 빌드 속도는 향상되지만 디버깅할 때는 약간의 불편함이 있다.

 브라우저 개발자 툴은 원래 소스 파일의 행만 가리킬 수 있으며,

 특정 컬럼(또는 문자)을 가리킬 수 없다.

 eval-source-map

 "eval"을 사용해 동일한 파일 안에 전체 소스맵과 소스코드 모듈을 중첩해 번들로 만든다.

 이 옵션을 사용하면 빌드 시간에 대한 부담 없이 모든 기능이 포함된 소스맵을 생성할 수 있지만

 자바스크립트를 실행할 때 성능과 보안이 저하되는 단점이 있다.

 즉, 개발 중에는 유용하지만 실무 버전을 빌드할 때는 사용하지 말아야 한다.

 cheap-module-eval-source-map

 빌드 중에 소스 맵을 생성하는 가장 빠른 방법이다. 

 생성되는 소스맵에는 번들 자바스크립트 파일이 칼럼 매핑을 제외하고 동일하게 인라인으로

 포함된다. 이전 옵션과 마찬가지로 자바스크립트 실행 시간에 부정적인 영향을 미치므로

 실무용 번들을 생성할 때는 적합하지 않다. 

표에 정리한 옵션들 이외의 옵션들은 웹팩 공식홈페이지에서 확인할 수 있다.


맨 위 옵션은 약간의 단점을 감수하고 최상을 결과를 출력하는 반면 맨 아래 옵션은 빌드 시간을 단축하기 위해 자바스크립트 실행하는 동안 단점을 감수해야 한다.


기능에 대해 알아보고 있거나 중소규모 프로젝트에 적용할 때는 "eval-source-map"이 적절한 옵션이다. 실무용 번들을 빌드하는 webpack.config.js를 별도로 가져갈 수 있으므로 개발중에만 적절하게 사용할 수 있다.



출처: http://jusungpark.tistory.com/52 [정리정리정리]


  • 아래와같이 source map 설정을 해주자. 참고로 create-react-app 으로 만든 프로젝트는 dev환경에서는 cheap-module-source-map, prod 환경에서는 source-map을 쓰고있는것을 확인할 수 있었다.

module.exports = {
   devtool : 'eval-source-map',// 소스맵 추가
   context : __dirname + '/app',      
   entry : './main.js',  
   output : {                      
   path : __dirname + '/public',
   filename : 'bundle.js'      
}
}

웹팩 개발 서버

  • 웹팩은 로컬 개발을 위한 웹팩 개발 서버라는 서버를 옵션으로 제공한다.

  • 웹팩 개발 서버는 정적 파일을 제공하며, 웹팩 구성에 따라 스크립트들을 빌드한 후 메모리에 저장했다가 개발자가 소스 파일을 수정하면 자동으로 브라우저를 새로 고치는 간단한 node.js 익스프레스 앱이다.

  • 웹팩 개발 서버는 별도의 npm 모듈이므로 프로젝트의 의존성으로 설치해야 이용할 수 있다.

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

웹팩 개발 서버는 webpack.config.js 구성 파일의 별도 "devserver" 항목으로 구성할 수 있다.


 devserver 설정

 설명

 contentBase

 기본적으로 웹팩 개발 서버는 프로첵트 루트에 있는 파일을 서비스 한다.

 다른 폴더 (ex. 예제에서 사용하는 public 폴더)의 파일을 서비스 하려면 이 설정으로 특정 contentBase를

 잡아주어야 한다.

 port

 사용할 포트를 지정하며, 생략할 경우 기본값은 "8080"이다

 inline

 "true"로 설정하면 조그만한 클라이언트 엔트리를 번들에 삽입해 페이지가 변경되면 새로 고침을 수행한다.

 colors

 서버가 터미널에 출력하는 내용에 색상을 지정한다. 

 historyApiFallback

 HTML5 히스토리 API를 이용하는 단일 페이지 애플리케이션을 개발할 때 유용한 옵션으로서 "true"로 설정하면

 기존 스크립트와 매핑되지 않는 웹팩 개발 서버에 대한 모든 요청이 곧바로 /로 (index.html 파일로) 라우팅된다.



출처: http://jusungpark.tistory.com/52 [정리정리정리]


  • 아래와같이 dev-server 관련 설정을 추가한다.


module.exports = {
   devtool : 'eval-source-map',
   context : __dirname + '/app',  
   entry : './main.js',    
   output : {                      
   path : __dirname + '/public',
   filename : 'bundle.js',
  },      
   devServer : { // devserver 설정을 추가해준다.
     contentBase : "./public",
     port : 8080,
     historyApiFallback : true,
     inline : true
  }
}

  • webpack-dev-server를 실행해 서버를 시작해보자.


node_modules/.bin/webpack-dev-server

  • 잘 실행되는 것을 확인할 수있다.


| 로더

  • 웹팩의 가장 흥미로운 기능 중 하나로 로더(Loader)가 있다.

  • 로더를 이용하면 외부 스크립트와 도구를 통해 소스 파일을 전처리하고 다양한 변경과 변환을 적용할 수 있다. 이러한 변환은 JSON 파일을 빌한 자바스크립트로 구문 분석할수 있게 해주거나, 차세대 자바스크립트 (ES6, ES7) 코드를 현재 브라우저가 이해할 수 있는 일반 자바스크립트(ES5)로 변환해 먼저 이용할 수 있게 하는등 다양한 상황에 유용하게 사용된다.

  • 또한 로더는 리액트의 JSX를 일반 자바스크립트로 변환하는 데도 이용할 수 있다. (리액트 이외에도 알맞은 해석구문의 로더만 있다면 일반 자바스크립트로 변환시킬수 있다.)


로더는 별도로 설치해야 하며, webpack.config.js의 "module" 항목에서 구성해야 한다.


 로더 구성 설정 

 설명 

 test 

 이 로더로 처리하기 위해 일치해야 하는 파일 확장자를 비교하는 정규 표현식 (필수)

 loader

 로더의 이름 (필수)

 include/exclude

 로더가 명시적으로 추가하거나 무시할 폴더와 파일을 수동으로 지정하는 옵션

 query

 로더로 추가 옵션을 전달하는 데 이용되는 쿼리 설정

  • JSON로더를 이용하여 예제 어플리케이션을 수정해 본다.


npm install --save json-loader //Json 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 : {
   rules : [
      {
         test : /\.json$/,
         loader : "json-loader"
      }
    ]
  },
   devServer : {
     contentBase : "./public",
     port : 8080,
     historyApiFallback : true,
     inline : true
  }
}

config.json


{
"greetText" : "Hi there and greetings from JSON!"
}

Greeter.js


var config = require('./config.json');    //Json Loader 로 인해 webpack이 json형식의 파일도 모듈로 가져올수 있게 됬음.

module.exports = function() {
 var greet = document.createElement('div');
 greet.innerHTML = config.greetText;//업데이트
 return greet;
}

그런데 아래와 같은 오류가 발생했다. 알고보니 webpack 4 부터는 json 형식 파일을 require 해주는것이 기본스펙이 되어서 json loader를 불러오지 않아도 되서 오류가 발생하고 있는 것이었다. https://github.com/webpack-contrib/file-loader/issues/259 참고


  • 따라서 아래와 같이 json-loader 부분을 주석처리 해주니 정상적으로 실행되었다. webpack 4 버전으로 업데이트 되면서 여러가지가 바뀐것 같다. 참고로 webpack 4 이전버전에서는 rules 말고 loader라는 이름이었는데 4에 오면서 바뀐것 같다. https://stackoverflow.com/questions/49370849/configuration-module-has-an-unknown-property-loaders 참고

module.exports = {
   devtool : 'eval-source-map',
   context : __dirname + '/app',      // 모듈들이 존재하는 기준 경로 (필수는 아님 없다면 매번 entry 에 풀경로를 적어줘야함)
   entry : './main.js',    // 엔트리 파일 위치.
   output : {                       // output의 엔트리가 배열이면 차례대로 엔트리가 만들어짐
   path : __dirname + '/public', // 번들 파일의 대상 경로
   filename : 'bundle.js',
  },
  // module : {
  // rules : [
  //     {
  //       test : /\.json$/,
  //       loader : "json-loader"
  //     }
  //   ]
  // },
   devServer : {
     contentBase : "./public",
     port : 8080,
     historyApiFallback : true,
     inline : true
  }
}

| 바벨


아래 내용은 다른 블로그에 정리가 잘되어 있어 그대로 가져왔다.


http://jusungpark.tistory.com/52 참고


바벨은 자바스크립트 컴파일 도구 지원을 위한 플랫폼으로서 다음과 같은 기능을 제공하는 강력한 도구다.


1. 아직 일부 브라우저에서 지원되지 않은 자바스크립트의 다음 버전(ES6, ES7 등)을 이용할 수 있게 해준다.


2. 리액트의 JSX와 같은 자바스크립트 구문 확장을 이용할 수 있게 해준다. 


바벨은 독립 실행형 도구이다.

하지만 로더로도 이용할 수 있으며, 웹팩과 아주 아주 잘 어울린다.



바벨의 설치와 구성


바벨은 모듈형 구조를 띠며, 다양한 npm 모듈로 배포된다.

핵심 기능은 "babelcore" npm 패키지로 제공되며, 웹팩과의 통합은 "babel-loader" npm 패키지로 제공된다.

또한 코드에서 이용하려는 기능과 확장 유형마다 각기 다른 패키지를 설치해야 한다.

많이 사용되는 패키지로는 ES6 컴파일을 위한 "babel-preset-es2015"  리액트의 JSX 지원을 위한 "babel-preset-react" 가 있다.


이러한 패키지를 모두 개발 의존성으로 설치한다.


npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react


다른 웹팩 로더와 마찬가지로 바벨도 웹팩 구성 파일의 "module" 섹션에서 구성할 수 있다.


업데이트 된 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 : {

rules : [

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader",

query : {

presets : ['es2015','react']

}

}


]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


이제 리액트의 JSX 자바스크립트 확장 구문은 물론 ES6 모듈과 구문을 이용할 수 있다.

이러한 기능을 모두 이용하도록 예제 프로젝트를 리팩터링 해본다.


리액트를 이용하기 위해 React  React-DOM을 설치한다. (react Loader 와 헷갈리면 안된다)


npm install --save react react-dom


업데이트 된 Greeter.js

import React, {Component} from 'react';  // 설치한 react

import config from './config.json';


class Greeter extends Component{

render() {

return (

<div>

{config.greetText}

</div>

);

}

}

export default Greeter

//ES6 모듈 정의를 이용하고 리액트 컴포넌트를 반환하도록 구성



업데이트 된 main.js

import React from 'react';

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

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

//ES6모듈 정의를 이용하고 리액트 컴포넌트를 렌더링 하도록 구성




바벨 구성 파일


바벨을 webpack.config.js에서 완전히 구성할 수도 있지만, 바벨은 구성 설정과 옵션, 조합이 매우 다양하기 때문에 동일한 파일 안에서 모든 구성을 처리하려면 지나치게 복잡해질 수 있다.

이 때문에 ".babelrc"라는 별도의 바벨 리소스 구성을 만드는 경우가 많다.


지금까지 사용한 바벨 전용 구성은 프리셋 정의뿐이므로 이 항목만 포함 하는 바벨 전용 구성 파일을 따로 만드는 것이 과하게 보일 수 있지만 이후 계속해서 추가 적으로 웹팩과 바벨 기능을 사용할 것이므로 미리 따로 만들어 놓는다.



업데이트 된 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 : {

rules : [

{

test : /\.js$/,

exclude : /node_modules/,

loader : "babel-loader"

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

}


]

},


devServer : {

contentBase : "./public",

port : 8080,

historyApiFallback : true,

inline : true

}

}


.babelrc 파일 생성 (webpack 이 .babelrc 파일을 자동으로 인지한다)

{

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

}


이번 장에서는 기본적인 웹팩 개발 환경 구성을 다루었다.



출처: http://jusungpark.tistory.com/52 [정리정리정리]


| 마치며,


시간이 좀 걸리긴 했지만, 기본적인 웹팩 환경설정을 차근차근 학습해보면서, 어떻게 구성되어있는지 대강 파악을 할 수 있었다. 예전에는 리액트 프로젝트에서 webpack 파일에서 이 부분이 어떤걸 의미하는지 전혀 파악이 되지 않았었다면 이제는 어느정도 파악은 할 수 있을 것 같다. 또한 바벨이라는 중요한 개념에 대해서 다시한번 학습해보는 좋은 기회가 되었다. 그리고 들었던 생각은 create-react-app 만든사람에게 정말 감사하다는 생각이다..ㅎ 기본적인 웹팩 설정만 했는데도 웹팩 설정이 정말 빡셌기 때문이다 하핳........ create-react-app 명령어만 치면 이런 작업들을 이제 해도되지 않으니 말이다 ㅋㅋㅋㅋ

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함