본문 바로가기

Web.d

[React][Webpack] webpack, babel 로 시작하기 (without CRA)

반응형

https://github.com/joohaem/boilerplate-webpack-without-cra

 

GitHub - joohaem/boilerplate-webpack-without-cra: setting Webpack, Babel without CRA

setting Webpack, Babel without CRA. Contribute to joohaem/boilerplate-webpack-without-cra development by creating an account on GitHub.

github.com

 


Webpack이란?

JS 모듈을 파일 단위로 관리하다 보니, 자연스레 파일이 많아지게 된다

한 편, 브라우저에는 한 번에 보낼 수 있는 HTTP 요청 수의 제한이 있기 때문에,

이를 묶어 처리하는 번들러 라이브러리(Webpack, Parcel 등)가 필요해졌다

 

[Fig. 1] bundler

 

그 중 가장 인기 있는 모듈 번들러 중 Webpack 이 있고

이를 세팅하는 코드를 정리해놓았다

 


시작하기

$ yarn init -y
// All Yes

$ yarn add react react-dom
// npm으로 설치한 react와 react dom을 불러오게 되면
// CDN으로 파일(react, babel)을 불러오지 않아도 된다.

$ yarn add -D @babel/core babel-loader @babel/preset-env @babel/preset-react
// @babel/core: babel의 핵심 라이브러리로 es6를 es5로 컴파일
// babel-loader: babel과 webpack을 사용해서 자바스크립트 파일을 컴파일
// @babel/preset-env: es6, es7 버전을 지정안해도 babel이 자동 탐지
// @babel/preset-react: 리액트(JSX)를 js로 인식가능

$ yarn add -D webpack webpack-cli webpack-dev-server
// webpack-cli - 웹팩을 커맨드라인에서 실행할 수 있게 해 줌
// webpack-dev-server - 파일이 변화할 때마다 실시간으로 빌드하는 개발 서버 구동 (우리가 실행하는 dev 서버)

$ yarn add -D babel-loader css-loader style-loader
// babel-loader - jsx 파일과 최신 자바스크립트 문법을 변환(바벨과 연동)
// css-loader - css 파일을 해석(import or require)
// style-loader - css를 dom(style 태그로 head)에 삽입

$ yarn add html-webpack-plugin
// html-webpack-plugin - html 파일에 번들링 된 js 파일을 삽입

 

 


Webpack 및 Babel 설정

.babelrc 파일 생성

 

// 바벨에 대한 플러그인을 설정,
// presets(번들 파일)에 한번만 설정하면 플러그인들이 자동으로 설치

{
    "presets": ["@babel/preset-env", "@babel/preset-react"]
}

 

webpack.config.js 파일 생성

 

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

const port = process.env.PORT || 3000;

