웹팩 막연히 강력하다고 들어보던 웹팩 이제 사용해보려 한다.

  • CRA없이 환경 설정 해보자

개인 프로젝트를 진행하다 보니, 당연히 CRA 를 사용했다.
뭐 CRA의 장점이나 요런요런것들을 대신 해주니깐 CRA를 사용하면 좋아요~ 였지, 정확히 어떤 부분들이 필요한지 몰랐다. 환경 설정 관련해서 한번 처음부터 진행해보려 한다.

웹팩(webpack)이란?

  • 웹팩 공식 Github 에서는 웹팩을 '모듈(module)'을 위한 '번들러(bundler)' 라고 한다.

    webpack is a bundler for modules. The 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

그러면 모듈과 번들러란??...

모듈이란?

  • 모듈(module)은 재사용 가능한 코드조각이다. 더 쉽게는 js 파일이다.
    모듈은 자신만의 파일 스코프(모듈 스코프)를 갖고 export, import 할 수 있다.
    보통 클래스 하나 또는 특정한 목적을 가진 복수의 함수로 구성된 라이브러리 하나로 구성된다.

초기 자바스크립트는 크기도 작고 기능도 단순해서 '모듈'에 관한 표준 문법이 필요하지 않았다.
시간이 흘러 웹에 요구되는 기능이 점점 복잡해지면서, 코드의 크기가 점점 커지기 시작했다.
이에 따라 자바스크립트 커뮤니티는 필요한 모듈을 언제든지 불러올 수 있게 해 주거나, 코드를 모듈 단위로 구성해 주는 방법 등 다양한 라이브러리를 만들었다.
'AMD', 'CommonJS', 'UMD'와 같은 모듈 시스템이 그 예이다.
'모듈시스템'에서는 전역에 선언된 var의 사용으로 발생하는 부작용을 예방할 수 있기도 하다.

모듈의 특징

  1. 모듈은 항상 defer 속성을 붙인 것처럼 지연 실행된다. (굳이 body 끄트머리에 적지 않아도 된다.)
  2. 모듈은 strict mode 로 실행된다.
  3. 모듈은 자신만의 스코프를 갖는다. (파일 스코프)
  4. 모듈은 단 한 번만 평가(실행)되고 필요한 곳에서 공유된다.
  5. 모듈 최상위 레벨 this는 undefined이다.
  6. import.meta 객체로 정보를 얻을 수 있다. (e.g. import.meta.url)

번들러란?

JS, CSS, 이미지 등의 파일을 묶어주는 작업을 '번들링(Bundling)'이라고 하고,
작업의 결과물은 '번들(Bundle)'이라고 한다. 웹팩 자체는 묶어주는 역할을 하기 때문에 '번들러(Bundler)'라고 한다,

번들링 과정이 끝나면 기존 스크립트에서 import/export가 사라지기 때문에 type="module"이 필요 없어진다.
따라서 번들링 과정을 거친 스크립트는 일반 스크립트처럼 취급한다.

웹팩의 등장 배경

  • 파일 단위의 자바스크립트 모듈 관리의 필요성
  • 웹 개발 작업 자동화 도구
  • 웹 애플리케이션의 빠른 로딩 속도와 높은 성능

웹팩의 장점과도 같다.

파일 단위의 자바스크립트 모듈 관리의 필요성

자바스크립트의 변수 유효 범위는 기본적으로 전역 범위를 갖는다.
이 때문에 서로 다른 모듈에서 같은 이름의 변수를 사용한다면, 서로가 서로를 의도치 않게 변경할 수 있다.

이렇다 보니 파일 단위로 변수를 관리하고 싶고 자바스크립트를 모듈화하고 싶어지는데, 이전까지는 AMD, CommonJS와 같은 라이브러리를 사용했다.

그렇다면 AMD, CommonJS와 웹팩의 차이점은 뭘까?

AMD VS CommonJS VS Webpack

