웹팩(Webpack) 쓰는 이유 / 사용 방법


웹팩(module bundler) 쓰는 이유
2000년대 초반의 웹페이지는 각 페이지마다 새로운 html을 요청해서 화면을 나타냈다. 자바스크립트는 DOM을 조작하는 간단한 역할만 했었기 때문에 html의 script태그에 넣는 것으로도 충분했다. ajax가 유행했을 때는 자바스크립트의 비중이 조금 더 커졌지만 그래 봐야 페이지당 자바스크립트 파일 몇 개면 충분했다 SPA(single page app)는 하나의 html에 수십, 수백 개의 자바스크립트 파일을 포함하기 때문에 더 이상 기존 방식이 통할리 없었다.
<html>
<head>
<link rel="stylesheet" type="text/css" href="javascript_file_1js">
<link rel="stylesheet" type="text/css" href="javascript_file_2js">
기타 수많은 자바스크립트 파일
<link rel="stylesheet" type="text/css" href="javascript_file_999js">
</head>
</html>
위의 방식으로는 계속 늘어나는 자바스크립트 파일을 관리하기 힘들다. 또한 선언되는 순서도 신경 써야 하고, 기존에 생성된 전역 변수를 덮어쓰는 위험도 존재한다.
모듈 시스템이 필요하다
자바스크립트는 태생이 브라우저에 종속적이었기 때문에 자체적인 모듈 시스템이 없었다. 모듈 시스템은 C++이나 자바에서 include나 import 키워드를 떠올리면 이해하기 쉽다. 자바스크립트 최신 표준인 ES6부터 모듈 시스템이 포함됐지만 아직 모든 브라우저가 지원하지 않고 있다. 모든 브라우저가 지원한다 하더라도 다수의 유명한 라이브러리가 ES6 표준으로 작성되지 않았다는 게 큰 걸림돌이다.
브라우저에 얽매이지 말자
예전부터 자바스크립트를 브라우저 밖에서 사용할 수 있게 하려는 노력이 있었다. 대표적인 표준 위원회는 CommonJS, AMD가 있다. 이들이 자바스크립트를 범용적으로 사용하기 위해서 하는 대부분의 일은 모듈 시스템을 정의하는 일이었다. 그리하여 nodejs 같은 프레임워크가 등장할 수 있었고 자바스크립트가 서버에서 돌아가는 세상이 되었다.
SPA개발은 webpack과 함께
webpack은 CommonJS와 AMD 스펙 모두를 지원한다. webpack을 사용하면 여러 개의 자바스크립트 파일을 하나의 파일(원한다면 여러 개)로 컴파일할 수 있다. 그리하여 SPA개발 시 html에는 컴파일된 하나의 자바스크립트 파일만 포함시키면 된다 고마운 점은 ES6 표준으로 작성되지 않은 라이브러리도 알아서 잘 처리해준다는 점이다 따라서 필요한 라이브러리를 npm으로 설치 후 필요한 부분에 import만 하면 바로 사용할 수 있다.
webpack의 장점 1: 파일 분할 기능
수백 개의 자바스크립트 파일을 하나의 파일로 컴파일하는 건 좋은 생각이 아니다. 이렇게 하면 사용자가 첫 페이지를 보기 위해 몇 초를 기다려야 할 수도 있다 webpack에는 다양한 파일 분할 기능이 있다.
vendor코드만 따로 분리해서 하나의 파일로 만들 수 있다. vendor코드는 자주 변경되지 않기 때문에 사용자의 브라우저에 캐싱 후 오랫동안 재사용될 수 있다 이 방법만 사용해도 사용자 경험을 상당 부분 끌어올릴 수 있다 하지만 첫 방문자의 경우에는 의미가 없다.
requireensure 구문을 사용해서 파일 분할을 지정할 수 있다. 이 방법은 requireensure 구문을 실행할 때 필요한 파일을 on-demand로 다운로드한다(webpack이 알아서 해준다-_-b) 따라서 첫 방문자의 경우에도 전체 코드를 다운로드할 필요가 없기 때문에 반응 속도가 빠르다 첫 페이지 로딩은 빠르지만 이후 필요한 부분의 파일을 다운로드해야 하기 때문에 분할된 코드의 크기가 너무 크지 않도록 주의해야 한다 react에서는 route별로 파일을 만드는 방법이 많이 사용된다. webpack에서는 컴파일된 파일의 이름에 hash값을 붙이는 기능이 많이 사용된다. 해당 파일이 변경된 경우에만 hash값이 변경된다 따라서 변경되지 않은 파일은 사용자의 브라우저에 캐싱된 파일이 재활용된다.
webpack의 장점 2: 다양한 loader를 사용할 수 있다
대부분의 loader는 파일을 입력으로 받아서 자바스크립트 파일을 출력해준다. loader를 사용하면 webpack이 컴파일을 하기 전에 원하는 파일에 대해서 전처리를 할 수 있다 jsx라는 react 고유의 문법으로 작성된 파일을 자바스크립트 파일로 변환할 때 많이 쓰인다. 그 외에도 babel-loader를 이용해서 ES6, ES7과 같은 최신 자바스크립트 문법을 사용할 수도 있다. 여러 개의 loader를 체인 형식으로 묶을 수도 있다 예를 들어 babel-loader와 eslint-loader를 묶어서 먼저 eslint로 정적 분석을 하고 성공하면 babel-loader가 jsx파일을 자바스크립트 파일로 변환하게 할 수 있다.
또 다른 대표적인 예는 style-loader와 css-loader를 같이 쓰는 경우이다 css를 사용할 때 어려운 점 중의 하나가 클래스 이름을 겹치지 않게 정의하는 것이다 css-loader는 import 하는 모듈의 id값을 클래스 이름에 자동으로 붙여주는 기능을 갖고 있다 따라서 단순히 클래스 이름을 ‘button’으로 정의하더라도 이름이 겹칠까 봐 걱정할 필요가 없어진다 style-loader는 css-loader가 출력하는 css정보를 받아서 style태그로 만들고 그것을 DOM에 붙여준다.
웹팩 설치
npm i webpack webpack-cli
// webpack: package we use in a file
// webpack-cli: package we use in the console
웹팩 폴더 설정법

