플러그인

로더가 파일단위로 처리하는 반면 플러그인은 번들된 결과물을 처리할때 사용한다. 번들된 자바스크립트를 난독화 하거나 특정 텍스트를 추출할하는 용도로도 사용이 가능하다.


커스텀 플러그인 만들기

로더는 함수 기반이었지만 플러그인은 클래스 기반으로 작성한다.

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
31
// plugin.js

class MyPlugin {
apply(compiler) {
// 플러그인이 완료 된 후 실행될 콜백함수를 지정한다.
compiler.hooks.done.tap('My Plugin', stats => {
console.log('MyPlugin: done');
});

// 실제로 플러그인이 처리할 코드가 들어가는 부분이다.
compiler.plugin('emit', (compliation, callback) => {
// compliation.assets['main.js'].source();를 통해서 번들링 된 파일을 가져올수 있다.
const source = compliation.assets['main.js'].source();

// source 메소드를 재정의 하고 있다.
compliation.assets['main.js'].source = () => {
const banner = [
'/**',
' * 이것은 BannerPlugin이 처리한 결과입니다.',
' * Build Date: 2019-10-10',
' */'
].join('\n');
return banner + '\n\n' + source;
}

callback();
});
}
}

module.exports = MyPlugin;
1
2
3
4
5
6
7
8
9
10
// webpack.config.js

const MyPlugin = require('./plugin.js');

module.exports = {
// ...
plugins: [
new MyPlugin()
]
}

웹팩에 plugins 배열에 등록해준다. 직접 클래스를 생성후에 넣어준다.

플러그인 또한 로더처럼 커스텀 플러그인을 만들 일을 거의 없다.


자주사용되는 플러그인

BannerPlugin

결과물에 빌드 정보다 커밋 버전 등을 추가할때 주로 사용한다. 말그대로 배너를 추가할때 사용한다.
웹팩이 기본적으로 제공해주기 때문에 따로 설치할 필요가 없다.

1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js

const webpack = require('webpack');

plugins: [
new webpack.BannerPlugin({
banner: `
Build Date: ${new Date().toLocaleString()}
Commit Version: ${childProcess.execSync('git config user.name')}
`
})
]

DefinePlugin

웹팩에서 제공하는 DefinePlugin은 모든 자바스크립트 코드에서 접근이 가능한 전역 변수를 선언하기 위해서 사용되는 플러그인이다. 사용방법은 webpack.DefinePlugin의 생성자에 전역 변수로 사용할 값을 객체 형태로 넘겨준다.

1
2
3
4
5
6
7
8
9
10
11
// webpack.config.js

const webpack = require('webpack');

plugins: [
new webpack.DefinePlugin({
TWO: '1+1',
TWO2: JSON.stringify('1+1'),
'api.domian': JSON.stringify('http://naver.com')
})
]

주의 할 점은 값이 문자열이 아니라 계산식이라는 것이다. 첫번째 값이 ‘1+1’은 문자열이 아니라 계산되어 2라는 값이 TWO에 저장된다. ‘1+1’이라는 문자열을 사용하고 싶으면 JSON.stringify를 사용하여야 한다.
키가 api.domian 이런식으로 등록하면 실제 사용할때는 객체 형식으로 접근이 가능하다.

1
2
3
4
5
// main.js

console.log(TWO); // 2
console.log(TWO2); // 1+1
console.log(api.domain); // http://naver.com

노드의 process 객체는 기본적으로 전역적으로 사용할수 있도록 등록이 되어 있다.

1
2
3
// main.js

console.log(process.env);

HtmlWebpackPlugin

서드파티로 제공하는 HtmlWebpackPlugin는 HTML 파일을 후처할때 사용한다. 이 플러그인을 사용하면 HTML도 빌드의 과정에 포함 시킬수 있다.

1
npm install -D html-webpack-plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// webpack.config.js

const HtmlWebpackPlugin = requrie('html-webpack-plugin');

plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
templateParameters: {
'param': 'value'
},
minify: {
collapseWhitespace: true,
removeComments: true
}
})
]
  • template : index.html의 경로를 적어준다. 빌드 후에 output 경로에 index.html 생성이 된다. 번들링된 자바스크립트 경로도 자동으로 index.html에 추가되기때문에 수동으로 작성할 필요가 없어진다.
  • templateParameters: index.html에 파라미터를 전달할수 있다. <%= 파라미터명 %> 으로 값을 가져올수 있다.
    1
    2
    3
    <html>
    <%= param %>
    <html>
  • minify: 말그대로 코드를 경량화 하기 위한 옵션이다.
    • collapseWhitespace: value가 true로 설정 하면 모든 빈칸을 제거해준다.
    • removeComments: value가 true이면 모든 주석을 제거해준다.

