보통, cra typescript를 위해서
1 | npx create-react-app [project-name] --template typescript |
를 쓰지만,
이번에는 직접 만들어보면서 react library의 작동 원리를 살펴보려고 한다.
세팅 과정
npm을 세팅한다.
1
npm init -y // -y로 default 설정 적용
npm pkg를 설치한다.
typescript
1
npm i --s typescript @types/react @types/react-dom
react
1
npm i --s react react-dom
babel
1
npm i --s-d babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
webpack
1
npm i --s-d webpack webpack-dev-server webpack-cli
타입스크립트 설정하기
타입스크립트 설정 파일을 만들기 위해,
- 전역으로 설치된 경우
tsc --init
- 해당 프로젝트에만 설치된 경우 직접 파일을 명시해야 하기 때문에
node_modules/.bin/tsc --init
을 수행한다.
- 전역으로 설치된 경우
그럼
tsconfig.json
이 생성되는데, 다음과 같이 주석을 해지해주면 된다. (꼭 밑과 같지 않아도, 경우에 맞게/ 입맛에 맞게 설정해두면 두고두고 용이함!)1
2
3
4
5
6
7
8
9
10
11{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react"
},
"include": ["./src/**/*"]
}
리액트 Entry File 설정
보통 cra 시 다음과 같은 디렉토리를 갖게 된다. (직접 만들어야 하는 파일만 명시해둠)
1
2
3
4
5
6
7
8
9node_modules
public
index.html
src
App.tsx
index.tsx
package.json
tsconfig.json
...따라서 먼저 Component를 만들어보자.
1
import * as React from "react";// 함수형 컴포넌트const App: React.FunctionComponent<{ name: string }> = ({ children, name }) => ( <div title={name}>{children}</div>);export default App;
그리고 html에서 script로 읽을
index.js
를 생성하자.1
import * as React from "react";import * as ReactDOM from "react-dom";import App from "./App";// 클래스형 컴포넌트class Root extends React.Component { render() { return ( <div> <App name="test"> test </App> </div> ); }}ReactDOM.render(<Root />, document.getElementById("root"));
원래는 따로 클래스 정의 없이
ReactDOM.render()
에 클래스 컴포넌트 렌더 안에 들어있는 코드를 적어 바로 컴포넌트를 전달한다. 축약하면 다음과 같다.1
ReactDOM.render( <App />, document.getElementById('root'));
이제 최종적으로 js 파일을 전달할
public/index.html
을 정의하자!1
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>채용 프로세스 이메일 템플릿</title> </head> <body> <div id="root"></div> <!-- 번들 파일 추가 --> <script src="./bundle.js"></script> </body></html>
html은
id="root"
를 통해 index 파일의document.getElementById("root")
를 읽어나가기 때문에, 따로 script를 적용하지 않는다. 하지만, 이src/index.js
를 읽기 위해 webpack 번들러를 설정하였으므로, 해당bundle.js
파일을 script로 적용해야 한다!꼭
<div id="root"></div>
밑에 전달해야 한단다.
내 생각에는 html을 읽는 순서 때문에 그런듯.Babel 설정하기
trans-compile을 위해
.babelrc
나babel.config.js
로 설정한다.1
{ "presets": [ "@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript" ]}
webpack 설정하기
이 모든 과정을 연결하기 위해 번들러 webpack을 설정한다. 바벨과 같이
webpack.config.js
를 루트 폴더에 만들면 됨!1
module.exports = { entry: ["./src/index.tsx"], output: { filename: "bundle.js", publicPath: "/", path: __dirname + "dist" }, module: { rules: [ { test: /\.(js|jsx|ts|tsx)$/, exclude: /node_modules/, use: ["babel-loader"] } ] }, resolve: { extensions: ["*", ".js", ".jsx", ".ts", ".tsx"] }};
resolve
: 확장자나 경로를 알아서 처리할 수 있도록 설정하는 옵션이다.module
: 이 옵션에 설치한 ts-loader와 babel-loader를 설정하면 된다. loader들은 오른쪽에서 왼쪽 방향으로 적용되기 때문에 ts-loader를 babel-loader보다 오른쪽에 위치시켜야 한다.output
: 번들화 된 파일을 export할 경로와 파일명을 설정한다.
마지막으로,
package.json
에서script
를 설정해주면 된다.npm start
또는npm run start
로 script를 실행할 수 있도록 다음과 같이 설정하면 됨!npm run 시 script 내부의 명령어을 적용할 수 있다!
1
"scripts": { "start": "webpack-dev-server --config ./webpack.config.js --mode development", "test": "echo \"Error: no test specified\" && exit 1" },
FAQ
웹팩 설정에서 사용된
inline
모드는 무엇일까?네트워크 방화벽 구성과 동일하게 모든 트래픽이 해당 보안장비를 거쳐야만 목적지로 전송될 수 있도록 네트워크를 구성하는 방식
hot
모드는?Hot Module Replacement(HMR)는 응용프로그램 실행 중에 추가 또는 제거된 모듈들을 페이지 리로드 없이 교체하는 기능입니다.
Reference
리액트 - 타입스크립트 시작하기 (without CRA)
위 블로그 기반으로,
CRA없이 React + TypeScript 셋팅하기! - chanyeong
위 블로그는 심화형임