⛓️ webpack ⛓️

박상은·2021년 12월 6일
1

🎁 분류 🎁

목록 보기
9/16
post-thumbnail

webpack이란 모던 JavaScript 애플리케이션을 위한 정적 묘듈 번들러입니다.
번들러란 하나의 웹서비스를 구성하는 모든 파일들의 연관관계를 파악한 후 하나로 합쳐주는 것을 말합니다.

  • 설치: npm i -D webpack webpack-cli

1. 단축속성

  • --config 파일명: 기본적으로 webpack.config.js를 사용하지만 다른 파일을 명시적으로 지정하는 속성
  • --mode=모드명: 모드 지정

2. Entry

최초 접근할 파일을 명시하는 설정입니다.
기본값은 ./src/index.js입니다.

entry에 명시된 파일을 기점으로 연관성 있는 모든 파일들을 번들링해줍니다.
연관성 있는 파일들이란 importrequire등을 이용해서 다른 파일들을 사용하거나 불러오는 경우를 의미합니다.

const path = require("path");

module.exports = {
  entry: "./src/index.js"
};

2.1 Entry 설정값들

  1. import: 시작 시 로드되는 모듈
  2. dependOn: 현재 엔트리 포인트가 의존하는 엔트리 포인트를 지정
  3. filename: 디스크에 있는 각 출력 파일의 이름을 지정 (?)
  4. library: (?)
  5. runtime: (?)
  6. publicPath: (?)

entry속성 내부에 여러개의 값을 지정(다중 엔트리 포인트)하면 따로 분리해서 번들링해준다.
다중 엔트리 포인트시 파일명은 output에서 지정할 수 있다.

const path = require("path");

module.exports = {
  entry: {
    a: "./src/index.js",
    b: {
      dependOn: "a",
      import: "./src/b.js"
    }
  }
};

2. Output

번들링된 파일명과 파일위치를 웹펙에 알려주는 설정입니다.
기본값은 ./dist/main.js입니다.
이외에 기타파일(js로 합칠 수 없는 파일들)들은 ./dist내부에 생성됩니다.

  • output.path: 번들링된 파일을 생성할 위치 결정
  • output.filename: 번들링된 파일을 이름 결정
const path = require("path");

module.exports = {
  output: {
    path: path.resolve(__dirname, "dist");
    filename: "my-first-webpack.bundle.js",
    // 다중 엔트리 포인트일 경우 [name], []
    // filename: "[name].js",
  },
};

3. Loaders

webpack은 기본적으로 JavaScriptJson만 이해할 수 있습니다.
따라서 다른 파일들을 포함해서 번들링할 경우 해당 파일을 변환시킬 수 있는 로더를 웹펙에 포함시켜줘야 합니다.

  • test: 변환이 필요한 파일들을 식별하는 속성 ( 정규표현식이용 )
  • use: 변환하는데 사용할 로더를 명시
module.exports = {
  module: {
    rules: [
      { test: /\.txt$/, use: "raw-loader" },
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: "asset/resource"
      }
    ],
  },
};

3. Plugins

번들 최적화, 에셋 관리, 환경 변수 주입 등과 같은 광범위한 작업을 수행할 수 있도록 도와준다.
따로 설치해야 하는 플러그인도 있고, 기본적으로 내장되어 있는 플러그인도 많으니 필요시 찾아보고 사용하면 된다.

// 번들링된 파일을 포함하는 html파일을 자동으로 생성해주는 플러그인
const HtmlWebpackPlugin = require("html-webpack-plugin");
//빌트인 플러그인
const webpack = require('webpack');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({ title: "웹펙 플러그인 테스트" }),
  ]
}

4. Mode

현재 어떤 모드에서 웹펙을 돌리는지 설정하는 옵션이다.
none, development, production이 존재한다.

기본값은 development이지만 명시를 안하면 경고를 줘서 명시하는 것이 좋은 것 같음

module.exports = {
  mode: "none",
};

5. 전체 적용 예시