assets/js,css
package.json 파일
"scripts": {
"dev:server": "nodemon --exec npx babel-node init.js",
"dev:assets": "cross-env WEBPACK_ENV=development webpack -w",
"build:assets": "cross-env WEBPACK_ENV=production webpack"
}
- dev:assets: 웹팩을 불러오는 역할
- build:assets: 웹팩을 서버로 올려주는 역할
- -w : --watch: webpack can watch files and recompile whenever they change build assets webpack
- npm run dev:server로 실행
webpack.config.js 파일
**: Default file that webpack looks for when we call it
**
-
서버와 연결시키는 코드는 없고, 100% 클라이언트 코드와 관련되어있다.
-
바벨노드를 사용할 수 없기에 구버전 코드를 써서 작성한다.
-
config 객체에 설정을 넣어야 웹팩이 비로소 파일 다루는 법을알게된다.
-
Write all the transform instructions for webpack in the 'rules' array inside of the 'modules' object
const path = require("path");
// path는 node.js에 기본적으로 깔려있는 패키지다.
// 파일을 가져오기 위해 path사용
const Dotenv = require("dotenv-webpack");
const MODE = process.env.WEBPACK_ENV;
//env를 webpack이 넘겨받지 못해서 수동으로 env를 넘겨받도록 한다.
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ENTRY_FILE = path.resolve(__dirname, "assets", "js", "script.js");
// entry: 현재 프로젝트 디렉토리/assets/js/main.js
// path.resolve(): used to resolve a sequence of path-segments to an absolute path.
const OUTPUT_DIR = path.join(__dirname, "static");
// output: 현재 프로젝트 /static
// path.join(): joins the specified path segments into one path.
const config = {
entry: ENTRY_FILE,
output: {
path: OUTPUT_DIR,
filename: "[name].js",
},
module.exports = {
entry: ENTRY_FILE,
output: {
filename: "[name].js",
path: OUTPUT_DIR,
},
mode: MODE,
module: {
rules: [
{
test: /\.js$/,
exclude: "/node_modules",
use: ["babel-loader"],
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "styles.css",
}),
],
devtool: "source-map",
};
module.config = config
// export dafault config;
- 절대경로(Absolute path): C:/users/documents/projects
- 상대경로(Relative path): ./projects
- 상위, 상위 디렉토리: ../../, 루트 디렉토리:/
- __dirname: 현재 프로젝트 디렉토리 이름, Node.js 전역 변수
- entry: 파일이 어디서 왔는가, is a path to the root file of our app
- output: 그걸 어디에 넣을 것인가, is a path to the directroy where all the transformed assets should go
- Loaders: teach webpack how to transform the files, loaders used From last to fisrst in webpack
- "modules" object
- allows us to specify different transformations for different file formats.
- How many loaders can we have inside if one rule? -> min1, max inf
- devtool: "source-map"
SCSS추가하기
test: /\.(scss)$/
- SCSS인 파일을 전부 찾아라
use
-
가장먼저 CSS로 바꾸고
-
CSS에 해당하는 텍스트 부분만 추출해서
-
추출된 CSS를 분리된 하나의 파일로 만들기
postcss-loader
autoprefixer라는 옵션을 통해 다양한 웹 브라우저에서 호환가능한 css코드로 변환시켜준다.