CleanWebpackPlugin

서드파티로 제공하는 CleanWebpackPlugin는 빌드 이전 결과물을 모두 제거해 주는 플러그인다(output 폴더를 모두 삭제 후에 빌드가 된다). 해당 플러그인은 export시에 객체로 감싸기 때문에 { CleanWebpackPlugin }으로 사용해야 한다.

1
npm install -D clean-webpack-plugin
1
2
3
4
5
6
7
// webpack.config.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin');

plugins: [
new CleanWebpackPlugin()
]

MiniCssExtractPlugin

스타일 시트의 양이 많을때 자바스크립트 하나로 결과물을 모두 번들링 하게 되면 부담이 커진다. 번들 결과에서 스타일시트 코드만 뽑아서 별도의 css 파일로 관리 할수 있다. 최종 결과물이 css 파일하나, js 파일 하나가 된다(물론 그 이상도 만들수 있다).
개발 모드일때는 하나의 js로 하는게 작업에 좋다고 한다. 배포시에만 설정하도록 해보자.

1
npm install mini-css-extract-plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// webpack.config.js
const MiniCssExtracPlugin = require('mini-css-extract-plugin');
module: {
rules: [
{
test: /\.css$/,
use: [
process.env.NODE_ENV === 'development'
? MiniCssExtracPlugin.loader
: 'style-loader',
'css-loader'
]
}
]
},
plugins: [
...(
process.env.NODE_ENV === 'development'
? [new MiniCssExtracPlugin({ filename: '[name].css' })]
: []
)
]

위에 코드에서도 확인 할수 있듯이 MiniCssExtracPlugin를 사용하려면 loader 또한 MiniCssExtracPlugin.loader를 사용하여야 한다.

Comment and share

로더의 역할

로더(Loader)는 웹팩이 웹 애플리케이션을 해석할 때 자바스크립트 파일이 아닌 웹 자원(HTML, CSS, Images, 폰트 등)들을 변환할 수 있도록 도와주는 속성이다. 로더를 사용하면 모든 파일을 모듈로 변환해 주기 때문에 자바스크립트에서 import 구문을 통해서 자바스크립트 영역에서 사용이 가능하다.

1. 모든 파일을 자바스크립트의 모듈처럼 만들어준다.
2. 타입스크립트 같은 다른 언어를 자바스킙트 문법으로 변환해 준다.
3. 이미지를 data URL 형식의 문자열로도 변환 가능하다.
4. CSS 파일을 자바스크립트에서 직접 로딩할수 있게 해준다.
결론 네가지의 역할 뿐 아니라 로더는 각 파일들을 처리 할때 사용할수있다.


커스텀 로더 만들기

로더는 함수 형식으로 만든다. 함수의 파라미터로 content를 받아온다. 이 content에는 파일의 content가 저장되어 있다. 그래서 로더는 파일의 내용을 변경하거나 처리할때에 사용할수 있다.

1
2
3
4
// loader.js
module.exports = function myWebpackLoader(content) {
return content.replace('console.log', 'alert');
}
1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
loader: './loader.js'
}
]
}
}

로더는 webpack.config.js의 module.rules 배열에 들어간다. 로더는 파일 유형별로 처리할 로더들을 등록 해준다.
하나의 로더에 처리할 파일들을 등록 하는게 아닌, 파일 하나(또는 그 이상)에 처리할 로더를 등록 해주는 것이기 때문에, 파일 유형별로 여러개의 로더가 등록 가능하다.

  • test : 로더를 적용할 파일 유형 (일반적으로 정규 표현식 사용)
  • loader : 로더를 하나만 등록 할때 이렇게 사용 하면 될거 같다.
  • use : 파일에 적용할 로더를 등록 (배열)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    module.exports = {
    // ...
    module: {
    rules: [
    {
    test: /\.js$/,
    use: [
    'style-loader',
    'css-loader',
    '로더 모듈 이름',
    '로더 경로' // './loader.js' 또는 path.resolve('./loader.js'),
    // 객체로도 등록 가능하다.
    {
    loader : '로더',
    options: {

    }
    }
    ]
    }
    ]
    }
    }
    use에 등록 된 로더는 뒤에서 부터 먼저 실행된다.
    style-loader는 css-loader가 등록 된 후에 사용가능하다. 그렇기 때문에 css-loader보다 앞쪽에 등록해야 한다.

실제로 커스텀로더를 사용할 일은 거의 없다. 로더가 어떤식으로 파일을 처리 하기 위해서 만들어본것이다.


자주사용되는 로더

css-loader

자바스크립트에서 CSS를 모듈로 변환해주는 역할을 한다.

