본문 바로가기

[IT/Programming]/HTML related

React 를 배워보자. (Learning React) with TypeScript and esbuild bundling

728x90
반응형
# React 를 배워보자. (Learning React) with TypeScript and esbuild bundling ## PH
  • 2024-08-28 : First posting.
## TOC ## Initiate React App Bundler 로는 Tree shaking 과 multi threading 을 지원해서 가장 빠르고 좋다는 esbuild 를 사용합시다. ``` mkdir hello_react cd hello_react npm init react-app . npm run start npm install --save-exact --save-dev esbuild npm audit fix --force // audit 뜻 : 1.감사 2.단속 3.청강 4.세무조사 npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader css-loader // 여기까지만 깔고 진행하면 될듯. 나머지는 npm init react-app . 실행하면서 대부분 깔렸을듯. Netlify 같은 remote server 에 올리려면 Bundler 만 필요한거니까... // 그리고 매 .js file 마다 import React from 'react'; 를 안쓰려면, @babel/preset-react 같은걸 깔아야 하는듯? npm install react react-dom jquery immer use-immer npm install -g typescript npm install typescript typescript@next @types/react @types/react-dom @types/jquery ts-loader @babel/preset-typescript --save-dev tsc --init ```/ typescript 를 깔았기 때문에 project 에 typescript file 이 한개는 존재 해야 함. Error 를 방지하기 위해... 의미없는 빈 .ts file 을 하나 만들어서 넣어줍시다. ``` // * ./src/placeholder.ts export {}; ```/ ### 모든 React file 들에서 import React from 'react'; 를 생략할 수 있게 만드는 세팅. 우선 최상위 폴더에 react-shim.js 란 file 을 다음과 같이 작성해 줍시다. ``` import React from 'react'; export { React }; ```/ 그리고 esbuild.config.js file 을 다음과 같이 설정해 줍시다. ``` import esbuild from 'esbuild'; esbuild.build({ sourcemap: true, logLevel: 'info', platform: 'browser', entryPoints: ['src/index.js'], bundle: true, minify: true, outfile: 'dist/esb-bundle.js', write: true, loader: { '.js': 'jsx', '.svg': 'file', '.jpg': 'file', '.jpeg': 'file', '.png': 'file', }, define: { 'process.env.NODE_ENV': '"production"' }, jsxFactory: 'React.createElement', jsxFragment: 'React.Fragment', inject: ['./react-shim.js'], // 자동 주입 파일 추가 // Other options... }) .catch(() => process.exit(1)); ```/ 마지막 줄 inject 가 핵심. React 18 에서부터인가는 explicit 하게 React 를 import 할 필요가 없다고 들은것도 같은데... esbuild 해보니 React 가 정의되지 않았다고 뜨길래, Copilot 한테 물어봐서 이렇게 해결. 더 좋은 방법도 있을거 같긴 한데... 잘 모르겄음. 한 react-app directory 에 한가지 page 만 구현하지는 않으니까 다음과 같이 esbuild.config.js 를 만들어 놓고 node .\esbuild.config.js [pagename] 을 실행해주면 되는거 같음. ``` import esbuild from 'esbuild'; // Get the page name from the command line arguments let pageName = process.argv[2]; let dirName = `${pageName}/`; if (!pageName) { console.log('Default is index[.js]'); pageName = 'index'; dirName = ''; } esbuild.build({ sourcemap: true, logLevel: 'info', platform: 'browser', entryPoints: [`src/${pageName}.js`], bundle: true, minify: true, outfile: `dist/${dirName}esb-bundle.js`, write: true, loader: { '.js': 'jsx', '.svg': 'file', '.jpg': 'file', '.jpeg': 'file', '.png': 'file', }, define: { 'process.env.NODE_ENV': '"production"' }, jsxFactory: 'React.createElement', jsxFragment: 'React.Fragment', inject: ['./react-shim.js'], // 자동 주입 파일 추가 // Other options... }) .catch(() => process.exit(1)); ```/ 매번 파일이 수정될때마다 변경된 사항을 다 적용시켜줘야 하니까 build-all.bat file 을 다음과 같이 만들어놓고 이걸 실행시키면 될거 같음. ``` node .\esbuild.config.js node .\esbuild.config.js login node .\esbuild.config.js signup node .\esbuild.config.js items ```/ ### package.json 설정 with esbuild. 이렇게 하면 package.json 은 다음과 같이 됨. TypeScript version 이 너무 높아서 문제가 생기는 것도 같음. 아래 package.json 을 복붙 저장한 다음 npm install 로 까는게 더 안전해 보임. ``` { "name": "moviepedia", "version": "0.1.0", "private": true, "type": "module", "dependencies": { "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "immer": "^10.1.1", "jquery": "^3.7.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-scripts": "^3.4.4", "use-immer": "^0.10.0", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": ".\\node_modules\\.bin\\esbuild .\\src\\index.js --loader:.svg=file --loader:.js=jsx --bundle --minify --outfile=.\\dist\\esb-bundle.js", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "@babel/preset-typescript": "^7.24.7", "@types/jquery": "^3.5.30", "@types/react": "^18.3.4", "@types/react-dom": "^18.3.0", "esbuild": "0.23.1", "ts-loader": "^9.5.1", "typescript": "^3.2.1" } } ```/ 일일히 package 들을 install 하기 귀찮다면, 이 package.json 파일만 잘 만들어 저정해 놓고 npm install 혹은 npm install --upgrade 로 까시면 됨. 중간 중간 막히는 부분은 ChatGPTCopilot, Claude, Gemini, Cue 등 AI 에게 물어보면서 해결하시길... svg 가 제대로 처리가 안되던데 --loader:.svg=file 설정 집어넣으니까 잘 됐던거 같음. Bundling 실행은 npm run build ### tsconfig.json 설정. tsconfig.json 설정은 대충 아래와 같이 했고... ``` { "compilerOptions": { "target": "ES2022", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "ES2022", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": [ "src" ] } ```/ ### esbuild.config.js 설정. esbuild.config.js 설정은 다음과 같이 함. npm run build 로 bundling 을 하는게 아니라 node .\esbuild.config.js 를 입력해서 bundling 을 해야 하는거 같음. ``` import esbuild from 'esbuild'; esbuild.build({ sourcemap: true, logLevel: 'info', platform: 'browser', entryPoints: ['src/index.js'], bundle: true, minify: true, outfile: 'dist/esb-bundle.js', write: true, loader: { '.svg': 'file', '.jpg': 'file', '.jpeg': 'file', '.png': 'file', '.js': 'jsx' }, // Other options... }) .catch(() => process.exit(1)); ```/ ### public/index.html 만 남기고 다 지우고 초기화. ```[.lang-html] <!DOCTYPE html> <html lang="ko"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>주사위 게임</title> </head> <body> <div id="root"></div> </body> </html> ```/ ### index.js 만 남기고 다 지우고 초기화. ```[.lang-jsx] import ReactDOM from 'react-dom/client'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<h1>안녕 리액트!</h1>); ```/ ## 반드시 하나의 요소로 감싸기 - Fragment or <></> 최상위로 원소를 2개 이상 붙이고 싶을 때 쓰는 tag ``` <Fragment> <div>가위</div> <div>바위</div> <div>보</div> </Fragment> or <> <div>가위</div> <div>바위</div> <div>보</div> </> ```/ ## JavaScript JSX 안에 쓰기. ``` import ReactDOM from 'react-dom/client'; const product = "MacBook"; const model = "Air"; const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<h1>{product} {model} 주문하기</h1>); ```/ {} 안에는 JavaScript 표현식만 가능. if else 같은 건 못 씀. JSX 문법도 결국은 자바스크립트 문법이기 때문에, for 나 class 처럼 자바스크립트의 문법에 해당하는 예약어와 똑같은 이름의 속성명은 사용할 수 없습니다. 그래서 HTML 의 for 의 경우에는 자바스크립트의 반복문 키워드 for 와 겹치기 때문에 htmlFor 로, HTML 의 class 속성도 자바스크립트의 클래스 키워드 class 와 겹치기 때문에 className 으로 작성해 주어야 합니다. ## Component React element React function component: 첫문자는 대문자로 시작해야 함. React lets you combine your markup, CSS, and JavaScript into custom “components”, reusable UI elements for your app. React components are regular JavaScript functions, but their names must start with a capital letter or they won’t work! Without parentheses, any code on the lines after return will be ignored! https://react.dev/learn/your-first-component ``` function Hello() { return <h1>Hello World!</h1> } ```/ ## Props and children 기본적으로 React component 는 props 라는 properties (or attributes) 와 React tag 안의 내용물인 children 을 가지고 있는데 이것 모두 function component 에서 첫번째 parameter 로 전달 받을 수 있음. ``` function Dice(props) { return (<div> <h2>{props.title}</h2> <p>{props.description}</p> <div>{props.children}</div> </div>); } export default Dice; ```/ 위의 Dice 란 React component 를 쓰려면 우선 import 를 하고 적절한 props (or attributes) 를 넣어서 전달해 주면 됨. ``` import Dice from "./Dice.js"; function App() { return (<> <Dice title="I am title!" description="I am description!"> I am children <div>Children can be plain text or another react component or HTML elements</div> <Hello/> </Dice> </>) } ```/ ## Refactoring ### Reusing components ### Refactoring
Check out redundancy: 중복 Compute num and sum from records: 계산하는 속성 vs 저장하는 속성 records num, sum 은 records 로부터 뽑아낼 수 있다. 계산이 오래 걸리거나, 빈번할 경우 귀찮다. 그 경우는 계산 속성도 저장하는게 좋을때도.
### React rendering 첫 rendering: Page 를 처음 불러올 때. Props 로 사용자가 처음 봐야 할 내용/데이터를 전달. Rerendering (첫 rendering 이후): State 가 바뀔 때. props, state state 가 바뀔 때
Virtual DOM 에서 미리 rerendering 을 해보고, 바뀐 부분만 (diff 란 효율적인 중간과정을 거쳐서 :: git 에서 사용되는 diff 랑 비슷한 algorithm) 실제 DOM 에 update 가 필요한 부분만 rerendering.
## inline style ``` <div style={{backgroundColor:"black", fontFamily:"맑은 고딕", color:"white"}}></div> ```/ CamelCase 로 입력 {{}} 두개 써서 JSON object 를 넘겨주는 방식으로... ## CSS className Create index.css under src. Import index.css in index.js. (automatically included in head) ## RRA
  1. https://react.dev/
  2. https://react.dev/learn/react-developer-tools
  3. kipid's blog :: React 사용 설정하기 (esbuild) with TypeScript
  4. geundung.dev :: esbuild 기반 React Native 번들러 개발기
    // 토스 개발자로 알고 있음. 유튜브 링크도 있었던거 같긴 한데... Tree Shacking 도 지원하고 multi thread 로 돌아가서 esbuild 가 다른 bundler 보다 훨씬 빠르고 좋다는 결론.
  5. https://publish.obsidian.md/iasandcb/
    https://publish.obsidian.md/iasandcb/site/2024-08-26
    https://publish.obsidian.md/iasandcb/site/2024-08-27
    https://publish.obsidian.md/iasandcb/site/2024-08-28
    https://publish.obsidian.md/iasandcb/site/2024-08-29
    https://publish.obsidian.md/iasandcb/site/2024-08-30