module.exports = {
  // development 모드는 개발자 경험에 초점이 맞춰진 모드
  // production모드는 배포에 초점이 맞춰진 모드
  mode: "development",

  // filename의 [hash]는 어플리케이션이 수정되어
  // 다시 컴파일될 때마다 Webpack(웹팩)에서 생성된 해시로 변경해 캐싱
	// build 시 확인 가능
  // entry가 하나여야, SPA 임
  // entry:'./src/index.js', 설정 기본값
  output: {
    path: __dirname + "/dist",
    filename: "bundle.[hash].js",
  },

  module: {
    rules: [
      // 첫 번째 룰
      // .babelrc를 babel-loader를 이용해 규칙에 적용
      {
        test: /\\.(js)$/,
        exclude: /node_modules/,
        use: ["babel-loader"],
      },
      // 두 번째 룰
      {
        test: /\\.css$/,
        use: ["style-loader", "css-loader"],
        // 각 로더에 옵션 적용 가능
        // 좌 <- 우 순서로 적용되기 때문에 위와 같은 순으로 작성해주어야 함
      },
    ],
  },

  plugins: [
    // HtmlWebpackPlugin은 html파일이나 favicon을 번들링과정에 포함
    // 예를들어 번들된 파일 bundle.[hash].js를 index.html에 자동 삽입
    new HtmlWebpackPlugin({
      template: "public/index.html",
    }),
  ],

  // 개발 서버 정의
  devServer: {
    host: "localhost",
    port: port,
    // 서버 실행 시 자동으로 브라우저 열어주는 옵션
    open: true,
    // 브라우저에서 URL 변경하도록 도와주는 옵션
    historyApiFallback: true,
  },
};

 

  • webpack.config.js, CRA의 다양한 옵션들
    (참고 : https://berkbach.com/create-react-app-%EC%9D%98-webpack-config-js-%EB%93%A4%EC%97%AC%EB%8B%A4%EB%B3%B4%EA%B8%B0-78e40bf37313)
    • mode: webpack에게 현재 모드를 알려주는 옵션이다.
      production은 최적화되어 빌드되고,
      development는 (최적화 없이) 빠르게 빌드된다.
    • entry: 앱을 번들할 때 시작 경로를 정의한다.
      배열로 받을 경우 시작시 모든 모듈이 하나의 파일로 합쳐 로드된다.
    • output: 번들을 완료한 파일을 설정한다. 
      이에 있는 정보를 통해 빌드 파일을 생성한다.
      path 는 파일을 저장할 경로 입니다. 
      pathinfo 는 모듈에 관련된 내용을 주석으로 표시합니다. 
      production 일 때는 안하는 것이 좋습니다. 
      filename 은 번들을 완료한 파일의 이름을 정의합니다. 
      futureEmitAssets 는 webpack-5 에서 없어진다고 하니 중요하지 않아보여서 넘어 가겠습니다. 
      chunkFilename 은 청크 파일의 이름을 정의합니다. 
      publicPath 는 브라우저에서 참조될때 출력 파일의 공용 URL 주소를 지정합니다. 
      devtoolModuleFilenameTemplate 은 source-map의 소스 배열을 커스터마이징 합니다. 
      jsonpFunction 는 여러 개의 webpack이 작동할 때 충돌을 막기위해 설정합니다. 
      globalObject 는 전역변수를 설정하는 부분입니다.
      기본 값은 window 입니다.
    • module: loader 를 설정하는 부분입니다.  
      strictExportPresence 는 경고 대신 에러를 보냅니다.
      rules 로 loader를 설정합니다.
      이는 번들링 과정에서 사용할 규칙을 설정합니다.
    • plugins: plugin을 설정합니다.
    • devServer: 개발 서버를 정의하는 옵션입니다.
    • resolve: 이 옵션은 모듈을 해석하는데 관여합니다.
      모듈을 해석할 때 modules 로 먼저 탐색할 폴더를 지정할 수 있습니다. 
      extensions 로 .ts , .jsx 와 같은 확장자를 관리할 수 있습니다.
      여기서는 paths.js/moduleFileExtensions 로 관리하고 있습니다. 
      alias 는 모듈에 별명을 주어서 간단하게 import , require 를 할 수 있습니다. 
      plugins 는 모듈 해석에 대한 plugin 입니다.
    • bail: True 일 경우 첫 번째 오류를 허용합니다.
      여기서는 production 일 때만 허용합니다.
    • devtool: 어떤 source-map 을 사용할지 결정하는 부분입니다. 
      source-map 이란 원본 코드와 빌드된 코드를 매핑 해주는 방법입니다.
      CRA 에서는 production 일 때는 source-map , development 일 때는 cheap-module-source-map 을 사용하는군요.
      근데 source-map 를 넣었을 때 원본 코드가 드러나는 경우가 있어서 source map 을 안쓰는 사람도 있습니다.
      또 쓰더라도 source-map 의 성능이 안 좋아서 source-map 대신 cheap-module-source-map 를 사용하는 경우도 있습니다.
    • optimization: webpack 4 부터 mode 에 따라서 설정이 가능해졌습니다. 
      minimize 는 TerserPlugin 이나 minimizer 에 따로 정의된 plugin 을 사용해서 번들한 파일을 최소화 할지 결정합니다. 
      minimizer 는 TerserPlugin 을 커스터마이징 하거나 기본 값으로 minimize 에 사용될 minimizer 를 설정합니다.
      여기서는 TerserPlugin 커스터마이징과 OptimizeCSSAssetsPlugin 을 추가해서 사용했네요. 
      splitChunks 는 청크 파일에서 중복되는 모듈을 모으는 역할을 합니다. 
      runtimeChunk 를 true 나 설정을 하면 런타임만 포함하는 각 진입점에 청크가 추가됩니다.
    • resolveLoader: resolve 와 같은 속성을 갖지만 resolveLoader는 loader 모듈만 해석합니다.
    • node: 노드 객체를 설정합니다. 
      true, false, empty, mock 값으로 객체를 설정할 수 있습니다. 
      true 는 polyfill 을 제공합니다. 
      false 는 어떤 것도 반환하지 않습니다. 
      empty 는 빈 객체, mock 은 mock 객체를 반환합니다.

 

 


index, App 파일 생성

src/index.js

 

// import React from "react";
// import ReactDom from "react-dom";
// import App from "./App";
const React = require("react");
const ReactDom = require("react-dom");
const { default: App } = require("./App");

ReactDom.render(<App />, document.querySelector("#root"));

 

src/App.js

 

import React from "react";
import "./App.css";

export default function App() {
  return (
    <div className="main_wrapper">
      Hello, World !!
    </div>
  );
}

 

src/App.css

 

.main_wrapper {
  color: rgb(224, 75, 113);
}

 


에러 짚기

 

Module not found: Error: Can't resolve './src/index.js'

Module not found: Error: Can't resolve './App’

: jsx 를 js 로 변환해주지 못하기 때문에, ./src/index.js / App.js로 명명해야 한다

이는 파일명을 수정하거나, 다음 코드를 추가하여 해결할 수 있다

 

resolve: {
  extensions: ['.js', '.jsx'],
},

 

Uncaught ReferenceError: main_wrapper is not defined

: style-loader 와 css-loader 가 적용되지 않는 것 같았다,

다음과 같이 해결하였다

(공식 문서: https://webpack.js.org/loaders/style-loader/)

 

// webpack.config.js

use: [
  {
    loader: "style-loader",
  },
  {
    loader: "css-loader",
    options: {
      // CSS Module, CamelCase 사용
      modules: true,
      camelCase: true,
    },
  },
],

// 위 코드를 아래와 같이 수정

use: ["style-loader", "css-loader"],

 

 


react-hot-loader

코드가 변경되었을 때 페이지를 새로고침 하지 않고

바뀐 부분만 빠르게 교체해주는 라이브러리

 

$ yarn add -D react-hot-loader

 

// .babelrc

{
    "presets": ["@babel/preset-env", "@babel/preset-react"],
    "plugins": ["react-hot-loader/babel"]
}

 

// webpack.config.js

...
module.exports = {
	...
  output: {
    ...
    publicPath: '/'
		// Hot reloading은 중첩된 경로에서 동작하지 않아
    // 설정해주지 않을 경우 Hot reloading이 작동이 안 됨
  },
};

 

// App.js

import { hot } from 'react-hot-loader';
...
export default hot(module)(App);

 


글을 줄이며

위 본문은 정말 기본적인 사항들만 있지만, 웹팩 설정은 정말 무궁무진하다

 

동료와 이야기를 나누며

CRA의 웹팩 설정을 살펴보기(참고 : https://maxkim-j.github.io/posts/cra-webpack-config) ...
에서 멈출 것이 아니라 이를 custom 하는 방향이 필요하겠다 싶었다

CRA 정말 간단하고 좋지만 그만큼 무게도 상당하기에!

 

CRA의 custom을 위한 키워드는 다음과 같다

  • CRA yarn eject
    (숨겨져 있던 모든 설정들과 패키지들의 의존성들을 볼 수 있다,
    그러나 이전 상태로 돌아갈 수 없고 config들을 직접 유지보수 해야하게 된다)
  • customize-cra / react-app-rewired
    (eject 없이 custom 할 수 있도록 하는 라이브러리)
  • typescript custom / terserplugin / ...

차차 공부해보도록 하자

 


참고 문서

https://velog.io/@_uchanlee/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%9B%B9%ED%8C%A9%EC%9C%BC%EB%A1%9C-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0without-CRA

 

리액트 웹팩으로 개발 환경 구축하기(without CRA)

지인의 블로그를 보다가 충격적인 사실을 발견했다."내가 회사에 가서도 CRA를 통해 개발할까? " 🤔에 대한 답변이 X(아니?) 라는 사실이였다. 몇개월 뿐이지만 리액트를 공부한 시점부터 현재까

velog.io

https://nukw0n-dev.tistory.com/25?category=979146 

 

Babel이란? (preset, polyfill, plugin 등)

https://babeljs.io/ Babel · The compiler for next generation JavaScript The compiler for next generation JavaScript babeljs.io 1. 배경 ES6가 등장한 지 얼마 되지 않았을 때에는 대부분의 브라우저에서..

nukw0n-dev.tistory.com

https://velog.io/@kim-jaemin420/CRA%EC%9D%98-%EC%9B%90%EB%A6%ACbabel-webpack-%EB%B9%8C%EB%93%9C%ED%95%98%EA%B8%B0

https://blog.joyfui.com/1243

https://medium.com/@jsh901220/create-react-app%EC%97%90%EC%84%9C-eject%EC%82%AC%EC%9A%A9%EC%95%88%ED%95%98%EA%B8%B0-customize-cra-react-app-rewired-10a83522ace0

 

Create-React-App에서 Eject사용안하기(customize-cra, react-app-rewired)

CRA를 쓰는 이유

medium.com

https://webpack.js.org/configuration/

 

Configuration | webpack

webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

webpack.js.org

https://github.com/ingong/react-boilerplate-session ( 커스텀 로더 / 에셋 모듈 ) 

 

GitHub - ingong/react-boilerplate-session: SOPT 30기 React BoilerPlate 세션 자료 저장소

SOPT 30기 React BoilerPlate 세션 자료 저장소. Contribute to ingong/react-boilerplate-session development by creating an account on GitHub.

github.com

 

반응형