AMD 방식은 Requirejs, CommonJS 방식은 Browserify가 인기가 많았다.
Requirejs는 콜백 함수를 통해 모듈들을 전달받는 구조였기 때문에 모듈이 많아질수록 관리하기가 힘들었고, Browserify는 node.js로 코드를 작성해야 했기 때문에 모듈이 많아지면 node.js를 다루는 상황이 많아져 모듈 관리를 하나로 유지하고 싶었다.

반면, 웹팩은 AMD와 CommonJS를 동시에 지원하고, 기본적으로 부분을 캐싱하여 변경점만 번들링하는 방식이기 때문에 속도가 빠르고 테스터 런너와의 연동도 훨씬 좋다.

웹 개발 작업 자동화 도구

이전에는 프론트엔드 개발 업무를 할 때 가장 많이 반복하는 작업은 코드를 수정하고 저장한 뒤 새로 고침을 누르는 것이었다. 그래야 화면에 변경된 내용을 볼 수 있었다.

이외에도 웹 서비스를 개발하고 웹 서버에 배포할 때 아래와 같은 작업들을 해야 했다.

  • HTML, CSS, JS 압축
  • 이미지 압축
  • CSS 전처리기 변환

이러한 일들을 자동화 해주는 도구들이 필요했고, 이전에는 Grunt와 Gulp 같은 도구들이 등장했습니다.

Grunt VS Gulp VS Webpack

Grunt와 Gulp는 Task Runner이고, 웹팩은 Package Bundler입니다.

Task Runner : 반복 가능한 특정 작업을 자동화
Package Bundler : 종속성을 가진 애플리케이션 모듈을 정적인 소스로 재생산합니다.

Gulp는 종속성 관리를 할 수 없지만 웹팩은 종속성 관리가 가능하고 이는 규모가 큰 프로젝트에서 빛을 발한다.
또, 웹팩 커맨드를 실행할 때 --watch 옵션을 주면 변경 내용을 감시해서 적용할 수 있다.

웹 애플리케이션의 빠른 로딩 속도와 높은 성능

일반적으로 5초 이내에 웹 사이트가 표시되지 않으면 대부분의 사용자들은 해당 사이트를 벗어나거나 집중력을 잃게 된다.

그래서 웹 사이트의 로딩 속도를 높이기 위해 많은 노력들이 있었다.
그 중 대표적인 방법이 브라우저에서 서버로 요청하는 파일 숫자를 줄이는 것이다.
파일 숫자를 줄이기 위해 파일들을 압축하고 병합하는 작업을 진행했다.

뿐만 아니라 초기 페이지 로딩 속도를 높이기 위해 나중에 필요한 자원들은 나중에 요청하는 레이지 로딩이 등장했다.

웹팩은 기본적으로 자원이 필요할 때, 그 때 그 때 요청하자는 철할을 갖고 있다.
웹팩의 코드 스플리팅 기능을 이용하여 원하는 모듈을 원하는 타이밍에 로딩할 수 있다.

웹팩 설치

0. React + Typescript 설치

//npm 초기화
npm init -y

// 리액트 설치 
npm install --save react react-dom 

// 타입스크립트 설치 
npm install --save typescript @types/react @types/react-dom

ts-loader 설치
npm install -D ts-loader
  1. tsconfig.json파일 생성 및 내용 작성
{
  "compilerOptions": {
    "outDir": "./dist",
    "sourceMap": true,
    "noImplicitAny": false,
    "module": "commonjs",
    "target": "es6",
    "lib": ["es2015", "es2017", "dom"],
    "removeComments": true,
    "allowSyntheticDefaultImports": false,
    "jsx": "react",
    "allowJs": true,
    "baseUrl": "./",
    "paths": {
      "src/*": ["src/*"]
    }
  },
  "include": ["src"]
}

1. webpack 설치