728x90
반응형

'[IT/Programming] > HTML related' 카테고리의 다른 글

week1 위클리 페이퍼 (CSS 에 대해 설명 (position, display: flex and grid), 시맨틱 (Semantic) 태그를 사용하면 좋은 점)  (4) 2024.09.14
React Router 에서 CSS 충돌을 막고 좀 더 개발 친화적으로 CSS 를 다룰 수 있게 해주는 CSS module 을 배워봅시다. (Learning module.css)  (6) 2024.09.13
JAVA 에서 Selenium 이 제대로 동작 안할 때 해결법  (0) 2024.09.10
week6 위클리 페이퍼 (웹 페이지 렌더링 방식 CSR, SSR, SSG 각각의 특징과 각 방식을 어떤 상황에 사용하면 좋을지 설명)  (3) 2024.09.03
week5 위클리 페이퍼 (useMemo, useCallback 에 대해 설명하고, 어떤 경우에 사용하면 좋을지, 남용할 경우 발생할 수 있는 문제점을 설명, 리액트 생명주기 (life cycle) 에 대해 설명, React 에서 배열을 렌더링할 때 key 를 설정해야 하는 이유와 key 설정 시 주의할 점을 설명)  (0) 2024.09.03
JavaScript 중급 서술형 평가 (자바스크립트에서 this 키워드의 사용과 그 특성에 대해 설명, 렉시컬 스코프(Lexical Scope)의 개념과 그 특성에 대해 설명, 브라우저가 어떻게 동작하는지 설명, 이벤트 버블링과 캡처링을 설명하고 이를 방지하기 위한 방법을 서술, 프로미스(Promise)의 3가지 상태에 대해 설명)  (0) 2024.08.31
마지막이 ```/ 로 끝나면 error 나는거 해결합시다.  (3) 2024.08.30