Skip to content

webpack #

Find similar titles

10회 업데이트 됨.

Edit
  • 최초 작성자
    tykim
  • 최근 업데이트
    dongiljogun

Structured data

Category
Programming

webpack #

개요 #

'webpack은 모듈 번들러로, 의존성을 가진 모듈들을 다루고, 그 모듈로부터 정적인 asset을 생성한다.'

-webpack 공식페이지-

웹 서비스를 개발할 때 자바스크립트로 작성하는 코드의 양이 많아지면 유지, 보수가 쉽도록 코드를 모듈로 나누어 관리하는 모듈 시스템이 필요한데 자바스크립트는 언어 자체가 지원하는 모듈 시스템이 없다. webpack은 이런 한계를 극복하기 위한 도구 중 하나로 자바스크립트 모듈화 도구이다.
이 문서에선 간단한 Webpack 설명과 예제를 통해 Webpack5로 개발환경을 세팅하는 방법에 관해 설명한다.

프로젝트 생성 #

먼저 webpack으로 실행할 프로젝트 파일을 생성하고 node로 새로운 패키지를 생성한다.

npm init

혹은 -y를 추가해 기본 세팅을 건너뛰고 생성할 수 있다.

npm init -y

webpack과 함께 필수적인 webpack 패키지도 함께 다운로드 한다.

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

약자는 이렇게 된다.

npm i webpack webpack-cli webpack-dev-server -D

디렉터리 설정 #

디렉터리는 프로젝트를 빌드하거나 파일이나 문서를 연결할 때 주요한 요소 중 하나이기에 정확히 파악하는 것이 중요하다. 이 문서에서 다루는 프로젝트의 디렉터리는 다음과 같다.

dist
└── index.html
└── src
└── . . .

public
└── index.html
└── images
  └── . . .  .png/jpg

Src
└── index.js
└── htmls
  └── . . .  .html
└── scss
  └── . . .  .scss
└── js
  └── . . .  .js
└── images
  └── . . .  .png/jpg

tasks
└── webpack.config.js

package.json
package-lock.json

dist 폴더는 당장 있는 것이 아닌, webpack을 실행하고 난 후 생성된다. Webpack을 설정하는 데 필요한 webpack.config.js파일은 공식 문서에서는 가장 바깥에 있는 package.json과 같은 경로에 있지만 여기서는 깔끔한 파일 배치를 위해 tasks 파일 안에 있다. 이 경우 경로가 달라지는 점을 유의한다.

Webpack 설정하기 #

Webpack을 설정하는 webpack.config.js 파일을 만든다. 이 문서에서는 위의 디렉터리 설정대로 tasks 폴더 안에 만들었다.

Webpack 환경설정을 위해 중요한 객체들은 다음과 같다.

Entry: 모든 의존 객체들이 모인 Webpack의 시작점.
Output: 빌드할 때 JS와 정적 파일들(output files)의 경로를 설정.
Loaders: Webpack이 다양한 파일 확장자를 다룰 수 있도록 도와주는 서드파티 확장 프로그램. JS가 아닌 파일들을 모듈로 바꿔줌.
Plugins: Webpack의 동작 방식을 바꿔주는 서드파티 확장 프로그램.
Mode: 개발(development)과 생산(production) 두 모드 설정. Default는 생산(Production).

위의 객체들을 설명하기 전 config 파일의 기본적인 환경은 다음과 같다.

const webpack = require('webpack');

module.exports = {
  mode: ‘ . . . ‘,
  entry: { . . . },
  output: { . . . },
  module: { . . . },
};

Webpack을 실행하는 데에 필요한 플러그인들은 devDependencies에 다운로드 한다.

npm i . . . -D

다운로드 한 플러그는 config 파일 안에서 불러와 사용하면 된다.

const webpack = require('webpack');

entry #

Entry 안에 시작점이 될 JS 파일 경로를 입력한다.

module.exports = {
  entry: '../src/dist/index.js',
}

더 정확한 경로를 위해 path를 사용할 수도 있다. Path는 기본적으로 node에 있는 값이기에 다운로드 할 필요 없이 Webpack에 가져오기만 하면 된다.

const path = require('path')

module.exports = {
  entry: path.resolve(__dirname, ‘../src/js/index.js’)
}

상황에 따라 한 개 이상의 entry를 설정하기도 한다.

module.exports = {
  entry: {
    index : path.resolve(__dirname, ‘../src/index.js’),
    main : path.resolve(__dirname, ‘../src/js/main.js’)
  }
}

output #

