JavaScript

webpack, webpack dev server, babel을 이용하여 프론트 소스 파일 bundle하기

한땀코딩 2020. 10. 18. 21:01

https://webpack.js.org/

 

webpack

webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

webpack.js.org

프론트, 즉 어떤 웹 서비스의 클라이언트 영역에 해당하는 부분을 제작하다 보면 소스 파일이 점점 증식하는 것을 체험할 수 있습니다. 간단한 페이지라면 하나의 html, js, css 파일로 끝낼 수 있겠지만 하나의 페이지 안에서도 각각의 부분을 컴포넌트로 쪼개서 작업하는 요즘은 오히려 개발 단계에서 하나의 파일에 압축해놓으면 효율성이 현저히 떨어지고 확장성 면에서도 좋지 않은 것 같습니다.

이런 상황에서 활용해볼 수 있는 것이 webpack인데, 간단하게 생각해서 모든 소스 파일을 하나로 bundling 해주는 것이라고 볼 수 있습니다. 시작점이 되는 js 파일을 '엔트리'라고 부르는데, 이를 기점으로 연결되는 모든 소스 파일을 하나로 합쳐주는 걸 자동화해주는 고마운 기능을 제공하고 있습니다.

세팅 요약

번들링이라는 것이 단순히 합치는 것은 맞지만 그 안에서 또 수많은 옵션이 존재하고 이걸 또 개발 단계에서 어떻게 테스트할지는 다양한 방식이 있습니다. 그중에서 제가 선택한 방향은 아래와 같습니다.

  • SPA 사이트라고 생각하고 엔트리 포인트는 하나
  • 스타일은 CSS가 아닌 SCSS(SASS) 사용하며 별도 파일이 생성하지 않고 html, js와 합쳐서 나오게 설정
  • webpack dev server를 이용하여 개발 단계에서 화면을 테스트
  • 호환성을 위해 바벨을 적용
  • Webpack의 경우 최근 5버전이 나왔기 때문에 이번 글에서는 4.44.2 버전을 기준으로 작성됨

공식 문서와 여러 튜토리얼을 참고하여 작성한 내용이기 때문에 설정의 상세한 내용을 하나하나 설명하지는 않는다는 점도 참고 부탁드립니다.

디렉토리 요약

.
├── babel.config.js
├── dist
│   ├── index.html
│   └── index.js
├── package-lock.json
├── package.json
├── src
│   ├── index.html
│   ├── index.js
│   └── stylesheets
│       └── style.scss
└── webpack.config.js

dist 폴더에는 최종적으로 번들된 파일이 위치하게 됩니다. 그 외 node_modules를 제외한 디렉토리 구조는 이렇습니다.

설치

클라이언트 부분이기 때문에 서버와 따로 폴더, 소스파일, npm 환경을 세팅할 수 있습니다.

1. Babel

webpack.config.js에서 모든 걸 하나로 합치는 느낌이기 때문에 먼저 바벨부터 설정을 해줍니다.

npm install @babel/core @babel/cli @babel/preset-env babel-loader core-js@3 --save-dev

Configure Babel · Babel

바벨의 설정 파일과 관련된 것 또한 위 공식 파일에서 확인이 가능합니다. 점유율이 0.2%보다 높은 브라우저를 대상으로 호환성을 맞춰줄 수 있도록 세팅을 한다면 기본적으로 아래처럼 작성이 됩니다.

module.exports = function (api) {
	api.cache(true);
  
	const presets = [
	  [
		'@babel/preset-env',
		{
		  targets: "> 0.2%, not dead",
		  useBuiltIns: 'usage',
		  corejs: '3',
		  modules: false,
		},
	  ],
	];
	const plugins = [
	  ['@babel/plugin-proposal-class-properties', { loose: true }],
	];
  
	return {
	  presets,
	  plugins,
	};
};

2. CSS 관련 설치

css 및 스타일을 적용하기 위한 모듈을 설치합니다.

npm i style-loader sass-loader css-loader --save-dev

별도의 스타일 파일을 만들지는 않기 때문에 scss는 html에서 import 하지 않고 js 파일에서 다음과 같이 불러옵니다.

import './stylesheets/style.scss'

3. webpack

웹팩과 관련된 모듈을 설치해줍니다.

npm i webpack@4.44.2 webpack-cli@3.3.12 html-webpack-plugin webpack-dev-server path --save-dev

Configuration | webpack

여기서 webpack.config.js 파일의 각각의 줄에 대한 설명을 볼 수 있습니다. 간단하게 babel과 webpack dev server를 localhost에서 사용하기 위한 설정을 작성해주면 아래와 같습니다.

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

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'app.js',
  },
  devServer: {
    port: 8000,
    contentBase: path.join(__dirname, 'dist'),
    host: 'localhost',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader',
        ],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html',
      inject: false,
    }),
  ],
};

4. package.json

위의 설정을 마쳤다면 이제 npm script로 web dev server 실행과 빌드 실행문을 넣어줍니다.

"scripts": {
    "dev": "webpack-dev-server --open",
    "build": "webpack -w"
  }
npm run dev
npm run build

위 두 개의 명령어로 각각 dev server 실행과 웹팩 번들을 빌드를 실행할 수 있습니다.

5. 그 외

간단하게 빈 html 파일에 div 하나를 만들고 내용을 채우는 페이지를 생성한다고 가정하고 html, scss, js 파일을 웹팩에서 빌드할 수 있게끔 작성한 내용입니다.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Webpack</title>
</head>
<body>
</body>
<script type='module' src="./index.js"></script>
</html>
import 'core-js';
import './stylesheets/style.scss'

const body = document.querySelector('body');

const titleDiv = document.createElement('div');
titleDiv.innerHTML = `
<h1>HELLO WORLD!</h1>
<h3>webpack is cool!</h3>
`;
body.append(titleDiv);
$main-color: rgb(50, 211, 197);

h1 {
	color: $main-color;
}