webpack config

Intro


  • 기존에 돌아가는 서버를 바라보는 dev proxy server를 띄워 부분적으로 react component를 개발하는 환경을 만들어보자.
  • 그러기 위해서 사용하는 개발서버 webpack dev config 설정을 해보자.
  • 배포를 위한 webpack prod config 설정을 해보자.
  • webpack 개발을 위한 babel , react-hot-loader 등을 설정해보자.
  • webpack 을 node api 로 사용해보자.

Tech stack


  • webpack v4.0
  • react v16.2

Structure


├── config
│   ├── paths                       ## 경로 설정 ( 각자의 경로가 다르다면 여기서 수정)
│   ├── webpack.prod.config.js      ## 웹팩 prod config
│   ├── webpack.dev.config.js       ## 웹팩 dev config
│   ├── wepackDevServer.js          ## 웹팩 dev server용 config
├── scripts                         ## frontend 개발서버 , build , 배포 쪽 스크립트
│   ├── build.js                    ## 배포 build 
│   ├── start.js                    ## 개발서버 start 
├── src                             ## react 소스 폴더
│   ├── components                  ## components 들 모음 폴더
│   ├── App.js                      ## app 의 시작점
│   ├── index.js                    ## react render의 시작점
├── .babelrc
├── package.json                    
  

각 파일 설명


webpack.dev.config.js

const path = require("path");
const paths = require("./paths");

module.exports = {
  entry: ["./src/index.js"],
  output: {
    path: paths.appPublic,
    filename: "bundle.js"
  },
  devtool: "inline-source-map",
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  mode: "development",
  plugins: [],
  resolve: {
    modules: ["node_modules"]
  }
};

webpack 4에는 production 과 development mode 옵션이 생겨났다.

보통의 경우 development config 파일과 production config 파일 2개를 관리하게 된다.

  • webpack dev server 를 설정하고 기타 설정들을 위한 dev config
  • UglifyJsPlugin , 소스맵 , 뿐만아니라 배포를 위한 최적화 된 bundle.js 를 위한 기타 설정들을 위한 prod config

webpack 4 에선 --mode (production / development) 옵션으로 해당 옵션만으로

production 모드에선 minification과 hoisting , tree-shaking(불필요 한것을 떨군다.) 등등의 최적화 작업이 자동으로 이뤄지고 development 모드에선 다른 방식으로 optimized를 하면서 un-minified bundle을 내뱉어 준다.

mode 옵션에 대한 참고 : https://www.valentinog.com/blog/webpack-4-tutorial/#webpack4productionanddevelopment_mode

webpackDevServer

const noopServiceWorkerMiddleware = require("noop-service-worker-middleware");

module.exports = {
  public: "nodeapp.local:3001",
  inline: true, // live reloading insert bundle..
  hot: true, // hot module reloading
  compress: true, // enable gzip compression
  historyApiFallback: true,
  before(app) {
    //app.use(errorOverlayMiddleware());
    app.use(noopServiceWorkerMiddleware());
  },
  overlay: {
    warnings: true,
    errors: true
  }
};

webpack dev server 에 대한 기본적인 option 부분이다.

devServer 의 옵션

  • devServer.public : dev server 의 inline 모드와 proxying dev server 이용시, inline client scrtip는 항상 어디에 연결해야 하는지 모른다. client script는 server에 window.location 기준으로 추축하게 된다. 그러나 이게 실패할시 이 public을 이용하게 된다.
  • devServer.inline : dev server 에는 inline 모드와 hot 모드가 있다. default 는 inline 모드를 사용한다. 이것은 번들에 삽입되어서 live reloading을 지원하고 build 메세지를 브라우져 console에 보여준다.
  • devServer.historyApiFallback : HTML5 History API 를 사용할때(즉, SPA사용시), true로 설정하면 어느 404 응답대신 index.html을 제공된다. rewrites(Object or Array)를 이용하면 by passing을 설정할 수 있다.
  • devServer.contentBase : dev server 는 기존 프로젝트 루트에 있는 파일을 서비스 하는데 여기서는 proxy를 사용하기에 별도로 작성하지 않는다.
  • devServer.before() : dev 서버 안에 모든 내부 미들웨전에 실행하는 부분이다. 이부분은 커스텀 핸들러를 정의하는데 사용할 수 있다.
  • devServer.overlay : 컴파일 에러시 브라우져 화면에 overlay 로 보여준다.

