react + typescript + webpack4 - (1) 설정하기

최근에 react에 관련된 프로젝트는 typescript로 진행을 하고 있습니다. 최근에 webpack4에 대해서 알아볼겸, typescript와 react를 같이 사용하면서, mobx도 같이 연동하는 example을 미리 만들어서 대비해야 겠다는 생각에, project를 진행하게 되었습니다. 이번 내용은 react와 typescript를 webpack4를 이용하여 만드는 첫번째 내용으로, 설정하는 부분부터 다뤄보고자 합니다.

사용법

test-webpack4라는 프로젝트를 먼저 생성하겠습니다.

mkdir test-webpack4

webpack4 설치

webpack4를 설치합니다.

npm i webpack webpack-cli

webpack4버전에서는 webpack-cli 플러그인을 필수로 설치합니다.

typescript 설치

typescript를 설치합니다.

npm i typescript

react 설치

javascript react 에 대한 관련 plugin을 설치합니다.

npm i react react-dom

typescript 관련 types 모듈을 설치합니다. 이를 설치함으로써 react와 react-dom을 typescript로 사용할 수 있을 뿐만 아니라, typescript에 관련된 내용들도 같이 사용할 수 있게 됩니다.

npm i @types/react @types/react-dom

ts-loader 설치

현재 webpack내 typescript loader에는 awesome-typescript-loader와 ts-loader 두가지가 있습니다. awesome-typescript-loader를 많이 쓰시지만, 제가 사용하는 환경에서 webpack4 기준으로 at-loader가 정상적으로 작동하지 않는 이슈가 있어, 저는 ts-loader로 개발하고 있습니다.

npm i ts-loader --save-dev

tsconfig 설정

typescript를 이용하기 위한 config 설정입니다.

{
  "compilerOptions": {
    // leave JSX as it is
    "jsx": "react",
    // resolve modules as you would expect
    "moduleResolution": "node",
    // leave imports as they are
    "module": "commonjs",
    // do not transpile stuff like classes, async/await, ...
    "target": "es5",
    "lib": [
      "es2015", "es6", "esnext", "dom"
    ],
    "allowJs": true,
    // produce a source map
    "sourceMap": true,
    "baseUrl": ".",
    "outDir": "dist",
    "paths": {
      "components/*": ["./src/components/*"],
      "containers/*": ["./src/containers/*"],
      "assets/*": ["./src/assets/*"],
      "constants/*": ["./constants/*"],
      "utils/*": ["./src/utils/*"]
    },
    "allowSyntheticDefaultImports": true,
    "keyofStringsOnly": true
  },
  "include": [
    "./src/**/*"
  ],
  "exclude": [
    "./node_modules/**/*"
  ]
}

option에서 확인해 보시면, jsx 라는 옵션이 있는데, 해당 옵션을 react로 설정해 줍니다.

paths의 경우 babel내 module resolver와 같은 설정으로 alias를 통한 module 경로 설정이 가능할 수 있도록 해줍니다. 이는 빌드 시점에서도 해당 alias를 찾아서 빌드할 수 있도록 해주며, vscode를 사용하시는 경우에는 autocomplete 기능도 같이 사용하실 수 있습니다.

webpack 파일 설정

우선 webpack4부터 달라진 설정으로는, mode 분기를 통해서 develop 모드에서는 sourcemap과 webpack-dev-server 자동 실행등을, production 모드에서는 uglify를 자동으로 설정할 수 있도록 구성된것이 특징입니다. (자세히 보면, parcel-bundler에서 영향을 받은것일지 모른다는 생각도 듭니다.)

저는 관련 내용을, tools내 폴더에서 base.js / development.js / production.js 로 나누어 만들고자 했습니다. 이를 통해서 기본적인 module loader를 처리하는 rules 등이나 plugin 등은 base.js에서 처리하고, development.js에서는 개발에서만 사용하는 부분들을, production.js 에서는 배포용에서 사용하는 옵션들을 설정하고자 했습니다.

// tools/base.js
const path = require('path');

module.exports = {
  entry: {
    'vendor': ['react', 'react-dom'],
    'app': path.resolve(__dirname, '..', 'src', 'App.tsx'),
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          chunks: 'initial',
          name: 'vendor',
          enforce: true,
        },
      },
    },
  },
  output: {
    filename: '[name].[chunkhash].js',
    chunkFilename: '[name].[chunkhash].chunk.js',
  },
  resolve: {
    extensions: ['.js', '.ts', '.tsx'],
    alias: {
      'components': path.resolve(__dirname, '..', 'src', 'components'),
      'containers': path.resolve(__dirname, '..', 'src', 'containers'),
      'assets': path.resolve(__dirname, '..', 'src', 'assets'),
    },
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'ts-loader',
          },
        ],
      },
    ],
  },
  // plugins
  plugins: [],
};

다음은 개발용, 배포용의 development.js 및 production.js의 설정 내용을 확인하실 차례입니다. 저는 설정에 대한 내용을 webpack-merge 플러그인을 이용하여 base.js에서 설정한 내용을 merge하여 각 모드에 맞게 사용하고자 했습니다.

entry내 네용을 보시면, 이후 저희는 typescript로 사용할 react app을 ./src/App.tsx을 entry file로 만들 예정입니다.

npm을 통해 webpack-merge를 사용합니다.

npm i webpack-merge
// tools/development.js

const merge = require('webpack-merge');
const config = require('./base');

module.exports = merge(config, {
  mode: 'development',
  devtool: 'cheap-eval-sourcemap',
  devServer: {
    port: 9000,
  },
});
// tools/production.js

const merge = require('webpack-merge');
const config = require('./base.config');

module.exports = merge(config, {
  mode: 'production',
});

각 모드 내에서 development, production 설정시 자동으로 production 모드일시 minify, development 모드시 sourcemap, webpack-dev-server 등을 진행할 수 있도록 해줍니다. mode의 경우에는 명시해주지 않으면 webpack 자체에서 warning을 출력합니다. development.js에서 devServer는 mode가 development일때 자동으로 실행되는 devServer에 관련된 내용으로, port를 9000으로 설정하여 localhost:9000에서 개발에 대한 내용을 확인할 수 있도록 했습니다.

package.json 설정

dev, prod 모드를 설정할 차례입니다.

// package.json

"scripts": {
  "dev": "webpack-dev-server --config ./tools/development.js",
  "prod": "webpack --config ./tools/production.js"
},

자세히 보시면, dev 및 prod를 통해서 –config 옵션에는 각각 개발용/배포용으로 작성했던 development.js, production.js를 실행하도록 되어 있습니다. 개발용에서 자동으로 브라우저에 띄우고 싶으시다면, dev 옵션의 끝에 –open을 붙이시면 됩니다.

각 환경별 command는 터미널에서 다음과 같이 입력하시면 확인 가능합니다.

# development
npm run dev
# production
npm run prod

이후 본격적으로 typescript를 활용하여 react App을 작성해볼 차례입니다! 관련된 개발 내용을 github repository 에서 확인하실 수 있습니다 :)