개발 알다가도 모르겠네요

리액트 프로젝트 초기 환경 세팅 본문

웹/React

리액트 프로젝트 초기 환경 세팅

이재빵 2022. 8. 2. 23:54
728x90

1. 설치

# typescript를 사용하실 분들은(권장)
**$ npx create-react-app 서비스이름 **--template typescript**

# javascript를 사용하실 분들은
$ npx create-react-app 서비스이름

#eslint: 코드 검사 도구 (안쓰는 변수, 오타 잡아줌)
yarn add -D eslint
//yarn add eslint --save-dev
npx eslint --init //eslint 초기화 설정

#prettier: 코드 정렬도구 
yarn add -D prettier eslint-plugin-prettier eslint-config-prettier

yarn add eslint-import-resolver-typescript -D

tsconfig.json 에 아래 코드 추가

"sourceMap": true, //에러 찾아가기 쉽게

 

 

2. Eslint & Prettier 세팅

 

[React] Typescript + eslint + prettier 설정

😁 Project 할 때마다 eslint, prettier 세팅 시 모호했던 것 들을 한 번 정리해 보려고 한다.Create React App은 타입스크립트를 별도의 설정 없이 사용할 수 있도록 지원한다.다음 명령어를 실행하면 TypeSc

velog.io

 

.eslintrc

{
  "globals": { "JSX": true },
  "env": {
    "browser": true,
    "es2021": true
  },
  "extends": ["plugin:react/recommended", "plugin:prettier/recommended", "plugin:react-hooks/recommended", "airbnb"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": "latest",
    "sourceType": "module"
  },
  "plugins": ["react", "@typescript-eslint"],
  "rules": {
    "prettier/prettier": [
      "error",
      {
        "endOfLine": "auto"
      }
    ],
    "semi": 2,
    "react/jsx-one-expression-per-line": "off",
    "react/jsx-filename-extension": ["warn", { "extensions": [".tsx"] }],
    "import/extensions": [
      "error",
      "ignorePackages",
      {
        "ts": "never",
        "tsx": "never"
      }
    ],
    "no-use-before-define": "off",
    "object-curly-newline": "off",
    "implicit-arrow-linebreak": "off",
    "global-require": "off",
    "indent": "off",
    "operator-linebreak": "off",
    "react/jsx-props-no-spreading": "off",
    "function-paren-newline": "off",
    "react/jsx-wrap-multilines": "off",
    // 제거 필요
    "react/no-unstable-nested-components": "off"
  },
  "settings": {
    "import/resolver": {
      "typescript": {}
    }
  },
  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "rules": {
        "@typescript-eslint/no-unused-vars": [2, { "args": "none" }],
        "@typescript-eslint/no-use-before-define": ["error"]
      }
    }
  ]
}

이 코드를 추가하는데

윈도우 환경일 경우

 "linebreak-style": ["error", "unix"]

에서 아래 코드로 바꾸면 해결 가능.

 "linebreak-style": ["error", "windows"]

.prettierrc

{
  "printWidth": 120,
  "tabWidth": 2,
  "singleQuote": true,
  "trailingComma": "all",
  "semi": true
}

오류뜨면

.vscode 폴더 생성.

settings.json

 {
   "editor.defaultFormatter": "esbenp.prettier-vscode",
   "editor.formatOnSave": true
 }

 

 

3. Webpack & Babel 세팅 (CRA 안했을 때)

웹팩은 최신 프론트엔드 프레임워크에서 가장 많이 사용되는 모듈 번들러.

웹펙에서 모듈이란, 웹 애플리케이션을 구성하는 모든 자원을 말함.

HTML, CSS, Javascript, Images, Font 등 파일 하나하나가 모두 모듈.

결국, 웹팩은 모듈을 번들링 해주는 모듈 번들러

  1. 파일 단위의 자바스크립트 모듈 관리의 필요성
  2. 웹 개발 작업 자동화 도구
  3. 웹 애플리케이션의 빠른 로딩 속도와 높은 성능
 

[웹팩]웹팩이란? | 웹팩이 하는 일과 필요한 이유

웹팩은 리액트를 배우고 있다면 다들 한 번쯤 들어봤을 프레임워크입니다. 그렇다면 웹팩은 무슨 일을 하는걸까요?웹팩은 최신 프론트엔드 프레임워크에서 가장 많이 사용되는 모듈 번들러입

velog.io

 

*타입스크립트

import path from 'path';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import webpack, { Configuration as WebpackConfiguration } from 'webpack';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server';

interface Configuration extends WebpackConfiguration {
  devServer?: WebpackDevServerConfiguration;
}
const isDevelopment = process.env.NODE_ENV !== 'production';

