webpack의 내용을 정확히 학습하기 위해 작성하였습니다.
- webpack과 babel 기본 설명 -> webpack & babel
Webpack을 사용하는 이유
- 여러개의 파일을 하나로 묶어준다.
Webpack을 사용하면 의존 모듈이 하나의 파일로 번들링되므로 별도의 모듈 로더가 필요 없습니다. 그리고 다수의 JS파일을 하나의 파일로 번들링하므로 HTML파일에서 script 태그로 다수의 JS파일을 로드해야 하는 번거로움도 사라진다. - http 요청이 비효율적이기 때문이다.
웹 페이지는 수많은 파일들을 받아와야 하는데 http/1.1에서는 커넥션 하나를 열어 하나씩 요청을 보내야 한다(요청이 많을수록 비효율적) 때문에 하나의 파일로 합쳐주어 요청 횟수를 줄이고 속도를 향상시킨다.(여러 개로 나누는 것도 가능)
하단의 그림처럼 Webpack은 여러 파일들을 하나로 합쳐주면서 크로스브라우징 이슈도 대응한다.
크로스 브라우징 : 웹 페이지 제작 시에 모든 브라우저에서 깨지지 않고 의도한 대로 올바르게(호환성) 나오게 하는 작업을 말한다. 원인은 브라우저마다 랜더링 엔진이 다르기 때문이다.
Webpack의 핵심 철학
- 모든것은 module 이다.
JS파일들은 모듈이 될 수 있으므로 다른 모든 것(CSS, image, HTML ...)등 또한 모듈이 될 수 있다. 이러한 것들을 require를 활용해 불러올 수 있다. - 필요한것은 필요할때에 불러져야 한다.
webpack은 코드 분할과 다중 "bundle"파일 같은 다양한 기능을 가지고 있어 필요할 때에 앱이 비동기적으로 로드하게 해준다.
설정 파일 구분
WebPack4 가 나오면서 개발시 사용하는 Development 모드와 파일을 압축하여 변수 이름 들을 읽기 어렵게 축약해 놓은 Production 모드가 생겼다. 한개의 설정파일을 생성하고 공유하면서 각 빌드 별로 분기를 만들어 설정해줄 수도 있지만 파일을 개발용, 배포용으로 나누어 사용하는걸 권장한다고 한다.
WebPack파일을 3가지로 나누어 개발용, 배포용, 공용으로 만들어준다. 나눈 후 공통으로 쓰이는 부분을 WebPack Merge를 사용해 분리하여 사용한다.
- webpack.common.js
- webpack.dev.js
- webpack.prod.js
흔히 webpack.config.js 하나의 파일을 사용하는 방법을 공부했었는데 실제 개발중에는, 개발용 설정과 빌드용 설정을 나누어서 사용하는 경우가 발생했습니다. 그에 따른 정리를 시작해보자 합니다.
개발용 설정은 webpack-dev-server 설정 및 uglify(압축, 즉 webpack을 활용한 build) 설정을 뺍니다.
빌드용 설정은 uglify을 추가하고 webpack-dev-server는 빼는 등의 설정입니다.
Developement(개발모드) VS Production(배포모드)
개발모드와 배포모드 사용 정리
Webpack 공식문서를 살펴보니 수 많은 기능을 가지고 있는 것을 확인했습니다. 필요한 기능은 공식문서를 참조하시면 좋을 것 같습니다. Webpack 공식문서
일반적으로 대부분의 프로젝튼느 2가지의 Webpack 설정 파일을 가지고 사용합니다.
그리고 bundels 파일을 만들기 위해서 package.json안에 스크립트를 다음과 같이 작성해야 합니다.
“scripts”: {
// 개발용 webpack 실행
// "dev" : "webpack-dev-server" 와 같이 사용하기도 한다.
“dev”: “webpack-dev-server --open --config webpack.dev.js”
// 배포용 build
“build”: “webpack --config webpack.config.prod.js”,
}
webpack CLI(Command Line Interface) VS webpack-dev-server
Webpack은 2가지 인터페이스를 제공하는 점을 유의해야 합니다.
- Webpack CLI toole - 기본 인터페이스(Webpack이 자동으로 설치한다.)
- webpack-dev-server - Node.js server 사용(Node.js가 존재해야 한다.)
Webpack CLI(배포와 빌드에 사용, webpack 커맨드라인 인터페이스)
이 도구는 CLI를 사용하거나 설정파일(default: webpack.config.js)을 통해 bundle을 위하여 Webpack에 옵션을 제공합니다.
webpack-dev-server (실시간 리로드 기능을 가진 개발 서버 제공)
webpack-dev-server는 nodeJS(express)서버, 즉 8080 포트로 러닝합니다. 서버는 내부적으로 Webpack을 호출하며 브라우저 리로딩(실시간 로딩), "Hot Module Replacement"와 같은 추가적인 기능을 사용할 수 있는 이점이 있습니다.
inline, hot 과 같은 옵션은 오로지 webpack-dev-server에만 있다는 것에 주목할 필요가 있으며 hide-modules은 CLI에만 있는 옵션입니다.
webpack-dev-server의 자세한 설명 && 자동적 갱신 Refresh --> webpack-dev-server
"hot" Vs "inline" webpack-dev-server options
inline 은 전체 페이지에 대한 실시간 리로딩(“Live Reloading”) 옵션이며, hot 은 컴포넌트가 수정 될 경우 그 수정된 부분만 리로드 해주는 부분 모듈 리로딩(“Hot Module Reloading”) 옵션입니다. 만약 두개 옵션을 모두 지정할 경우 “Hot Module Reloading”이 처음 발생하며 그리고 “Hot Module Reloading”이 안되면 전체 페이지 로딩을 합니다.
//1. 페이지를 로딩하지 않는다.
$ webpack-dev-server
//2. 전체 페이지를 로딩 한다.
$ webpack-dev-server --inline
//3. 부분 로딩 또는 전체 페이지 로딩
$ webpack-dev-server --inline --hot
Hot Module Replacement : HMR은 프로덕션용이 아니므로 개발용으로만 사용, 모든 종류의 모듈을 새로고침 할 필요 없이 런타임에 업데이트 할 수 있습니다. HMR
Inline 모드 : 작은 웹팩개발서버 클라이언트엔트리가 번들에 추가가 되어서 바뀔때마다 페이지를 갱신합니다.
webpack-dev-server로 옵션 전달 방법
webpack.config.js를 통해서 devServer 객체를 사용
devServer: {
inline: true,
hot:true
}
단순 CLI 옵션 - package.json
//package.json {
scripts: {
“start”: “webpack-dev-server --hot --inline”
}
}
devServer 설정이 안될 경우가 존재하기 때문에 CLI 옵션을 좀 더 선호한다.
entry -- String VS Array VS Object
“entry”는 root 모듈의 위치 또는 시작 지점이라고 Webpack이 말하더군요. “entry”는 String, Array, Object 형태로 만들 수 있습니다. 이것이 바로 혼란스러운 점인데 다른 타입은 결국 다른 목적에 사용된다고 생각하면 됍니다. 만약 당신이 시작지점이 1개라면 다음과 같은 output format을 사용할 수 있습니다.
entry - Array
의존성이 없는 여러 개의 파일을 사용하고 싶다면 Array형식으로 사용하면 된다. 예를 들어 "googleAnalystic.js"파일을 HTML안에 필요로 한다면, 당신은 "bundle.js"마지막에 붙여서 output이 가능합니다.
entry - object
SPA가 아니라 다중 페이지 어플리케이션을 개발한다면 entry-object를 사용하여 한번에 다중 bundle을 만들어서 사용할 수 있습니다. 아래 설정 파일은 2개의 bundle JS파일을 생성합니다. (indexEntry.js, profileEntry.js가 나오며 index.html, profile.html에 각각 사용할 수 있습니다.)
Usage:
//profile.html
<script src=”dist/profileEntry.js”></script>
//index.html
<script src=”dist/indexEntry.js”></script>
Note : "entry"의 객체 key가 파일 이름으로 매핑된다.
output -- "path" VS "publicPath"
“output” 은 어디, 그리고 어떻게 결과 파일이 저장되는지에 대한 것이다. “output”은 ‘path’와 ‘publicPath’ 2가지 속성이 있어서 매우 헷갈립니다.
- path: 어디에 결과가 저장되는지에 관한 것
- publicPath : 배포 빌드 할 때 Webpack plugins(url-loader, file-loader 같은..) CSS나 HTML파일 안에 URL들을 업데이트 해주기 위한 것
예를 들어, 당신의 CSS파일 안에 url을 localhost에서 ./test.png와 같이 사용합니다. 그러나 배포모드에서는 test.png는 CDN이나 다른 지정된 경로에 위치해있을 것 입니다. 그래서 수동으로 ./test.png의 url을 수정 해주어야 배포 모드에서 올바른 위치에 파일에 접근 할 수 있다. 수동으로 수정하지 않고 Webpack 'publicPath'를 사용하면 수많은 플러그인과 다수의 CSS, HTML파일안에 URL들을 자동으로 업데이트 해줍니다.
// 결과
// Development: Both Server and the image are on localhost
.image {
background-image: url(‘./test.png’);
}
// Production: Server is on Heroku but the image is on a CDN
.image {
background-image: url(‘https://someCDN/test.png’);
}
Loaders And Chaining Loaders
“Loaders”는 JS,CSS와 같은 브라우저 허용 포맷과 같은 다양한 타입의 파일을 ‘load’ 또는 ‘import’ 하게 도와주는 추가 node modules입니다. 게다가 “Loaders”는 require 또는 ES6의 import 를 JS파일을 가져올 수 있게 해줍니다. 예를 들어 당신은 ES6로 쓰여진 JS를 변환해주는 babel-loader를 사용 할 수 있습니다.
module: {
loaders: [{
test: /\.js$/, // Test for ".js" file, if it passes, use the loader
exclude: /node_modules/, // Exclude node_modules folder
loader: ‘babel’ // use babel (short for ‘babel-loader’)
}]
Chaining Loaders (오른쪽에서 왼쪽방향으로 실행된다.)
다중 “Loaders”는 연결하고, 같은 파일 타입에서 작동할 수 있게 해줍니다.(Multiple Loaders can be chained and made to work on the same file type) “!” 을 사용하여 오른쪽에서 왼쪽 방향으로 작업을 수행합니다.
예를 들어 우리는 “myCssFile.css”를 가지고 있으며, 그 파일을 HTML안에로 넣고 싶을 때 우리는 css-loader, style-loader 인 2개의 loader로 진행 할 수 있습니다.
module: {
loaders: [{
test: /\.css$/,
loader: ‘style!css’ <--(short for style-loader!css-loader)
}]
- Webpack은 모듈안에 의존적인 CSS파일들을 검색한다. webpack은 require(‘myCssFie.css’)을 가지고 있는지 JS파일을 체크한다. 만약 찾았다면, 최초로 css-loader를 수행한다.
- css-loader는 모든 CSS와 그안에 의존적인 다른 CSS(ex: import otherCSS) 를 JSON파일로 로드한다. 그후 Webpack은 결과들을 style-loader로 보낸다.
- style-loader 는 JSON을 받고,tag 를 추가하고, index.html 파일안에 tag를 삽입한다.
.babelrc.file
babel-loader presets을 통해 ES6 에서 ES5 로 어떻게 변환 해야 하는지 그리고 React JSX 에서 JS 어떻게 파싱 하는지 대해 설정을 할 수 있게 해줍니다.
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel',
query: {
presets: ['react', 'es2015']
}
}
]
}
하지만 대부분에 큰 프로젝트에서는 babel 설정이 굉장히 방대할 수가 있습니다. 그래서 당신은 .babelrc 설정파일을 통해 babel-loader 설정을 대신 할 수 있습니다. 만약 .babelrc 파일이 있다면 babel-loader 는 자동으로 읽어들입니다.
Usage:
//webpack.config.js
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel'
}
]
}
//.bablerc
{
“presets”: [“react”, “es2015”]
}
Plugins
Plugins는 보통 결과물(bundle)에 작동하는 추가적인 node_modules 입니다.
예를 들어 uglifyJSPlugin은 파일 사이즈를 줄이고, minimized를 한 bunlde 파일을 줍니다.
유사하게 extract-text-webpack-plugin 는 내부적으로 css-loader, style-loader를 사용하여 한곳에 CSS파일을 수집하고 외부 style.css 파일로 결과를 추출 하여 index.html 안에 style.css 를 삽입 하면 됩니다.
//webpack.config.js
//Take all the .css files, combine their contents and it extract them to a single "styles.css"
var ETP = require("extract-text-webpack-plugin");
module: {
loaders: [
{test: /\.css$/, loader:ETP.extract("style-loader","css-loader") }
]
},
plugins: [
new ExtractTextPlugin("styles.css") //Extract to styles.css file
]
}
만약 HTML 안에 style 태그로 CSS 를 하고 싶다면 extract-text-webpack-plugin 사용하지 않고 CSS와 Style loaders를 아래와 같이 사용하면 됩니다.
module: {
loaders: [{
test: /\.css$/,
loader: ‘style!css’ <—(줄임말 for style-loader!css-loader)
}]
Loaders VS Plugins
Loaders는 개인적인 파일 레벨에서나, bundle이 생성되기 전에 작동하며 Plugins은 bundle 이나 chunk 레벨 그리고 bundle이 생선 된 후에 작동합니다.
Resolving File Extensions
대부분의 Webpack 설정 파일은 아래와 같이 빈 string 을 포함한 resolve extensions 라는 속성을 가지고 있다. 빈 string 은 require(‘./myFile’) 과 같은 빈 확장자를 import하게 도와주는 역할입니다.
{
resolve: {
extensions: [‘’, ‘.js’, ‘.jsx’]
}
}
서로 다른 설정 파일 생성하기
적용 방법은 매우 간단합니다. 실제로 설정파일을 나누어서 작성하면 됩니다.
개발용 설정
// dev config, `webpack.config.dev.js`
const path = require('path');
const webpack = require('webpack');
module.exports = {
devtool: 'inline-source-map',
entry: [
'./assets/js/reactComponents/about.js'
],
output: {
path: path.join(__dirname + '/_site/assets/js/reactComponents/'),
publicPath: '/assets/js/reactComponents/',
filename: 'about.js'
},
plugins: [
// webpack-dev-server enhancement plugins
new webpack.HotModuleReplacementPlugin()
],
devServer: {
hot: true,
port: 4000,
contentBase: path.join(__dirname, '_site')
},
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/],
use: [{
loader: 'babel-loader',
options: { presets: ['es2015', 'react'] }
}],
}
]
}
};
배포용 설정
// prod config, `webpack.config.prod.js`
module.exports = {
entry: './assets/js/reactComponents/about.js',
output: {
path: __dirname + '/_site/assets/js/reactComponents/',
filename: 'about.js'
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
}
}),
new webpack.optimize.OccurenceOrderPlugin()
],
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
cacheDirectory: true,
presets: ['es2015', 'react']
}
}
]
}
};
서로 다른 설정 파일 사용하기
필요에 따라 구분된 설정파일을 사용해서 webpack이 구동되게 합니다.
CLI로 common을 바로 입력하기
// dev 설정으로 webpack
$ webpack --config webpack.config.dev.js
// prod 설정으로 webpack
$ webpack --config webpack.config.prod.js
npm에 등록해서 사용
node에 npm을 사용하는 경우 더 간단하게 사용 가능하며
특히 dev는 webpack-dev-server 을 사용하게 하고, prod는 webpack 을 사용 할 수 있습니다.
npm 의 script 을 사용 하는 형태입니다.
package.json
"scripts": {
"start": "webpack-dev-server --config webpack.config.dev.js",
"build": "webpack --config webpack.config.prod.js"
},
사용
// dev 설정으로 실행
$ npm run start
// prod 설정으로 실행
$ npm run build
'REACT' 카테고리의 다른 글
npx란?? (0) | 2022.03.30 |
---|---|
State and Lifecycle (0) | 2022.03.28 |
babel과 webpack (0) | 2022.01.19 |
Components와 Props (0) | 2022.01.15 |
엘리먼트 렌더링이란?? (0) | 2022.01.15 |