웹팩 (심화)

< yujin />·2023년 3월 22일
0

우리는 이전에 웹팩(Webpack)이란 모듈 번들러(module bundler)를 사용하여 프로젝트를 빌드하는 방법을 배웠습니다. 그러나 이번에는 좀 더 나아가, 웹팩의 다양한 기능과 설정을 알아보겠습니다.

1. 웹팩 개발 서버(Webpack Dev Server)

개발 중인 애플리케이션을 브라우저에서 실시간으로 확인할 수 있다.
이 서버를 사용하면 개발 중인 코드를 수정할 때마다 애플리케이션이 자동으로 다시 로드된다.

// webpack.config.js:
module.exports = {
  devServer: {
    contentBase: path.join(__dirname, "dist"),
    publicPath: "/",
    host: "dev.domain.com",
    overlay: true,
    port: 8081,
    stats: "errors-only",
    historyApiFallback: true,
  },
}
  • contentBase: 정적파일을 제공할 경로. 기본값은 웹팩 아웃풋이다.

  • publicPath: 브라우져를 통해 접근하는 경로. 기본값은 '/' 이다.

  • host: 개발환경에서 도메인을 맞추어야 하는 상황에서 사용한다. 예를들어 쿠기 기반의 인증은 인증 서버와 동일한 도메인으로 개발환경을 맞추어야 한다. 운영체제의 호스트 파일에 해당 도메인과 127.0.0.1 연결한 추가한 뒤 host 속성에 도메인을 설정해서 사용한다.

  • overlay: 빌드시 에러나 경고를 브라우져 화면에 표시한다.

  • port: 개발 서버 포트 번호를 설정한다. 기본값은 8080.

  • stats: 메시지 수준을 정할수 있다. 'none', 'errors-only', 'minimal', 'normal', 'verbose' 로 메세지 수준을 조절한다.

  • historyApiFallBack: 히스토리 API를 사용하는 SPA 개발시 설정한다. 404가 발생하면 index.html로 리다이렉트한다.

이 외에도 개발 서버를 실행할때 명령어 인자로 --progress를 추가하면 빌드 진행율을 보여준다. 빌드 시간이 길어질 경우 사용하면 좋다.

2. Api 연동하기

// webpack.config.js
module.exports = {
  devServer: {
    before: (app, server, compiler) => {
      app.get("/api/keywords", (req, res) => {
        res.json([
          { keyword: "이탈리아" },
          { keyword: "세프의요리" },
          { keyword: "제철" },
          { keyword: "홈파티" },
        ])
      })
    },
  },
}

before에 설정한 미들웨어는 익스프레스에 의해서 app 객체가 인자로 전달되는데 Express 인스턴스다. 이 객체에 라우트 컨트롤러를 추가할 수 있는데 app.get(url, controller) 형태로 함수를 작성한다. 컨트롤러에서는 요청 req과 응답 res 객체를 받는데 여기서는 res.json() 함수로 응답하는 코드를 만들었다.
axios를 설치해서 model.js를 ajax 호출 후 응답된 데이터를 반환하도록 다음과 같이 수정한다.

// src/model.js:
import axios from "axios"

// const data = [
//   {keyword: '이탈리아'},
//   {keyword: '세프의요리'},
//   {keyword: '제철'},
//   {keyword: '홈파티'},
// ]

const model = {
  async get() {
    // return data

    const result = await axios.get("/api/keywords")
    return result.data
  },
}

export default model

목업 API : connect-api-mocker

  • 패키지 설치
npm i -D connect-api-mocker
  • 다음 코드로 수정
// webpack.config.js:
const apiMocker = require("connect-api-mocker")

module.exports = {
  devServer: {
    before: (app, server, compiler) => {
      app.use(apiMocker("/api", "mocks/api"))
    },
  },
}

실제 API 연동: devServer.proxy

  • ajax 요청부분 변경
// src/model.js
const model = {
  async get() {
    // const result = await axios.get('/api/keywords');

    // 직접 api 서버로 요청한다.
    const { data } = await axios.get("http://localhost:8081/api/keywords")
    return data
  },
}
  • CORS 이슈 해결을 위해 서비스 측에서 헤더 설정 추가
// server/index.js
app.get("/api/keywords", (req, res) => {
  res.header("Access-Control-Allow-Origin", "*") // 헤더를 추가한다
  res.json(keywords)
})
  • 프론트엔드 측에서 프록시 추가
// webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      "/api": "http://localhost:8081", // 프록시
    },
  },
}

핫로딩

싱글페이지어플리케이션은 브라우져에서 데이터를 들고 있기 때문에 리프레시 후에 모든 데이터가 초기화 되어버린다. 전체 화면을 갱신하는 대신, 변경한 모듈만 바꿔치기 해주는 기능이 핫 모듈 리플레이스먼트 이다.

// webpack.config.js:
module.exports = {
  devServer = {
    hot: true,
  },
}

최적화

코드가 방대해질수록 번들링한 결과물도 커지기 마련인데, 이를 최적화하기 위한 방법들이다.

  • Production mode
    mode를 "production"으로 설정하면 자바스크립트 결과물을 최소화 하기 위해 다음 일곱 개 플러그인을 사용한다.
FlagDependencyUsagePlugin
FlagIncludedChunksPlugin
ModuleConcatenationPlugin
NoEmitOnErrorsPlugin
OccurrenceOrderPlugin
SideEffectsFlagPlugin
TerserPlugin
// webpack.config.js:
const mode = process.env.NODE_ENV || "development" // 기본값을 development로 설정

module.exports = {
  mode,
}
// package.json
{
  "scripts": {
    "start": "webpack-dev-server --progress",
    "build": "NODE_ENV=production webpack --progress"
  }
}

npm run build로 빌드해보면, dev모드와 prod 모드의 차이점을 확인 할 수 있다.

  • optimazation 속성으로 최적화
    optimazation 속성은 빌드 과정을 커스터마지징할 수 있는 여지를 제공한다.

  • 설치
    npm i -D optimize-css-assets-webpack-plugin

  • 웹팩 설정 추가

// webpack.config.js:
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")

module.exports = {
  optimization: {
    minimizer: mode === "production" ? [new OptimizeCSSAssetsPlugin()] : [],
  },
}
  • prod모드에서 debugger 구문을 제거하는 플로그인 설치
npm i -D terser-webpack-plugin
  • 설정
// webpack.config.js:
const TerserPlugin = require("terser-webpack-plugin")

module.exports = {
  optimization: {
    minimizer:
      mode === "production"
        ? [
            new TerserPlugin({
              terserOptions: {
                compress: {
                  drop_console: true, // 콘솔 로그를 제거한다
                },
              },
            }),
          ]
        : [],
  },
}
  • 코드 스플리팅
    1) 엔트리 분리
// webpack.config.js
module.exports = {
  entry: {
    main: "./src/app.js",
    controller: "./src/controller.js",
  },
    optimization: {
    	splitChunks: {
      		chunks: "all", // 중복 코드 제거
    	},
	}
}

2) Dynamic import

3) externals
써드파티 라이브러리를 최적화해준다.

// webpack.config.js:
module.exports = {
  externals: {
    axios: "axios", //externals에 추가하면 웹팩은 코드에서 axios를 사용하더라도 번들에 포함하지 않고 빌드한다. 대신 이를 전역 변수로 접근하도록하는데 키로 설정한 axios가 그 이름이다.
  },
}
profile
잘하진 않지만 포기하진 않을거햐

0개의 댓글