블로그 프로젝트를 version2로 업그레이드할 예정이어서 프론트 프로젝트를 처음부터 다시 셋팅할 예정이다.
CRA는 간단한 명령어로 필요에 따른 프로젝트 셋팅을 제공해주지만 때에 따라 필요하지 않은 모듈들도 포함되어있다.
Creat-React-App(CRA)
Creat-React-App(CRA)은 메타에서 개발한 보일러 플레이트로 React 프로젝트 개발 초기 세팅에 필요한 여러 가지 라이브러리나 패키지의 설치 및 d웹팩,바벨, EsLint등 설정 없이 간편하게 시작할 수 있도록 환경을 제공해준다.
CRA로 프로젝트를 셋팅한다해서 작은 규모의 프로젝트가 안 좋은 영향을 많이 받진 않겠지만 직접 개발 환경을 셋팅해보는 것은 분명 좋은 경험일 것이라 생각하여 개발 환경을 셋팅해보려한다.
물론 CRA로 만든 프로젝트라 하더라도 webpack과 babel을 직접 설정할 수 있는 방법은 있다.
npm run eject라는 명령어를 통하여 숨겨져있던 webpack,babel 등의 설정들을 꺼내어볼 수 있고 본인의 상황에 맞게 직접 설정할 수도 있다.
그렇다면 환경 셋팅을 하기 위한 무엇보다 시작해야하는지 생각해보자.
우선 CRA로 만든 프로젝트는 개발 환경 셋팅이 어떻게 되있나 확인해봐야겠다는 생각이 들었다.
블로그 프로젝트 version2에서는 javascript => typescript로 전환하고 redux => redux tool kit으로 전환할 예정이다.
그러기 위해서 CRA 템플릿 중 Redux+Ts Template 셋팅을 가져와 eject하여 살펴보겠다.
다음 명령어를 통해 RTK와 TS의 개발 환경이 셋팅된 CRA 템플릿을 만들 수 있다.
npx create-react-app my-app --template redux-typescript
5~10분가량의 시간이 지나면 프로젝트가 셋팅된다.
(설치 시간을 보면 얼마나 많은 패키지 셋팅해주는지 알 수 있다.)
일단 eject하지 않은 디렉터리 구조를 살펴보자.
디렉터리 구조 before eject
흠.. 요약하자면 redux를 사용하기 위한 셋팅과 ts를 사용하기 위한 셋팅이 되어있다.
이제 eject하여 내부 구조를 꺼내보자.
다음 명령어로 eject할 수 있다.
npm run eject
eject를 하니 굉장히 많은 디렉터리와 파일들이 꺼내져나왔다.
다음은 eject한 후의 디렉터리 구조이다.
디렉터리 구조 after eject
각각이 무슨 파일인지,파일의 각 코드들은 무슨 역할을 하는지 파악하기가 어렵다.
갑자기 package.json에도 아까는 없던 수많은 모듈들이 나와있다.
거의 모듈이 60개정도 된다.
일단 webpack.config.js 파일은 800줄이다...ㅎ
좌절하지 말자.
나에겐 시간은 많다.
우선 다른 분들이 어떻게 셋팅하는지 여러 레퍼런스들을 참조해보고 오겠다.
(슝~)
다녀왔다.
우선 필요한 라이브러리부터 천천히 설치해보는 것부터 시작해보자.
eject한 프로젝트와 비교하여 설치해보겠다.
그 다음에는 설정 파일에 대한 코드를 작성할 것이다.
설치해야할 라이브러리들이 꽤 많다.
리액트,타입스크립트,babel,webpack,eslisnt,prettier,redux 등이 있다.
각 라이브러리들을 천천히 알아보자.
npm i react react-dom
위 라이브러리들은 리액트를 사용하기 위한 기본 라이브러리이다.
리액트 라이브러리는 컴포넌트, jsx문법, 훅 등을 사용하기 위해서 필요한 리액트 핵심 라이브러리이다.
import React from "react"
각 리액트 파일에는 위와 같이 react 모듈을 가져오는 코드를 볼 수 있었을 것이다.
내부적으로 컴포넌트는 React.Component를 사용하기 때문에 컴포넌트를 사용할 수 있다.
또한 내부적으로 리액트 요스를 만들때에는 React.createElement()라는 API도 사용한다.
React.createElement()
그리고 리액트 라이브러리가 있어야 리액트 훅도 불러와 사용할 수 있다.
import {useState,useEffect} from "react";
그 외에도 리액트의 여러 API 및 기능을 사용하기 위해서는 리액트 라이브러리가 핵심적으로 필요하므로 react 라이브러리는 필수적으로 설치해줘야한다.
react-dom은 리액트 dom을 사용하고 html파일에 렌더링해주기 위한 라이브러리이다.
import * as ReactDOM from 'react-dom/client';
const container = document.getElementById('root')!;
const root = createRoot(container);
root.render(element);
위와 같이 리액트 요소들을 html에 렌더링해주고 react-dom(virtual-dom)을 사용해주기 위해서 꼭 필요한 라이브러리이다.
타입스크립트를 사용하기 위해 필요한 라이브러리들을 살펴보자.
npm i -D typescript @types/react @types/react-dom
typescript를 사용하기 위해 설치해줘야한다.
중간에 -D을 붙이는 이유는 개발 환경에서만 사용할 것이기 때문에 -D를 붙여준다.
실제 프로덕션 환경에서는 해당 라이브러리는 포함되지 않는다.
(불필요한 라이브러리를 줄이기 위해서)
react와 react-dom 라이브러리에는 타입이 정의되어있지 않기 때문에 각각이 필요한 타입 라이브러리를 설치해줘야한다.
즉,react나 react-dom이 ts로 만들어져있지 않기 때문이다.
babel을 사용하기 위해 설치해야하는 라이브러리들을 알아보자.
npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
바벨과 웹팩을 사용하여 자바스크립트 ES6+코드를 ES5 코드로 트랜스파일로 해준다.
브라우저에서 간혹 ES6이상 최신 문법을 지원하지 않는 경우가 있는데 해당 문법을 ES5로 변환해주면 코드가 해당 브라우저에 적용될 수 있다.
최신 코드를 여러 브라우저와 호환하기 위해 사용하는 라이브러리이다.
바벨을 사용하기 위해서 필수적으로 필요한 라이브러리이다.
브라우저에 필요한 ecmascript 버전을 자동으로 파악해서 알아서 polyfill을 넣어준다.
리액트와 같이 사용할 때 설치해주면 되는 모듈이다.
jsx 문법을 js로 변환해준다.
jsx로 작성된 코드들을 createElement 함수를 이용한 코드로 변환해 주는 바벨 플러그인이 내장되어 있다.
typescript 문법을 javascript로 변환해주는 라이브러리이다.
typescript만으로는 소스 코드가 적용되지 않는다.
typescript 문법은 javascript 변환되어야 소스 코드가 적용된다.
npm i -D webpack webpack-cli webpack-dev-server webpack-merge html-webpack-plugin ts-loader
전반적인 웹팩 기능들을 사용할 수 있게 해주는 모듈이다.
커맨드 라인으로 웹팩 명령어를 사용할 수 있게 해준다.
웹팩 개발서버를 구동할 수 있게 해준다.
웹팩 머지는 단어 그대로 여러 개의 웹팩 설정 파일을 하나로 병합해주는 라이브러리이다.
일반적으로 웹 애플리케이션을 제작할 때는 웹팩 설정을 개발(Development)용과 배포(Production)용으로 나누어 적용한다.
웹팩 번들에 html파일을 제공한다.
번들링된 js파일을 html에 자동으로 제공해줘 html에 script태그로 로드할 필요가 없다.
타입스크립트를 자바스크립트로 변환해주기 위한 라이브러리이다.
npm i react-redux @reduxjs/toolkit
리덕스 툴킷을 사용하기 위한 라이브러리이다.
리액트와 리덕스를 같이 사용하기 위한 라이브러리이다.
ts.config.json파일에서 코드를 설정하면 타입스크립트 ts 파일들을 .js 파일로 변환할 때 어떻게 변환할 것인지 세부설정이 가능하다.
따라서 ts.config.json 파일을 작성해줘야한다.
ts.config.json 파일 코드를 편리하게 작성하도록 도와주는 명령어이다.
tsc --init
위 명령어를 사용하면 ts.config.json 파일을 생성해주고 기본 설정 코드를 생성해주고 필요에 따라 주석을 해제,설정하여 사용할 수 있다.
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
// "incremental": true, /* Enable incremental compilation */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
...
...
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve",
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
...}
}
웹팩 관련 설정을 할 수 있는 파일이다.
설정 파일에서 어느 파일에서부터 번들링을 할것인지(번들링 entry point 지정),번들링된 파일을 어디로 내보낼것이고 파일명은 어떻게 지을 것인지 등등 설정들을 할 수 있다.
각 속성들을 살펴보자.
webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const path = require("path");
module.exports = {
mode: "development",
entry: "./src/index.tsx",
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: ["babel-loader", "ts-loader"],
},
],
},
output: {
path: path.join(__dirname, "/dist"),
filename: "bundle.js",
},
plugins: [
new HtmlWebpackPlugin({ template: "./public/index.html" }),
new CleanWebpackPlugin(),
],
devServer: {
port: 3000,
historyApiFallback: true,
hot: true,
open: true,
},
};
mode
웹팩 실행 모드를 설정해줄수 있다. 각 실행 모드에 따라 웹팩의 결과물 모습이 달라진다.
development(개발 모드) or production(배포 모드 => 기본값) or none 중에 값이 들어갈 수 있다.
개발 모드인 경우에는 개발자들이 좀 더 보기 편하게 웹팩 로그나 결과물이 보여지고, 배포 모드인 경우에는 성능 최적화를 위해 기본적인 파일 압축 등의 빌드 과정이 추가된다.
모드의 기본 값을 설정하지 않으면 production 모드로 자동 설정
entry
번들링을 시작할 entry point 파일을 지정할 수 있다.
많은 모듈들이 중첩되어 import되고 있을텐데 최초로 모듈들을 import한 파일이 있을 것이다.
해당 파일을 entry 속성에 지정해주면 된다.
output
번들링된 파일을 내보낼 경로를 설정해주고 번들링된 파일명을 설정해줄수 있다.
위 예제로 살펴보면 dist라는 디렉터리에 bundle.js라는 파일명으로 번들된 파일을 내보내겠다는 뜻이다.
resolve
모듈을 가져올 때 해당 모듈이 위치한 경로를 상대적으로 설정해줄 수도 있고, 가져올 모듈명을 입력할 때 확장자를 생략하게 해줄 수도 있는 속성이다.
위 예제로 확인해보면 js,jsx,ts,tsx로 된 모듈을 다른 파일에서 import한다고 했을 때 해당 모듈명 확장자는 적지않아도 된다.
뿐만 아니라 디렉터리 구조가 복잡해졌을 때 상대경로를 본의의 편의대로 모듈을 가져올 때 편리함을 준다.
module
사용할 loader를 설정해줄수 있는 속성이다.
module 속성을 추가하고, 그 안에 rules 속성을 통해 처리 규칙을 등록한다.
test 항목에 정의된 정규식에 매칭되는 파일은 use 항목에 등록된 로더를 통해서 처리된다.
위 예제로 확인했을 때 tsx파일은 babel-loader와 ts-loader를 통해 처리된다.
plugins
설치한 플러그인들을 적용해줄수 있다.
devServer
webpack-dev-server를 사용할 수 있게 해주고 관련 설정을 해줄수 있는 속성이다.
webpack-dev-server는 개발환경에서 실시간으로 내가 구현한 부분들을 확인할 수 있게 해준다.
개발 서버 시작 및 빌드
package.json에서 scripts 명령어 설정을 통해 개발 서버 시작 및 빌드 명령어를 설정해줄수 있다.... "scripts": { "start": "webpack serve", // 웹팩 개발 서버 시작 명령어 "build": "webpack", // 빌드 명령어 }, ...
바벨 설정을 해줄 수 있는 파일이다.
module.exports 객체에 presets필드를 선언하고 사용하고 싶은 babel 모듈들을 배열로 넣어주면 된다.
@babel/preset-react(jsx를 js 변환,createElement로 리액트 요소 새성),@babel/preset-env(브라우저에 필요한 ecmascript버전을 알아서 폴리필),@babel/preset-typescript(ts를 js로 변환)이 필요하니 배열의 요소로 넣어주자.
module.exports = {
presets: [
"@babel/preset-react",
"@babel/preset-env",
"@babel/preset-typescript",
],
};
tsconfig.json에서 "jsx"옵션
모든 옵션 파일에서 설정 코드를 마무리한뒤 개발 서버를 띄웠는데 다음과 같이 에러가 발생했다.
여러 설정 파일을 변경해가면서 삽질해보다가 스택오버플로우에서 답을 찾았다.
tsconfig.json에서 "jsx"옵션
tsconfig.json 파일에서 "jsx" 옵션을 "preserve" => "react"로 변경해주어야한다고 한다.
Before tsconfig.json
{
...
"jsx": "preserve"
...
}
After tsconfig.json
{
...
"jsx": "react"
...
}
"react"로 옵션을 변경해주었더니 에러가 없어지고 잘 작동되는 것을 확인할 수 있었다.
reference
tsconfig.json에서 jsx 속성을 "preserve"로 해놔도 위와 같은 에러가 안 생기도록 즉, 번들링된 파일에서 리액트 모듈을 가져올 수 있게 하는 방법이 있다.
다음과 같이 webpack.config.json 파일에 webpack 모듈을 가져온뒤 new webpack.ProvidePlugin({ React: "react" })
플러그인을 추가해주면 된다.
const webpack = require("webpack");
module.exports = {
...
plugins: [
new webpack.ProvidePlugin({ React: "react" }),
],
...
};
좋은 글 감사합니다!