const config: Configuration = {
  name: 'sleact',
  mode: isDevelopment ? 'development' : 'production',
  devtool: !isDevelopment ? 'hidden-source-map' : 'inline-source-map',
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
    alias: {
      '@hooks': path.resolve(__dirname, 'hooks'),
      '@components': path.resolve(__dirname, 'components'),
      '@layouts': path.resolve(__dirname, 'layouts'),
      '@pages': path.resolve(__dirname, 'pages'),
      '@utils': path.resolve(__dirname, 'utils'),
      '@typings': path.resolve(__dirname, 'typings'),
    },
  },
  entry: {
    app: './client',
  },
  target: ['web', 'es5'],
  module: {
    rules: [
      {
        test: /\\.tsx?$/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env',
              {
                targets: { browsers: ['IE 10'] },
                debug: isDevelopment,
              },
            ],
            '@babel/preset-react',
            '@babel/preset-typescript',
          ],
          env: {
            development: {
              plugins: [['@emotion/babel-plugin', { sourceMap: true }], require.resolve('react-refresh/babel')],
            },
            production: {
              plugins: ['@emotion/babel-plugin'],
            },
          },
        },
      },
      {
        test: /\\.css?$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [
    new ForkTsCheckerWebpackPlugin({
      async: false,
      // eslint: {
      //   files: "./src/**/*",
      // },
    }),
    new webpack.EnvironmentPlugin({ NODE_ENV: isDevelopment ? 'development' : 'production' }),
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: '/dist/',
  },
  devServer: {
    historyApiFallback: true,
    port: 3090,
    devMiddleware: { publicPath: '/dist/' },
    static: { directory: path.resolve(__dirname) },
    proxy: {
      '/api/': {
        target: '<http://localhost:3095>',
        changeOrigin: true,
        ws: true,
      },
    },
  },
};

if (isDevelopment && config.plugins) {
  config.plugins.push(new webpack.HotModuleReplacementPlugin());
  config.plugins.push(
    new ReactRefreshWebpackPlugin({
      overlay: {
        useURLPolyfill: true,
      },
    }),
  );
  config.plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'server', openAnalyzer: false }));
}
if (!isDevelopment && config.plugins) {
  config.plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true }));
  config.plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'static' }));
}

export default config;

 

*자바스크립트

const path = require('path');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

const isDevelopment = process.env.NODE_ENV !== 'production';

const config = {
  name: 'sleact',
  mode: isDevelopment ? 'development' : 'production',
  devtool: !isDevelopment ? 'hidden-source-map' : 'eval',
  resolve: {
    extensions: ['.js', '.jsx', '.json'],
    alias: {
      '@hooks': path.resolve(__dirname, 'hooks'),
      '@components': path.resolve(__dirname, 'components'),
      '@layouts': path.resolve(__dirname, 'layouts'),
      '@pages': path.resolve(__dirname, 'pages'),
      '@utils': path.resolve(__dirname, 'utils'),
      '@typings': path.resolve(__dirname, 'typings'),
    },
  },
  entry: {
    app: './client',
  },
  module: {
    rules: [
      {
        test: /\\.jsx?$/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env',
              {
                targets: { browsers: ['last 2 chrome versions'] },
                debug: isDevelopment,
              },
            ],
            '@babel/preset-react',
          ],
          env: {
            development: {
              plugins: [['@emotion', { sourceMap: true }], require.resolve('react-refresh/babel')],
            },
            production: {
              plugins: ['@emotion'],
            },
          },
        },
        exclude: path.join(__dirname, 'node_modules'),
      },
      {
        test: /\\.css?$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [new webpack.EnvironmentPlugin({ NODE_ENV: isDevelopment ? 'development' : 'production' })],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: '/dist/',
  },
  devServer: {
    historyApiFallback: true, // react router
    port: 3090,
    devMiddleware: { publicPath: '/dist/' },
    static: { directory: path.resolve(__dirname) },
    proxy: {
      '/api/': {
        target: '<http://localhost:3095>',
        changeOrigin: true,
      },
    },
  },
};

if (isDevelopment && config.plugins) {
  config.plugins.push(new webpack.HotModuleReplacementPlugin());
  config.plugins.push(new ReactRefreshWebpackPlugin());
  config.plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'server', openAnalyzer: true }));
}
if (!isDevelopment && config.plugins) {
  config.plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true }));
  config.plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'static' }));
}

module.exports = config;

 

babel은 Javascript의 compiler.

Java나 C의 컴파일러처럼, 소스코드를 바이너리 파일로 변환하는 것은 아니지만,

React의 JSX문법을 Vanilla JavaScript로 변경하거나, 최신버전의 문법을 구 버전 문법으로 변환해줌.

JSX 를 Vanilla JavaScript로 변경해 준다.

React에서의 JSX 문법은, 브라우저가 잘 모르는 문법이기 때문에,

브라우저가 이해할 수 있는 Vanilla JS로 변경해 주어야 하며, 이것을 babel이 해 줌.

 

[React] babel과 webpack의 차이

React의 개발 환경을 구성하려면, 여러가지 도구들이 필요하고, 이 도구들에 대한 설정을 해 주어야 한다. 대표적으로 webpack + babel 설정을 해 주어야 한다. webpack : JavaScript의 static module bundler bab..

hianna.tistory.com

 

' > React' 카테고리의 다른 글

LifeCycle 를 간단하게 알아보자.  (0) 2022.01.13
Component와 State&Props 를 간단하게 알아보자  (0) 2022.01.12