Home 03-webPack-기초-속성
Post
Cancel

03-webPack-기초-속성

참고자료 / 강의 링크 / 공식문서


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// webpack.config.js

const path = require('path');

module.exports = {
  // 선택한 모드를 통해 webpack이 알맞은 내장 최적화를 사용
  mode: "production", // "production" | "development" | "none"

  // ./src 를 기본으로 함
  // 애플리케이션이 여기에서 실행되며 webpack이 번들링을 시작 
  entry: "./app/entry", // string | object | array
  
  // webpack이 결과를 내보내는 방법과 관련된 옵션
  output: {
    // 모든 출력 파일의 대상 디렉터리는 반드시 절대 경로 여야함 (Node.js의 path 모듈을 사용)
    path:path.resolve(__dirname, "dist"), // string (기본값)
    filename: "[name].js", // string (기본값)
    }
  },
 
  // 모듈 관련 설정
  module: {
   	// 모듈에 대한 규칙 (로더 설정, 파서 옵션 등)
    rules: [
      {
        // 각각의 정규식 또는 문자열을 허용하는 일치 조건
        // test 및 include 동작은 동일하며 둘 다 일치해야함
        // exclude는 일치하지 않아야함 (test 및 include 보다 우선함)
        test: /\.js$/,
        loader: "babel-loader",
        include: [
          path.resolve(__dirname, "app")
        ],
        exclude: /node_modules/
      },
     {
        test: /\.(png|jpg|gif|svg)$/,
        loader: 'file-loader',
        options: {
        name: '[name].[ext]?[hash]'
        }
     }
  },
 // 파일의 연관관계를 해석할 때의 해석 방식을 지정
 // 모듈 요청 해석 옵션
  resolve: {
    // 모듈을 해석할 때 검색할 디렉터리
    modules: ["node_modules",path.resolve(__dirname, "app")],
        
    // 사용자가 import할 때 확장자를 생략 할 수 있도록 한다. 
    extensions: [".js", ".json", ".jsx", ".css"],
    
    // 모듈 이름 별칭 목록
    // 현재 컨텍스트 기준으로 별칭을 import
    alias: {
      "@": path.resolve(__dirname, "src/")
    },
  },
      
  // 브라우저 devtools에 대한 메타 정보를 추가하여 디버깅 향상
  // 빌드 속도는 느리나 가장 상세한 소스맵.
  devtool: "source-map", // enum

  // devServer 설정
  devServer: {
    port: 9000,
  },

  plugins: [
    // ...
  ],
}


1. entry

webpack이 번들 빌드를 시작하는 곳이다.

1) entry 유형

  • SPA(Single Page Application): 엔트리 포인트가 1개이다.
  • MPA(Multi Pate Application): 다중 엔터리 포인트를 갖고 있다.


1
2
3
4
5
6
7
8
9
// 다중 엔트리 포인트
module.exports = {
  //...
  entry: {
    home: './home.js',
    about: './about.js',
    contact: './contact.js',
  },
};


2) entry 파일

entry 속성에 지정된 파일에는 애플리케이션의 전반적인 구조와 내용이 담겨야 한다.

웹 팩이 해당 파일을 가지고 애플리케이션에서 사용되는 모듈의 연관 관계를 이해하고 분석하기에 애플리케이션을 동작시킬 수 있는 내용이 담겨야 한다.


1
2
3
4
5
6
7
8
9
10
// 예시) vue의 main.js

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

const app = createApp(App);
app.use(store).use(router);
app.mount("#app");


2. output

output속성에는 웹팩으로 번들링 한 결과물을 저장하는 파일 경로를 의미한다.

1) Path

캐싱 가이드

모든 출력 파일의 대상 디렉터리는 반드시 절대 경로여야 한다. (Node.js의 path 모듈을 사용)


2) 파일 이름 옵션

  • 단일 엔트리 포인트의 경우, 정적인 이름으로 설정할 수 있다.
  • 그러나 둘 이상의 엔트리 포인트 , 코드 뿐할 또는 다양한 플러그인을 통해 여러 번들을 생성할 때 다음과 같은 파일 이름 옵션을 사용하여 각 번들에 고유한 이름을 부여해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
  output: {
    // 엔트리의 이름을 사용
    filename: '[name].bundle.js'
      
    // 내부 청크 id를 사용
    filename: '[id].bundle.js'
      
    // 여러 옵션을 조합해서 사용
    filename: '[name].[hash].bundle.js'
      
    // 생성된 콘텐츠에서 생성된 해시를 사용 
    filename: '[chunkhash].bundle.js'
  }
};


3. module

프로젝트 내에서 다른 유형의 모듈을 처리하는 방법을 결정한다.

공식문서

1
2
3
4
5
6
// webpack.config.js
module.exports = {
  module: {
    rules: []
  }
}


1) rules

모듈이 생성될 때 요청과 일치하는 Rule의 배열이다. 이러한 규칙은 모듈 생성 방법을 수정할 수 있다.

로더를 모듈에 적용시키거나 파서를 수정할 수 있다.

  • test: loader를 적용할 모듈 (정규식 사용)
  • use: 해당 모듈에 적용되는 Loader의 배열
    • use: ["style-loader"]use:[{loader: "style-loader"}]와 같다.
    • 여러 로더를 전달하여 연결할 수 있으며, 맨 오른쪽에서 부터 순차적으로 로더가 적용된다.
    • ex) use: ["style-loader", "css-loader", "scss-loader"]
  • exclude: 조건과 일치하는 모든 모듈을 제외한다.
  • include: 조건과 일치하는 모든 모듈을 포함한다.


2) loader가 필요한 이유