noopServiceWorkerMiddleware

  • express의 미들웨어를 리턴하는 녀석으로 이전의 서비스 워커 설정들을 reset 시키는 녀석이다. ( 사실 react-create-app 에서 사용하기에 들고왔다. )
  • 아직 왜 필요한지는 파악하지 못함.
  • 서비스 워커란? https://b.limminho.com/archives/1384

webpack.prod.config

const path = require("path");
const paths = require("./paths");

module.exports = {
  entry: ["./src/index.js"],
  output: {
    path: paths.appPublic,
    filename: "bundle.js"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  mode: "production",
  plugins: [],
  resolve: {
    modules: ["node_modules"]
  }
};
  • dev.config 와 동일

paths.js

const path = require("path");
const fs = require("fs");
const url = require("url");

const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);

module.exports = {
  appPublic: resolveApp("public"),
  appBuild: resolveApp("build")
};
  • path 를 관리하는 장소 ( 상세 설명은 생략 )

start.js ( dev start )

"use strict";

process.env.BABEL_ENV = "development";
process.env.NODE_ENV = "development";

const Webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server");
const webpackConfig = require("../config/webpack.dev.config");
const webpackDevConfig = require("../config/webpackDevServer");
const open = require("open");

// setting
const host = process.env.HOST || "0.0.0.0";
const proxyUrl = "http://nodeapp.local:8081";
const publicPath = "/";
const port = process.env.PORT || 3001;
const devServerOptions = Object.assign({}, webpackDevConfig, {
  proxy: {
    "/": {
      target: proxyUrl,
      secure: false
    }
  },
  host,
  port,
  publicPath,
  stats: {
    colors: true
  }
});

webpackConfig.plugins.push(new Webpack.HotModuleReplacementPlugin());
webpackConfig.plugins.push(new Webpack.NamedModulesPlugin());

WebpackDevServer.addDevServerEntrypoints(webpackConfig, devServerOptions);
const compiler = Webpack(webpackConfig);
const server = new WebpackDevServer(compiler, devServerOptions);

server.listen(port, host, err => {
  if (err) {
    return console.log(err);
  }

  console.log("Starting server on http://nodeapp.local:3001");
  open("http://nodeapp.local:3001");
});

기본적으로 webpack 에선 express를 이용해서 devServer를 만듭니다.

webpack dev server 에 필요한 추가적인 부분을 작성합니다.

devServerOptions

  • proxy 라는 부분을 이용해서 "/" 경로로 들어왔을때 target 프록시 url로 요청을 보내서 받아오게 됩니다.
  • publicPath 라는 부분은 개발시에 실제 서버 경로 처럼 사용할 수 있게 만들어 줍니다. 예를 들어 "/asset" 으로 설정해놓으면 실제로 dev 개발할 시 bundle의 주소는 /asset/bundle.js 로 참고 하게 됩니다.

HotModuleReplacementPlugin

  • hot module replace 모드를 활성화 시켜줍니다.
  • 절대 production 모드에선 사용하지 않습니다.

NamedModulesPlugin

  • hot module replace 모드 사용시 모듈의 상대 경로를 표시해줍니다. 개발시에 추천되는 플러그인 입니다.

webpack dev 참고 :
https://webpack.js.org/guides/hot-module-replacement/#via-the-node-js-api https://github.com/webpack/webpack-dev-server/tree/master/examples/api/simple

build.js ( prod bundle )

const path = require("path");
const paths = require("../config/paths");
const chalk = require("chalk");
const fs = require("fs-extra");
const argv = require("yargs").argv;
const webpack = require("webpack");
const config = require("../config/webpack.prod.config");

function execute() {
  build().then(
    ({ stats }) => {
      console.log("build Success!!");
      copyPublicFolder();
    },
    err => {
      console.log("build error");
    }
  );
}

function build() {
  console.log("Creating an optimized production build...");

  let compiler = webpack(config);
  return new Promise((resolve, reject) => {
    compiler.run((err, stats) => {
      if (err) {
        return reject(err);
      }

      return resolve({ stats });
    });
  });
}

// copy folder and file
function copyPublicFolder() {
  fs.copySync(paths.appPublic, paths.appBuild);
}

execute();

실제 배포 번들을 만든 뒤 파일 copy 하는 부분

< 추가 되어야 할 부분 >

  • 실제 배포되야할 번들 파일 뒤에 번들 리비젼 붙이기
  • 기타 console.log 부분 제거와 optimized

Reference


  • 해당 폴더 구성과 파일 구성등은 Create React App 을 참고 하였다.
© 2021 Merlin.ho, Built with Gatsby