npm install webpack webpack-cli webpack-dev-server --save-dev
  • webpack : 웹팩의 코어
  • webpack-cli : 터미널에서 웹팩 커맨드를 실행할 수 있도록 하는 도구
  • webpack-dev-server : 디스크에 저장되지 않는 메모리 컴파일을 사용하는 개발 서버
  1. webpack 세팅을 위한 파일을 생성한다.
touch webpack.config.js
위치는 package.json 이랑 같은 위치
  1. 플러그인 설치
npm install clean-webpack-plugin html-webpack-plugin -D
  • clean-webpack-plugin: 웹팩을 실행할 때마다 dist 폴더를 정리하는 플러그인
  • html-webpack-plugin: html 파일을 템플릿으로 생성할 수 있게 도와주는 플러그인
  1. webpack 초기 세팅을 해준다.(webpack.config.js)
const path = require("path");

const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //추가
const HtmlWebpackPlugin = require("html-webpack-plugin"); //추가

module.exports = {
  entry: "./src/index.tsx",
  resolve: {
    extensions: [".ts", ".tsx", ".js"],
  },
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.min.js",
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        use: "ts-loader",
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(), // 웹팩 실행시마다 dist 폴더 정리
    new HtmlWebpackPlugin({
      //index.html 자동 생성되도록 template 옵션 설정
      template: "./src/index.html",
    }),
  ],
};

Or

// path 모듈 불러오기
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    // 최종 번들링된 자바스크립트
    filename: 'main.js',
    // dist를 배포용 폴더로 사용
    path: path.resolve(__dirname, 'dist')
  }
}

entry: 배포 전 작업용 자바스크립트 시작점
output: 최종 배포용 번들링 파일 설정

  1. package.json에서 build 명령어를 세팅해준다.(package.json)
"scripts": {
  "build": "webpack"
},
  1. build test
npm run build

dist 폴더가 생성되는 것을 확인할 수 있다.
내부에는 main.js 파일이 생성되어 있다.
모든 자바스크립트 파일이 합쳐져서 main.js로 bundle된 것이다.

2. html 빌더 설치

  1. html도 빌드될 수 있도록 플러그인을 설치해준다.
npm install html-webpack-plugin
  1. webpack.config.js에 플러그인을 불러온 다음 설정해준다.
const path = require('path');

// html 플러그인을 불러오고
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  // 여기에 설정
  plugins: [new HtmlWebpackPlugin({
    template: "./src/index.html" // index.html을 기본 템플릿으로 반영할 수 있도록 설정
  })]
}
  1. 다시 build하면 dist 폴더에 index.html도 생성되어 있는 것을 확인할 수 있다.
npm run build

base-project
├── dist
│   ├── index.html
│   └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│   └── index.js
└── webpack.config.js

3. 화면에 실시간 업데이트 반영하기

  • webpack-dev-server를 설치하면 실시간으로 업데이트된 내용을 화면에서 확인할 수 있다.
  1. webpack-dev-server를 설치한다.
npm install webpack-dev-server -D
  1. webpack.config.js, package.json에 세팅해준다.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist') 
  },
  plugins: [new HtmlWebpackPlugin({
    template: "./index.html"
  })],
  devServer: {
    // 개발 서버가 dist 폴더를 제공할 수 있도록 설정
    static: {
      directory: path.resolve(__dirname, 'dist')
    },
    port: 8080
  }
}
  • package.json
"scripts": {
  "start": "webpack serve --open --mode=development",
  "build": "webpack --mode=production"
},
  • npm start : 개발 모드에서 사용하는 명령어이기 때문에 --mode=development로 모드를 설정해준다.
  • npm run build: 프로덕션 모드에서 사용하는 명령어이기 때문에 --mode=production로 모드를 설정해준다.
  1. 실행
npm start

4. internal 방식 스타일 시트

  • head에 스타일을 직접 작성하는 방식으로 스타일을 적용해보자.
  1. css-loader, style-loader 설치