Path에 Webpack으로 빌드한 파일 경로를 정하고 빌드한 파일 이름을 설정한다. Entry의 JS 파일들의 이름을 그대로 유지하고 싶다면 [name].js로 설정한다.

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

이렇게 하면 빌드된 JS 파일 디렉터리는 이렇게 된다.

dist
└── index.js
└── main.js

Filename으로 경로를 설정해 기획한 디렉터리대로 빌드되게 한다.

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

결과는 다음과 같다.

dist
└── src
  └── js
    └── index.js
    └── main.js

Plugins #

html-webpack-plugin #

html-webpack-plugin를 받아 웹페이지의 기본이 되는 index.html 파일을 읽고, 같은 파일에 번들을 삽입한다.

const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  plugins: [
    new HtmlWebpackPlugin ({
      title: 'webpack5',
      template: path.resolve(__dirname, '../ public /index.html'),
      favicon: path.resolve(__dirname, '../public/images/favicon.png'),
      filename: 'index.html',
    }),
  ],
}

clean-webpack-plugin #

clean-webpack-plugin로 webpack을 실행할 때마다 생기는 dist와 dist 안 파일들을 지운다.

npm i clean-webpack-plugin -D

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

module.exports = {
  plugins: [
    new CleanWebpackPlugin(),
  ]
}

webpack Dev Server #

모드는 config에서 설정할 수도 있지만 package.json 파일에 scripts를 수정해 명령어로도 설정할 수 있다.

{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  }
}

Webpack을 실행과 동시에 파일을 열기를 원한다면 –open을 추가하면 된다.

"scripts": {
    "dev": "webpack serve --open --mode development",
}

이 프로젝트에는 config 파일이 task 폴더 안에 있으므로 script에서 경로를 표시해주어야 한다. serve –open과 모드 설정을 같이 실행할 경우, 순서가 중요하다.

"scripts": {
    "dev": "webpack serve --open --mode=development --config tasks/webpack.config.js",
    "build": "webpack --mode=production --config tasks/webpack. config.js" 
}

이러면 상황에 따라 설정된 명령어로 프로젝트를 빌드 할 수 있다.

npm run dev // 개발모드

npm run build // 배포모드

module #

loader #

Webpack에는 파일 확장자를 다루기 위해 여러 종류의 loader, 서드파티 확장 프로그램이 있다.

loader는 module 객체 안, rules라는 속성으로 설정한다. loader의 일반적인 구문은 다음과 같다.

module.exports = {
  module: {
    rules: [
      {
        test: /\.filename1$/,
        use: ['loader-b', 'loader-a'],
      },
      {
        test: /\.filename2$/,
        use: ['loader-d', 'loader-c'],
      },
    ],
  },
}
loader for script #

호환성을 위해 JS파일 babeling을 설정한다.

npm i babel-loader @babel/core @babel/preset-env -D

module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
              ],
            ],
          },
        },
        exclude: /node_modules/,
      },
    ],
  },
loader for style #

기본적으로 Webpack에서 CSS를 적용하기 위해서 우리는 2가지 loader가 필요하다. css-loader 와 style-loader 이 프로젝트에선 scss를 사용하기 때문에 Webpack으로 scss를 css로 컴파일링 하기 위해 sass, sass-loader 또한 필요하며, 호환성을 위해 'autoprefixer'도 함께 사용할 것이다.

npm i css-loader style-loader postcss-loader sass-loader autoprefixer -D

module: {
    rules: [
      {
        test: /\.(scss|css)$/,
        use: [
          'style-loader',
          {
              loader: "css-loader",
              options: {
                  importLoaders: 2,
                  sourceMap: true,
                  url: false,
              }
          },
          {
              loader: 'postcss-loader',
              options: {
                  postcssOptions: {
                      plugins: [
                          'autoprefixer',
                      ]
                  }
              }
          },
          'sass-loader'
        ],
        exclude: /node_modules/,
      }
    ],
},

또, 파일 크기를 줄이기 위해 mini-css-extract-plugin를 다운로드하여 plugins에 추가한다.

npm i mini-css-extract-plugin -D

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
  plugins: [
    new MiniCssExtractPlugin(),
  ],
}

컴파일링한 css파일을 원하는 경로에 넣으려면 아래와 같이 설정한다.

plugins: [ new MiniCssExtractPlugin({ filename: "src/css/style.css", chunkFilename: "[id].css" }), ],

Webpack은 js를 중심으로 파일을 빌드하기 때문에 설정한 scss파일을 entry-js파일에 import해줘야 한다. 여기서는 index.js파일에 import했다.

