npm init
npm i react react-dom
npm i typescript
npm i @types/react @types/react-dom
npm i -D eslint
npm i -D prettier eslint-plugin-prettier eslint-config-prettier
_cf) eslint는 코드검사도구(에러잡거나 오타 잡아주는 도구),
prettier는 정렬해주는 도구
.eslintrc
생성
{
// prettier가 추천(recommended)하는대로 따르겠다는 의미
"extends": ["plugin:prettier/recommended", "react-app"]
}
.prettierrc
생성
{
"printWidth": 120, // 한 줄당 최대 글자수 (보편적으로 80~120많이 함)
"tabWidth": 2, // 탭너비
"singleQuote": true, // 홑따음표 ('')
"trailingComma": "all", // 항상 콤마(,)를 뒤에 붙이기
"semi": true // 세미콜론 항상 붙이기
}
tsconfig.json
생성
{
"compilerOptions": {
"esModuleInterop": true, // import * as React from 'react'; > import React from 'react';로 가져올 수 있음
"sourceMap": true, // 에러난위치 찾아가기 편함
"lib": ["ES2020", "DOM"],
"jsx": "react", // jsx가 여러군데에서 쓸 수 있기 때문에 react라고 명시
"module": "esnext", // 최신모듈 쓴다는 의미
"moduleResolution": "Node", // import export도 node가 해석할 수 있게 하는것
"target": "es5", // "lib"에 써있는 버전으로 작성하더라도 "es5"로 변환
"strict": true, // 타입체크를 엄격하게 하겠다는 의미
"resolveJsonModule": true, // json파일을 import로 가져오는것을 허용
"baseUrl": ".",
"paths": { // 경로지정시 ../../../ 이런거를 빼고 절대경로처럼 작성가능하게 해줌
"@hooks/*": ["hooks/*"],
"@components/*": ["components/*"],
"@layouts/*": ["layouts/*"],
"@pages/*": ["pages/*"],
"@utils/*": ["utils/*"],
"@typings/*": ["typings/*"]
}
}
}
cf) webpack5는 아직 지원안되는것들이 많아서 에러가 잘 날 수 있음. 안정화 될 때까진 webpack4로 개발하는 것이 좋음.
webpack.config.ts
생성
import path from 'path';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import webpack from 'webpack';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
const isDevelopment = process.env.NODE_ENV !== 'production'; // production은 배포용, development는 개발용
const config: webpack.Configuration = {
name: 'sleact',
mode: isDevelopment ? 'development' : 'production',
devtool: !isDevelopment ? 'hidden-source-map' 또는 'cheap-module-source-map' : 'eval',
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], // 확장자 생략(바벨이 처리할 확장자 목록)
alias: { // ../../ 이런거 없애주는 설정, tsconfig에서 설정해줘도 웹펙이 js로 바꿀땐 webpack.config파일을 토대로 바꾸기 때문에 여기서도 설정해줘야 함.
'@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', // app은 진입점에 해당하는 파일의 별명
},
module: { // 모듈 처리 방식을 설정, 웹팩의 처리과정, tsx/css/js등 확장자를 만나면 각각의 로더를 돌려달라는 내용.
rules: [
{
test: /\.tsx?$/,
loader: 'babel-loader',
options: {
presets: [ // 바벨로더가 js로 바꿔줄 때, 바벨에 대한 설정
[
'@babel/preset-env',
{
targets: { browsers: ['last 2 chrome versions'] }, // targets에 설정한 브라우저에서 지원하게끔 알아서 바꿔준다
debug: isDevelopment,
},
],
'@babel/preset-react',
'@babel/preset-typescript',
],
env: {
development: {
plugins: [['@emotion', { sourceMap: true }], require.resolve('react-refresh/babel')],
},
production: {
plugins: ['@emotion'],
},
},
},
exclude: path.join(__dirname, 'node_modules'), // node_modules안의 파일들은 바벨로 해석안해도 됨
},
{
test: /\.css?$/,
use: ['style-loader', 'css-loader'],// 복수라서 use사용, 배열로 넣기. 한개라도 loader가 아니라 use로 적어도 됨.
},
],
},
// 번들링 후 결과물의 처리 방식 등 다양한 플러그인들을 설정
plugins: [// 웹팩의 처리과정, 모듈이 처리된 후에 추후에 어떤 작업을 더 진행해야 하는지 배열로 명시
new ForkTsCheckerWebpackPlugin({ // typescript 사용하는 경우에 입력, typescript와 webpack이 동시에 실행되도록 해주는 기능
async: false,
// eslint: {
// files: "./src/**/*",
// },
}),
// 리액트에서 'process.env.NODE_ENV'라는 변수를 사용할 수 있게 해줌(원래는 백엔드에서만 사용가능)
new webpack.EnvironmentPlugin({ NODE_ENV: isDevelopment ? 'development' : 'production' }),
],
output: { // 결과물(번들)을 반환하는 설정
path: path.join(__dirname, 'dist'),// `__dirname`은 현재 파일의 위치를 알려주는 NodeJS 전역 변수
filename: '[name].js',// `[name]`은 `entry`의 Key 이름, `app`
publicPath: '/dist/',
},
devServer: {
historyApiFallback: true, // react router
port: 3090,
publicPath: '/dist/',
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' }));
}
export default config;
npm i -D webpack @babel/core babel-loader @babel/preset-env @babel/preset-react @babel/preset-typescript
npm i -D @types/webpack @types/node
npm i stype-loader css-loader
index.html
생성
웹팩 실행명령
npx webpack 또는 npm i webpack
후, npx webpack
> 에러날 경우, webpack.config.ts파일을 웹팩이 인식을 못하기 때문
->tsconfig-for-webpack-config.json
생성
(웹팩이 webpack.config.ts파일을 인식하게 만들어줌)
// tsconfig-for-webpack-config.json
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "Node",
"target": "es5",
"esModuleInterop": true
}
}
TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack
->명령이 길기 때문에 package.json
파일의 "scripts"
에
"build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack"
추가해서 간단하게 명령어 쓸 수 있게 하기
npm i ts-node
npm i cross-env
npm i run build
자동으로 수정된 코드를 반영해주기 위해서 Hot reloading
해주는 프로그램을 설치해야 함 (cra는 내장되어 있음)
npm i webpack-dev-server -D
(webpack-dev-server는 hot-reloading기능 + proxy서버역할, cors에러 해결해줌)
npm i webpack-cli
npm i -D @types/webpack-dev-server
hot-reloading해주기 위해서 아래 설치
npm i @pmmmwh/react-refresh-webpack-plugin
npm i react-refresh
typescript와 webpack이 동시에 실행되도록 해주는 기능
npm i fork-ts-checker-webpack-plugin -D
package.json
파일의 "scripts"
에
"dev": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack serve --env development"
npm run dev
npm i react-router react-router-dom
npm i -D @types/react-router @types/react-router-dom
+@
: 사용자경험을 위해(빠른 렌더링) 필요한 페이지들(컴포넌트들)만 불러오도록 하는 것.
- 분리기준
1) 페이지 단위로 분리
2) 서버사이드렌더링 필요없는것들
이렇게 코드 스플리팅 해주면 좋음
npm i @loadable/component
npm i -D @types/loadable__component
// App.tsx
// 아래코드 추가
// @로 가져오는건 웹팩설정해줬기 때문
import loadable from '@loadable/component';
// 아래코드 변경
// 기존
import Login from '@pages/Login';
import SignUp from '@pages/SignUp';
// 변경 후
const Login = loadable(() => import('@pages/Login'));
const SignUp = loadable(() => import('@pages/SignUp'));
// npm i -D eslint-config-react-app eslint-plugin-flowtype eslint-plugin-import eslint-plugin-jsx-ally
// 설치 후,
// .eslintrc에서 "react-app"추가
{
"extends": ["plugin:prettier/recommended", "react-app"]
}