npm install -D css-loader style-loader
  • css-loader : css 파일을 읽어주는 역할
  • style-loader : css를 < style> 태그로 만들어서 < head> 내부에 삽입해준다.
  1. 세팅
...

module.exports = {
  entry: './src/index.js',
  output: {
    ...
  },
  plugins: [new HtmlWebpackPlugin({
    ...
  })],
  module: {
    rules: [
      {
        test: /\.css$/,
		// use 배열은 뒤에서부터 적용된다.
        use: ["style-loader", "css-loader"] 
      }
    ]
  },
  devServer: {
    ...
  }
}
  1. src 폴더 안에 css를 생성 후 index.js에 import 해준다.
project
├── dist
│   ├── index.html
│   └── main.js
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── index.js
│   ├── style.css
│   └── util.js
└── webpack.config.js
  • src/index.js
// css를 가져온다
import './style.css'

document.getElementById("root").innerHTML = '안녕하세요✌️';
  • src/style.css
body {
	font-size: 30px;
	color: blue;
}
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<div id="root"></div>
	<!-- 스크립트를 삽입하지 않아도 웹팩에서 자동으로 스크립트를 삽입해준다. -->
	<!-- 아래 코드는 필요없다-->
	<!-- <script src="./dist/main.js"></script>  -->
</body>
</html>
  1. Restart.
npm start

< head> 영역에 < script>와 < style>이 자동으로 들어와 있음을 확인할 수 있다.

5. external 방식 스타일 시트

  • 외부 css 파일을 불러오는 방식으로 스타일을 적용해보자.
  1. mini-css-extract-plugin 설치
npm install -D mini-css-extract-plugin
  1. 세팅
  • webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 플러그인을 불러온다
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    ...
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./index.html"
    }),
    // 플러그인 추가
    new MiniCssExtractPlugin({
      filename: "common.css",
    })
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        // 다시 설정한다.
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      }
    ]
  },
  devServer: {
   ...
  }
}
  1. Restart
  • 외부 파일로 삽입된 것을 확인할 수 있다.

💡 internal 방식은 build 해도 CSS 파일이 따로 생성되지 않는다. 바로 head에 작성되기 때문이다.
반면, external 방식은 build 하면 별도의 CSS 파일이 생성된다.

6. 이미지 로더

  1. file-loader 설치
npm install -D file-loader

💡 Loader?
웹팩은 자바스크립트 파일뿐만 아니라 모든 웹 자원들도 모듈로 인식한다.
자바스크립트 파일에 이미지나 CSS 파일을 import해서 사용할 수 있게 해주는 게 바로 Loader다.
Loader는 빌드할 때 import한 자바스크립트 파일이 아닌 리소스들을 해석하고 변환해주는 역할을 한다.

  1. 세팅
...

module.exports = {
  entry: './src/index.js',
  output: {
    ...
  },
  plugins: [
    ...
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      },
      // file-loader 세팅
      {
        test: /\.(png|jpe?g|gif|svg|webp)$/i,
        use: ['file-loader'],
      }
    ]
  },
  devServer: {
   ...
  }
}

7. 사용하지 않는 build 파일 자동으로 지우기

build에 포함됐던 파일이 필요 없어졌을 때 삭제하고 다시 build하면 그대로 남아있는 것을 확인할 수 있다.
사용하지 않는 build 파일을 자동으로 삭제해주는 플러그인을 설치해보자.

  1. 설치
npm install -D clean-webpack-plugin
  1. 세팅
...

module.exports = {
  entry: './src/index.js',
  output: {
    ...
  },
  plugins: [
    ...
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"]
      },
      // file-loader 세팅
      {
        test: /\.(png|jpe?g|gif|svg|webp)$/i,
        use: ['file-loader'],
      }
    ]
  },
  devServer: {
   ...
  }
}

출처
https://velog.io/@nemo/webpack-setting
https://365kim.tistory.com/35

profile
가보자고

0개의 댓글

Powered by GraphCDN, the GraphQL CDN