만약 loader없이, 다른 유형의 모듈 파일을 엔트리 파일에 import하려고 하면 다음과 같은 에러가 발생한다.

1
2
3
ERROR in ./base.css 1:2
Module parse failed: Unexpected token (1:2)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
  • 이는 base.css를 loader없이 index.js(엔트리 파일)에 import하려고 해서 발생한 오류이다.
  • 해당 파일 타입을 다루기 위해 loader를 사용하라는 의미이다.


4. plugin

다양한 방법으로 webpack 빌드 프로세스를 사용자 정의하는 데 사용된다.

공식 문서

1
2
3
4
// webpack.config.js
module.exports = {
  plugins: []
}
  • 웹팩의 기본적인 동작에 추가적인 기능을 제공하는 속성이다.
  • 플러그인은 해당 결과물의 형태를 바꾸는 역할을 한다.
  • 플러그인의 배열에는 생성자 함수로 생성된 객체 인스턴스만 추가될 수 있다.


1) 플러그인 예시

MiniCssExtractPlugin을 사용한다면 다음과 같이 코드를 작성할 수 있다.

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
var path = require("path");
var MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  mode: "none",
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [{ loader: MiniCssExtractPlugin.loader }, "css-loader"],
      },
    ],
  },
  // 결과물에 대한 정보를 바꾼다.
  plugins: [new MiniCssExtractPlugin()],
};

해당 플러그인의 사용 전 후는 다음과 같다.

사용 전

image-20220904210523154


사용 후

image-20220904210443086


이렇게 dist 폴더의 구조가 변경된다. 해당 플러그인은 CSS파일을 필요로하는 JS파일만 CSS파일을 생성한다. 그 결과, bundle.js에는 css가 포함되어 있지 않다.

해당 플러그인을 사용하면 html에 직접 스타일 시트를 추가해야 한다. 이전에는 bundle.js에 css가 포함되어 있어서 style-loader를 사용하면 추가할 필요가 없었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>CSS & Libraries Code Splitting</title>
    <!-- style-loader를 사용하지 않고 직접 추가한다.  -->
    <link rel="stylesheet" href="./dist/main.css" />
  </head>
  <body>
    <header>
      <h3>CSS Code Splitting</h3>
    </header>
    <div>
      <p>This text should be colored with blue after injecting CSS bundle</p>
    </div>
    <!-- 웹팩의 빌드 결과물을 로딩하는 스크립트 -->
    <script src="./dist/bundle.js"></script>
  </body>
</html>


5. devServer

공식 문서

개발을 할 때, 수정한 코드를 확인하려면 매번 빌드를 해야 한다. 이런 불편함을 없애기 위해 webpack의 dev 서버를 사용할 수 있다.

  • webpack dev 서버는 빌드를 매번 안 해도 코드의 변경 사항을 확인 할 수 있다.
  • npm run dev 명령어는 dist 폴더를 생성하지 않는다.
  • 즉, 메모리에서 빌드 결과물을 그냥 올려놓는다.
  • 메모리 상으로만 빌드 결과물 올려놓아 실시간 확인이 가능하다.


1
2
# 필요한 라이브러리 설치
$ npm i webpack webpack-cli webpack-dev-server html-webpack-plugin -D


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// package.json
{
  "name": "devserver",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    
    // dev 서버를 여는 명령어 추가 
    "dev": "webpack-dev-server",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.42.0",
    "webpack-cli": "^3.3.11",
    "webpack-dev-server": "^3.10.3"
  }


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

const path = require('path');

module.exports = {
  mode: 'developement',
  entry: './index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devServer: {
    port: 9000,
  },
};


6. merge

merge를 활용하면 Webpack 설정 파일을 나눠서 관리할 수 있다.

1) 폴더 생성

1
2
# Webpack 개발, 서버, 빌드, 유틸리티 구성 파일을 webpack 디렉토리 안에 생성한다. 
$ code webpack/config.{dev,server,build,utils}.js


2) 각 파일 설정

1
2
3
4
5
// webpack/config.utils.js

const path = require('path');
const getAbsPath = (dirOrFile) => path.resolve(process.cwd(), dirOrFile);
exports.getAbsPath = getAbsPath;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 개발 구성
// webpack/config.dev.js

const { getAbsPath } = require('./utils');

const devConfig = {
  target: 'web',
  mode: 'development',
  devtool: 'eval-source-map',
  entry: {
    main: getAbsPath('src/index.js'),
  },
  output: {
    path: getAbsPath('public'),
    filename: 'js/main.js',
  }
};

module.exports = devConfig;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 서버 구성
// webpack/config.server.js

const { merge } = require('webpack-merge');
const devConfig = require('./dev');

const serverConfig = {
  devServer: {
    static: ['public'],
    client: {
      overlay: true,
    },
    compress: true,
    host: 'localhost',
    port: 3000,
    open: false,
  },
};

module.exports = merge(devConfig, serverConfig);


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 빌드 구성
// webpack/config.build.js

const { merge } = require('webpack-merge');
const { getAbsPath } = require('./utils');
const devConfig = require('./dev');

const buildConfig = {
  mode: 'production',
  devtool: false,
  output: {
    path: getAbsPath('public'),
    filename: 'js/bundle.min.js',
  },
};

module.exports = merge(devConfig, buildConfig);


1
2
3
4
5
6
7
8
9
10
// package.json 

{
	"scripts": {
		"start": "npm run dev -- --open",
    "bundle": "webpack --config webpack/config.dev.js",
    "dev": "webpack serve --config webpack/config.server.js",
    "build": "webpack build --config webpack/config.build.js"
  },
}


This post is licensed under CC BY 4.0 by the author.