1
npm install -D css-loader
1
2
3
4
5
6
7
8
9
10
11
// webpack.config.js

// ...
rules: [
{
test: '/\.css$/',
use: [
'css-loader'
]
}
]

이제 자바스크립트에서 css를 모듈로 가져올수 있다.

1
2
3
4
5
/* test.css */

body {
color: #111;
}
1
2
3
4
5
// test.js

import style from './test.css';

console.log(style); // 배열로 넘어온다.


style-loader

모듈로 등록된 css를 스타일로 적용시켜 주는 역할을 한다. 모듈로 등록된 css만 적용가능하기 때문에 css-loader가 존재하여야 한다.

1
npm install -D style-loader
1
2
3
4
5
6
7
8
// webpack.config.js

// 웹팩에 style-loader 등록시 순서에 유의!

use: [
'style-loader',
'css-loader'
]
1
2
3
4
// test.js

import './test.css'
import style from './test.css'; // 이렇게 해도 등록 해주지만 보통은 위에 처럼 작성한다.

브라우저에서 확인 해보면 head의 style 태그로 스타일이 적용된 것을 확인할수 있다.


file-loader

이름에서도 알수 있듯이 파일을 모듈화 해주는 로더이다. 보통은 이미지 파일이나 폰트 파일을 모듈로 변환할때 사용이된다.

1. 파일을 모듈화 해준다(주로 이미지에 사용)
2. 빌드 후에는 파일을 output 경로에 만들어준다.
3. publicPath 옵션을 통해서 실제 경로와 호출 경로를 일치 시켜주어야 한다.

1
npm install -D file-loader
1
2
3
4
5
6
7
8
9
10
11
12
// webpack.config.js

rules: [
{
test: '/\.png$/',
loader: 'file-loader',
options: {
publicPath: './dist',
name: '[name].[ext]?[hash]'
}
}
]

file-loader는 options 속성을 사용가능하다.

  • publicPath : 파일을 사용할때 경로 앞에 붙는 문자열이다. 아래와 같은 경로에 있을때 publicPath를 설정하지 않으면 파일이 저장된 경로와 호출 경로가 달라 이미지를 불러오지못한다.
    1
    2
    3
    4
    index.html
    dist
    ├── components
    └── image.png
  • name : 번들링 된 이미지 파일을 저장할 때 사용될 파일이름이다. [name], [ext], [hash] 를 사용 가능하다.
    • [name] : 실제 이미지 파일 이름을 그대로 사용한다.
    • [ext] : 실제 확장자를 사용한다.
    • [hash] : 파일이름에 해쉬 값을 사용한다. 브라우저는 이름이 동일한 파일에 대해서 캐시를 저장하고 있어, 파일의 내용이 달라져도 캐시가 존재하면 새로운 파일이 로드되지 않는다. hash처럼 계속 값이 달라지면 캐시를 무력화하여 최신 파일을 로드 할수 있다.

자바스크립트에서 모듈화된 이미지를 불러 올때 아래와 같이 사용한다.

1
2
3
4
5
import image from './image.png';

document.querySelector('body').innerHTML = `
<img src='${image}'>
`

url-loader

사용하는 이미지 개수가 많다면 네트워크 리소스를 사용하는 부담이 생겨 사이트 성능에 영향을 준다. 한 페이지에 작은 이미지를 여러개 사용한다면 DATA URI Scheme을 이용하는 것이 좋은 방안이 될수 있다(네트워크 통신을 안하게 해준다). 이러한 처리를 해주는 것이 url-loader이다.

1
npm install -D url-loader
1
2
3
4
5
6
7
8
9
10
11
rules: [
{
test: '/\.png$/',
loader: 'file-loader',
options: {
publicPath: './dist',
filename: '[name].[ext]?[hash]',
limit: 20 * 1024
}
}
]

사용방법은 file-loader와 유사하다. url-loader는 limit라는 옵션을 사용가능한데 해당 파일의 크기 이하는 url-loader를 사용하고 그 이상은 file-loader를 사용하도록 해준다. 그래서 웹팩에 url-loader만 등록 하더라도 file-loader가 설치되어 있어야 한다(물론 limit 이하만 사용하는 경우에는 에러는 발생하지 않는다. limit 초과하는 파일이 존재할때 에러발생)

  • limit : url-loader를 사용할 파일 크기. limit을 너무 높게 잡아도 좋지 않다. (단위는 byte)

Comment and share

웹팩이란?