import './scss/style.scss';

이제 Webpack을 실행해보면 dist 폴더와 그 안의 내용물을 확인할 수 있다.

dist
└── index.html
└── src
  └── js
    └── index.js
    └── main.js
  └── css
    └── style.css

Webpack 실행 결과 #

여기까지 파일은 다음과 같다.
webpack.config.js

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    index : paths.src,
    main : path.resolve(__dirname, '../src') + '/js/main.js',
  },
  output: {
    path: path.resolve(__dirname, '../dist),
    filename: 'src/js/[name].js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  corejs: { version: 3, proposals: true },
                  useBuiltIns: 'usage',
                  shippedProposals: true,
                  targets: {
                    browsers: ['>= 1%, not dead'],
                  },
                },
              ],
            ],
          },
        },
        exclude: /node_modules/,
      },
      {
        test: /\.(scss|sass|css)$/i,
        use: ['style-loader', 'css-loader', 'sass-loader'],
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'webpack-5',
      template: path.resolve(__dirname, '../dist) + '/index.html',
      filename: 'index.html',
    }),
    new MiniCssExtractPlugin({
      filename: "src/css/style.css",
      chunkFilename: "[id].css"
    }),
  ],
}

index.js

import './scss/style.scss';

console.log('index!!');

main.js

console.log('main.js');

style.scss

@charset 'utf-8';

body {
  text-align: center;
  background-color: orange;

  .container {
    background-color: pink;

    p {
      color: green;
      font-weight: bold;
    }
  }
}

HTML 결과
Image

JS 결과
Image

디렉터리 결과
Image

Mode 설정 및 config 파일 정리 #

Webpack은 모드에 따라 파일을 다르게 컴파일링 하는 것을 추천한다. 앞서 나온 대로 실행어로 mode를 설정할 수도 있지만 그럴 때 각 모드에 따른 디테일한 설정이 어렵기 때문에 다시 config 파일을 정리한다.
config파일은 공통된 값은 common, development에 따른 값은 dev, prod 3개로 나누어 작성한다. 여기서는 mode, css/scss, devtool, server을 다르게 설정할 것이다.

webpack.common.js

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    index : paths.src,
    main : path.resolve(__dirname, '../src') + '/js/main.js',
  },
  output: {
    path: path.resolve(__dirname, '../dist),
    filename: 'src/js/[name].js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  corejs: { version: 3, proposals: true },
                  useBuiltIns: 'usage',
                  shippedProposals: true,
                  targets: {
                    browsers: ['>= 1%, not dead'],
                  },
                },
              ],
            ],
          },
        },
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'webpack-5',
      template: path.resolve(__dirname, '../dist) + '/index.html',
      filename: 'index.html',
    }),
    new MiniCssExtractPlugin({
      filename: "src/css/style.css",
      chunkFilename: "[id].css"
    }),
  ],
}

Dev와 prod 파일을 실행할 때도 common값을 가져오기 위해 'webpack-merge'를 다운받아 연결한다.

npm i webpack-merge -D


const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  ( . . . )
});

개발자 모드일 때는 코드 수정이 잦아 코드값을 잘 찾기 위해 minimize는 피하고 source-map도 가독성이 높은 inline-source-map가 좋다. 또한 실행되는 화면을 확인하기 위해 sever port를 설정해야 한다.
webpack.dev.js

const { merge } = require('webpack-merge');

const common = require('./webpack.common.js');
const paths = require('./paths');

module.exports = merge(common, {
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.(scss|sass|css)$/i,
        use: ['style-loader', 'css-loader', 'sass-loader'],
        exclude: /node_modules/,
      },
    ],
  },
  devtool: 'inline-source-map',
  devServer: {
    contentBase: paths.build,
    compress: true,
    hot: true,
    port: 8000,
  },
});

webpack.prod.js

const { merge } = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const common = require('./webpack.common.js');
const paths = require('./paths');

module.exports = merge(common, {
  mode: 'production',
  module: {
    rules: [
      {
        test: /\.(scss|sass|css)$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
        exclude: /node_modules/,
      },
    ],
  },
devtool: 'cheap-module-source-map',
});

config 파일이 바뀌었으니 package.json 안 script 파일도 수정하면 각 모드에 맞춰 파일이 컴파일링 된다.

"scripts": {
  "build": "webpack --config tasks/webpack.prod.js",
  "dev": "webpack serve --open --config tasks/webpack.dev.js"
},

Reference #

0.0.1_20231010_1_v71