const path = require("path");
const RefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  // 웹펙 시작 모드 설정
  mode: "development",

  // 디버깅을 위한 설정 배포 시 eval
  devtool: "source-map",

  // 경로 및 확장자 설정
  resolve: {
    extensions: [".jsx", ".js"],
    alias: {
      "@components": path.resolve(__dirname, "src/components"),
      "@util": path.resolve(__dirname, "src/util"),
      "@store": path.resolve(__dirname, "src/store"),
      "@pages": path.resolve(__dirname, "src/pages"),
      "@css": path.resolve(__dirname, "src/css"),
    },
    // 로더 해석에 적용되지 않음
    modules: ["node_modules", path.resolve(__dirname, "app")],
  },

  // 진입점 설정
  entry: {
    app: "./index.js",
  },

  // 빌드 결과물 위치 지정
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/",
  },

  // 로더 설정
  module: {
    rules: [
      // jsx 해석을 위한 babel로더 설정
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: "babel-loader",
        options: {
          // @babel/preset-env는 브라우저 환경에 맞게 알아서 바벨 설정을 해줌
          // @babel/preset-react는 jsx 지원
          presets: ["@babel/preset-env", "@babel/preset-react"],
          // dev server을 위한 설정, async와 await를 위한 설정
          plugins: ["react-refresh/babel", "@babel/plugin-transform-runtime"],
        },
      },

      // css를 위한 로더
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },

  // 플러그인 설정
  /**
  * HtmlWebpackPlugin: 새로운 HTML파일을 설정에 맞게 만들어줌
  * RefreshWebpackPlugin: 정확히는 모르지만 webpack-dev-server 사용할 때 적용해줘야 하는 플러그인
  */
  plugins: [new HtmlWebpackPlugin({ title: "bluegram" }), new RefreshWebpackPlugin()],

  // 데브서버 설정
  devServer: {
    // 번들링한 결과물을 저장할 위치 ( 메모리상 )
    devMiddleware: {
      publicPath: "/dist",
    },
    // 정적 파일들의 위치 지정
    static: {
      // 내 컴퓨터에서 공유할 파일들이 있는 경로
      directory: path.resolve(__dirname, "public"),
      // 브라우저상에서 접근할 경로
      publicPath: "/",
      // 정적 파일 수정시 페이지 새로고침 여부
      watch: true,
      // index 파일 없으면 브라우저에서 폴더를 보여줄지 여부
      serveIndex: true,
    },
    // 핫 모듈 리로딩 기능 ( 새로고침해도 기존 입력 정보는 유지 )
    hot: true,
    // 포트번호 설정
    port: 8080,
    // SPA의 react-router 같은 거 사용할 때 필수적으로 적용해 줘야 하는 옵션이다.
    // 기본적으로 /login으로 요청 보내면 404에러가나기 때문에 그때 index.js로 요청을 넘기게 해주는 옵션 값
    historyApiFallback: true,
  },
};

6. dev-server / watch

6.1 watch

변경을 감지하고 변경되면 자동으로 다시 번들링를 해주는 속성입니다.
단점은 번들링된 파일이 생성되지만 브라우저에 적용하려면 새로고침을 해줘야 합니다.
npx webpack --watch

6.2 dev-server

변경을 감지하고 변경되면 자동으로 변화를 적용시켜줍니다.

dev-server는 번들링된 파일을 생성하는 것이 아닌 메모리에 번들링한 파일내용을 저장시키고 바로 사용하는 것이므로 빌드된 결과물이 파일로 생성되지도 않으며, 메모리에 저장해둠으로서 더 효율적으로 메모리를 사용할 수 있습니다.

npm i -D webpack-dev-server
npx webpack serve --open

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

module.exports = {
  // 데브서버 설정
  devServer: {
    // 번들링한 결과물을 저장할 위치 ( 메모리상 )
    devMiddleware: {
      publicPath: "/dist",
    },
    // 정적 파일들의 위치 지정
    static: {
      // 내 컴퓨터에서 공유할 파일들이 있는 경로
      directory: path.resolve(__dirname, "public"),
      // 브라우저상에서 접근할 경로
      publicPath: "/",
      // 정적 파일 수정시 페이지 새로고침 여부
      watch: true,
      // index 파일 없으면 브라우저에서 폴더를 보여줄지 여부
      serveIndex: true,
    },
    // 핫 모듈 리로딩 기능 ( 새로고침해도 기존 입력 정보는 유지 )
    hot: true,
    // 포트번호 설정
    port: 8080,
    // SPA의 react-router 같은 거 사용할 때 필수적으로 적용해 줘야 하는 옵션이다.
    // 기본적으로 /login으로 요청 보내면 404에러가나기 때문에 그때 index.js로 요청을 넘기게 해주는 옵션 값
    historyApiFallback: true,
  },![](https://velog.velcdn.com/images/1-blue/post/41b54820-8968-4838-8f96-6def080315e7/image.png)

};

참고한 사이트

마무리

프로젝트 만들면서 추가되는 설정, 로더, 플러그인들을 계속 정리하면서 추가할 예정

0개의 댓글