최근 자바스크립트에서는 모듈을 이용하여 주로 작성이 되고 있다. 번들러는 모듈의 의존 관계를 분석하여 브라우저가 인식할 수 있는 자바스크립트 코드로 변환 후 하나 또는 여러개의 파일로 만들어 주는 도구이다. 번들러를 통해서 소스코드를 모듈별로 작성 할수 있고 모듈간의 의존성을 쉽게 관리할수 있다. 자바스크립트에서 많이 사용되고 있는 모듈 번들러 중에 하나가 웹팩이다.
웹팩을 사용하면 자바스크립트 뿐 아니라 HTML, CSS, Image 파일의 리소스까지 의존성 관리를 할수 있게 해준다.


웹팩 설치

옵션을 -D(–save-dev) 옵션을 줄 경우에는 devDependencies에 들어가는데 이는 개발용 패키지이다.
webpack-cli를 설치하면 터미널에서 webpack 커맨드를 사용할수 있다.

1
npm install webpack webpack-cli -D

설치가 완료되면 아래와 같이 실행할수 있다.

1
2
node_modules/.bin/webpack --mode development
npx webpack --mode development

웹팩 옵션

웹팩을 사용할 때 여러가지 옵션을 줄수 있다.
아래는 - 하나로 보이지만 실제로는 -를 2개 써주어야 한다.


  1. –mode

    • development : 개발용으로 번들링된다.
    • production : 배포용으로 번들링된다.
    • none
  2. –entry
    모듈의 의존성 그래프를 만드는 시작점을 지정 해주는 것이다. 모든 모듈의 시작 파일을 지정해준다고 생각하면 쉽다.

  3. –output
    번들링된 파일의 위치와 이름을 지정할때 사용한다.

  4. –config
    config 파일의 위치를 지정할때 사용한다. 기본값으로는 webpack.config.js 또는 webpackfile.js이다.

  5. –progress
    웹팩이 빌드되는 것을 커맨드라인으로 볼수 있게 해준다.

1
npx webpack --mode development --entry ./src/app.js --output dist/main.js

설정 파일 webpack.config.js

매번 위처럼 cli 명령어를 통해서 작업하기는 힘들다. config 파일을 통해서 작성 후에 webpack만 실행하면 편하게 작업할수 있다.


설정 파일 만들기

프로젝트 폴더의 루트에서 webpack.config.js 파일을 생성한다(package.json 파일과 동일한 위치).

1
module.exports = {};

옵션 설정하기

옵션은 cli에서 사용했었던 옵션명을 사용한다.

mode

번들링할 모드를 설정한다.

development
  • 개발용모드이다.
  • 소스맵을 제공한다.
production
  • 배포용모드이다.
  • 코드를 압축, 난독화 한다.
  • mode를 설정 하지 않을 경우 production이 default이다.
1
2
3
module.exports = {
mode: '[development|production|none]',
}

entry

entry 옵션을 통해서 모듈의 시작점을 지정할수 있다.

1
2
3
module.exports = {
entry: './src/app.js'
}

entry를 여러개 사용 할 경우 객체 형태로 넘겨 주면 된다. 이때 key 값은 사용자가 커스텀하게 설정 가능하다.

1
2
3
4
5
6
module.exports = {
entry: {
main1: './src/main1.js',
main2: './src/main2.js'
}
}

output

output은 번들링 된 결과를 저장하기 위한 위치를 설정한다. 기본값은 './dist/main.js' 이다. 절대경로를 사용하는 것을 권장한다(path.resolve 사용).

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
}
}

저장할 파일이름 [name]는 동적으로 이름을 설정가능하다. entry에서 설정한 key를 filename의 이름으로 사용가능하다.
아래처럼 entry의 key를 설정 하지 않으면 default로 main이다.

1
2
3
4
5
6
7
8
9
const path = require('path');

module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}

entry의 key가 app이기 때문에 번들링 된 파일은 ./dist/app.js로 만들어진다.

1
2
3
4
5
6
7
8
9
10
11
const path = require('path');

module.exports = {
entry: {
app: './src/main.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}

package.json에 스크립트 등록하기

package.json의 scripts 부분에 아래와 같이 추가한다. 보통 build로 설정하는 듯 하다. 빌드를 할때는 npm run build 명령어를 사용하면 된다.

1
2
3
4
5
6
{
// ...
scripts: {
'build': webpack
}
}

프로젝트에 기본적인 웹팩 설정하기 순서

1. npm init 명령어 실행

package.json 파일을 생성한다.

2. 웹팩 설치
1
npm i -D webpack webpack-cli
3. 환경설정 파일 생성하기

프로젝트의 루트 디렉토리에 webpack.config.js을 생성한다.

4. 웹팩 스크립트를 추가

package.json에 웹팩을 실행할 스크립트를 추가한다.

5. 웹팩 스크립트 실행

npm run build를 통해서 웹팩을 실행한다.

Comment and share

  • page 1 of 1

Moon Star

author.bio


author.job