25%
29,700원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결Slack 클론 코딩[실시간 채팅 with React]
최초 로그인 시 새로고침을 하지 않으면 워크 스페이스가 뜨지 않습니다.
백 엔드 서버를 가동하고 로그인을 하면 이러한 창이 뜹니다. 이 상태에서 새로고침을 하면 정상적으로 워크스페이스를 제대로 가져오는데 혹시 가져오기 직전에(userData가 undefined) 화면이 렌더링 돼서 저러한 에러가 뜨는걸까요? 아무리 해결을 해보려 해도 되지 않아 이렇게 질문 남깁니다. 제 코드는 아래와 같습니다 import React, { VFC, useCallback, useState } from 'react'; import useSWR from 'swr'; import fetcher from '@utils/fetcher'; import axios from 'axios'; import { Redirect, Route } from 'react-router'; import { Header, RightMenu, ProfileImg, WorkspaceWrapper, Workspaces, Channels, Chats, WorkspaceName, MenuScroll, ProfileModal, LogOutButton, WorkspaceButton, AddButton, WorkspaceModal, } from '@layouts/Workspace/styles'; import gravatar from 'gravatar'; import { toast } from 'react-toastify'; import { IUser } from '@typings/db'; import { Link, Switch } from 'react-router-dom'; import loadable from '@loadable/component'; const Channel = loadable(() => import('@pages/Channel')); const DirectMessage = loadable(() => import('@pages/DirectMessage')); import Menu from '@components/Menu'; import { Button, Input, Label } from '@pages/SignUp/styles'; import useInput from '@hooks/useInput'; import Modal from '@components/Modal'; import CreateChannelModal from '@components/CreateChannelModal'; const Workspace: VFC = () => { const [showUserMenu, setShowUserMenu] = useState(false); const [showCreateWorkspaceModal, setShowCreateWorkspaceModal] = useState(false); const [showWorkspaceModal, setShowWorkspaceModal] = useState(false); const [showCreateChannelModal, setShowCreateChannelModal] = useState(false); const [newWorkspace, onChangeNewWorkspace, setNewWorkspace] = useInput(''); const [newUrl, onChangeNewUrl, setNewUrl] = useInput(''); const { data: userData, revalidate, mutate, } = useSWR<IUser | false>('http://localhost:3095/api/users', fetcher, { dedupingInterval: 2000, }); const onLogout = useCallback(() => { axios .post('http://localhost:3095/api/users/logout', null, { withCredentials: true, }) .then(() => { mutate(false, false); }); }, []); const onCloseUserProfile = useCallback((e) => { e.stopPropagation(); setShowUserMenu(false); }, []); const onClickUserProfile = useCallback(() => { setShowUserMenu((prev) => !prev); }, []); const onClickCreateWorkspace = useCallback(() => { setShowCreateWorkspaceModal(true); }, []); const onCreateWorkspace = useCallback( (e) => { e.preventDefault(); // 새로고침 방지 // 폼 검사 if (!newWorkspace || !newWorkspace.trim()) return; if (!newUrl || !newUrl.trim()) return; axios .post( 'http://localhost:3095/api/workspaces', { workspace: newWorkspace, url: newUrl, }, { withCredentials: true }, // CORS ) .then(() => { revalidate(); setShowCreateWorkspaceModal(false); setNewWorkspace(''); setNewUrl(''); }) .catch((error) => { console.dir(error); toast.error(error.response?.data, { position: 'bottom-center' }); }); }, [newWorkspace, newUrl], ); const onCloseModal = useCallback(() => { setShowCreateWorkspaceModal(false); setShowCreateChannelModal(false); }, []); const toggleWorkspaceModal = useCallback(() => { setShowWorkspaceModal((prev) => !prev); }, []); const onClickAddChannel = useCallback(() => { setShowCreateChannelModal(true); }, []); if (!userData) { return <Redirect to="/login" />; } return ( <div> <Header> <RightMenu> <span onClick={onClickUserProfile}> <ProfileImg src={gravatar.url(userData.email, { s: '28px', d: 'retro' })} alt={userData.nickname} /> {showUserMenu && ( <Menu style={{ right: 0, top: 38 }} show={showUserMenu} onCloseModal={onCloseUserProfile}> <ProfileModal> <img src={gravatar.url(userData.email, { s: '36px', d: 'retro' })} alt={userData.nickname} /> <div> <span id="profile-name">{userData.nickname}</span> <span id="profile-active">Active</span> </div> </ProfileModal> <LogOutButton onClick={onLogout}>로그아웃</LogOutButton> </Menu> )} </span> </RightMenu> </Header> <WorkspaceWrapper> <Workspaces> {userData?.Workspaces.map((ws) => { return ( <Link key={ws.id} to={`/workspace/${123}/channel/일반`}> <WorkspaceButton>{ws.name.slice(0, 1).toUpperCase()}</WorkspaceButton> </Link> ); })} <AddButton onClick={onClickCreateWorkspace}>+</AddButton> </Workspaces> <Channels> <WorkspaceName onClick={toggleWorkspaceModal}>Sleact</WorkspaceName> <MenuScroll> <Menu show={showWorkspaceModal} onCloseModal={toggleWorkspaceModal} style={{ top: 95, left: 80 }}> <WorkspaceModal> <h2>Sleact</h2> <button onClick={onClickAddChannel}>채널 만들기</button> <button onClick={onLogout}>로그아웃</button> </WorkspaceModal> </Menu> </MenuScroll> </Channels> <Chats> <Switch> <Route path="/workspace/channel" component={Channel} /> <Route path="/workspace/dm" component={DirectMessage} /> </Switch> </Chats> </WorkspaceWrapper> <Modal show={showCreateWorkspaceModal} onCloseModal={onCloseModal}> <form onSubmit={onCreateWorkspace}> <Label id="workspace-label"> <span>워크스페이스 이름</span> <Input id="workspace" value={newWorkspace} onChange={onChangeNewWorkspace} /> </Label> <Label id="workspace-url-label"> <span>워크스페이스 url</span> <Input id="workspace" value={newUrl} onChange={onChangeNewUrl} /> </Label> <Button type="submit">생성하기</Button> </form> </Modal> <CreateChannelModal show={showCreateChannelModal} onCloseModal={onCloseModal} /> </div> ); }; export default Workspace; 항상 질 좋은 강의 잘 듣고 있습니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
useCallback 관련 질문있습니다.
안녕하세요 제로초님 항상 질 좋은 강의 잘 듣고 있습니다. 다름이 아니라 useCallback과 관련하여 질문이 있는데요 만약 두번째 인자인 'deps'배열이 비게 되는 상황에도 무조건 useCallback으로 함수를 감싸주는게 맞나요? deps배열에 아무 요소도 들어가지 않는다면 굳이 써줘서 deps 배열을 검사하는 비용을 낭비할 필요가 없다. 라는 지인의 의견이 있어서 궁금하여 이렇게 질문 올립니다. 감사합니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
배포가 잘 안되어서 질문드립니다 ㅠㅠ
이번에 Front 강의 끝까지 마치고 배포하려고 하는데 build한 결과물(dist폴더+index.html)을 back/public에 옮겨넣어서 배포하면 되는것이 맞을까요??? 위의 방법으로 해보니 로컬에서 npm run dev로 실행하였을때는 잘 실행이 되는데, Nodebird강좌에서 알려주신대로 AWS에서 npm start를 하니 로그인 창에서 로그인을 해도 workspace화면으로 넘어가지지를 않네요ㅠㅠ 원인을 분석하려 네트워크탭을 보니 login정보는 잘 POST보내나 users정보를 get할때 자꾸 false로 들어오네요 ㅠㅠ 이게 back에서의 문제인지... front쪽의 문제인지.... 아직 초보인지라 어디가 어떻게 문제인지 감이 하나도 잡히지가 않습니다 ㅠㅠ 구글링으로만 3일 고생하다가 도저히 방법을 못찾겠어서 질문으로 남겨봅니당... /// Front-End 위주로 공부하고 있어서 백엔드 강의는 듣지않았습니다!! 혹시 듣는다면 해결이 될까요?? /// 혹시나 코드중에 제가 놓치거나 오타를 낸게 있을까 싶어 제로초님 깃헙을 클론해서 똑같은방법으로 배포해봤는데 똑같이 false가 반환됩니다 ㅠㅠㅠ 제가 뭔가 놓치고 있는것이 있는걸까요?
- 미해결Slack 클론 코딩[실시간 채팅 with React]
채팅 바로바로 안올라가는이유
채팅을 치는데 새로고침해야 먹는거는 왜그런건가요? 제로초님처럼 딱딱 올라가지는 않네요
- 미해결Slack 클론 코딩[실시간 채팅 with React]
강의를 따라하다 에러가 나서 질문을 올립니다.
강의를 보며 따라 치고 있던 와중 에러가 출력되었습니다. 우선 이 부분에서 에러가 출력되어 다른 분의 질문을 보고 typings에서 타입 인터페이스를 불러와 적용시켜주니 해결이 되었습니다. 하지만 이를 해결하고나니 마찬가지로 다른 분과 똑같은 에러가 출력되었습니다. 에러를 봐서는 1위치에 있는 형식들이 서로 호환이 되지 않는다는 에러로 출력됩니다. fetcher 부분에 return을 추가하라는 말씀을 들었는데 애로우 펑션은 한 줄로 정의되면 자동으로 리턴이 되지 않나요 일단 추가해봤을 때에도 에러는 출력되었습니다. 항상 질 좋은 강의를 올려주시고 성실한 답변 감사합니다.
- 해결됨Slack 클론 코딩[실시간 채팅 with React]
useSWR 관련 에러가 계속 납니다..ㅜ
useSWR<IUser | false> 를 작성하고 . db.ts도 순서대로 작성해줬는데 요청 url에 계속해서 빨간줄이 안없어 지더니 겨우 해결하고 나니 fetcher 부분이 계속 오류가 발생합니다. 무슨 이유인지 도무지 모르겠습니다...;ㅜ
- 미해결Slack 클론 코딩[실시간 채팅 with React]
제로초님 swr 로 api 를 get 요청 할 떄
만약 tsx 파일에서 콘솔로그를 찍어보면? console.log(Product) https://api.minsu.com/product/${undefined} 이런 식으로 error 출력됩니다. 왜 이러는 걸까요? id 값은 usePrams 로 const { id } = useParams<{ id?: any }>() 으로 타입 지정 해 주었습니다. api에 token 도 걸려 있어서 const token = 'minsu'; // fetcher const fetchWithToken = (url: string, token: string) => axios .get(url, { headers: { Authorization: `Bearer ${token}`, }, }) .then(result => result.data); 이런 식으로 만들어 준 뒤. 이런 식으로 코드 작성을 했는 데, {id} 값이 undefined 값 404 에러 나옵니다 ㅠㅠ const { data: ProductDetail } = useSWR(`https://api.minsu.com/product/${id}, url => fetchWithToken(url, token));
- 미해결Slack 클론 코딩[실시간 채팅 with React]
cannot read properties of undefined reading map 오류
안녕하세요 질문하나 남깁니다 그전에도 map관련 못읽어오는 오류가 뜨기는 했었는데 새로고침 한번 하면 사라졌거든요 그런데 dm 관련 화면이 안떠서 결국 로그찍어봤는데 undefinedr가 뜨길래 못받는가보다 생각이 드는데 어딘지 못찾겠네요 어떻게 디버깅하면 좋을까요?
- 미해결Slack 클론 코딩[실시간 채팅 with React]
안녕하세요 제로초님 문의사항이 있는데요
이 강의랑 연관되는 백앤드 강의는 없나요? 백앤드 강의듣고 본 강의 같이 사용 가능한 강의가 있는지 확인부탁드려요
- 미해결Slack 클론 코딩[실시간 채팅 with React]
안녕하세요 제로초님
제가 img 파일에다가 img 을 올려 놓고 싶은데 webpack 설정에 { test: /\.(jpe?g|png|gif|svg)$/, loader: 'file-loader' } 을 만들어 놓고 png 파일을 <img src='./logo.png'/> 이런식으로 불려 올려 하는 데. 계속 이미지가 안나오네요 제가 그래서 public 폴더에 logo.png 넣어 놓고 ../../public/logo@3x.png 이런 식으로 불러 올려 했는데 계속 나오지 않습니다. ㅠㅠ 웹팩에 또 다른 설정을 해줘야 하는 건가요? import logo from '/logo3x.png' 이런식 으로 불려 올려 해도 logo3x.png 이미지 가 없다고 나오고 그럽니다 ㅠㅠ
- 미해결Slack 클론 코딩[실시간 채팅 with React]
안녕하세요 제로초님 3:25초경에 해당하는 주소에 들어가서 css 파일로 만들어서 html에 연결했는데 css파일에서 오류가 발생했습니다.
안녕하세요 제로초님 3:25초경에 해당하는 주소에 들어가서 css 파일로 만들어서 html에 연결했는데 css파일에서 오류가 발생했습니다. css 파일 내에서 only속성 때문에 오류가 발생하는데요.. 아래는 html 파일과 css 파일입니다. html 파일은 강의에서 말씀하신대로 슬랙에 들어가 현재에 맞게 아이콘 코드를 바꿔주었습니다. 그래도 적용이되지 않아서 파일로 만드려고 해당하는 주소에 들어가서 css 파일 내용을 복사했는데 어디가 문제인지 모르겠습니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
안녕하세요 제로초님 다이렉트 메세지에서 아이콘이 뜨지 않아 문의드립니다.
안녕하세요 제로초님 강의를 보면서 따라하고 있는데 저는 다이렉트메세지에서 아이콘이 보여지지 않아서 문의드리려고 합니다. 개발자도구 - 콘솔창에서 확인했을떄 Failed to load resource: the server responded with a status of 403() 다음과 같은 오류메세지를 뱉어내는데 [애드센스]오류라고 해서요.. 어떻게 해결해야할지 감이 오지 않아서 문의드립니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
채널 생성시 개발자도구에서
안녕하세요 채널 생성시 채널생성이 되지 않고 개발자도구 network란에 "존재하지 않는 워크스페이스 입니다" 라고 뜹니다. 타이핑도 모두 동일하고 어느부분이 잘못됬는지 잘 모르겠습니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
08:11초 CreateChannelModal 임포트시 오류발생
안녕하세요 제로초님 08:11초에서 CreateChannelModal import 할때 아래 setShowCreateChannelModal에서 아래와 같은 오류가 발생합니다. (구글에서 구글링해보고 다 해봤는데 어디가 문제인지 몰라 여쭈어보려고 합니다.) '{ show: boolean; onCloseModal: () => void; setShowCreateChannelModal: Dispatch<SetStateAction<boolean>>; }' 형식은 'IntrinsicAttributes & Props' 형식에 할당할 수 없습니다.'IntrinsicAttributes & Props' 형식에 'setShowCreateChannelModal' 속성이 없습니다.ts(2322)
- 미해결Slack 클론 코딩[실시간 채팅 with React]
Link가 아닌 브라우저를 통한 직접 접근
안녕하세요 강사님 현재 프로젝트에서 /workspace/channel 처럼 중첩 라우팅을 한 페이지의 경우 Router를 통한 접근에서는 정상적으로 동작하고 브라우저에 직접 검색할 때는 404 에러를 응답받습니다. 왜 그런지 알 수 있을까요? 강의 진행에서는 브라우저로 직접 접근해도 에러가 발생하지 않아서요. 어디서 발생한 문제인지 감이 안잡혀서 구글링을 할 수가 없습니다... 일단 historyApiFallback 설정은 되어있어 depth 1단계의 페이지는 브라우저를 통해 직접 접근해도 잘 접근이 됩니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
npm run dev 시 에러가 나는데 해결이 안됩니다..
이것저것 다 시도해보아도 계속 이 에러가 납니다.. 노드 버전의 문제일까요? 현재 12.20 버전쓰고있습니다 ㅠㅠ
- 미해결Slack 클론 코딩[실시간 채팅 with React]
webpack-dev-server 핫리로딩 관련 질문입니다.
안녕하세요 저도 CRA로 무작정 만드는 것 보다는 한번쯤은 실제로 만들어보면서 에러도 만나보고 구글링해서 해결해보는 경험을 쌓는 것이 정말 중요하다고 생각합니다. 그래서 실제로 따라해보면서 build까지는 완료했는데 마지막에 문제가 생겨서 질문을 드립니다. 일단 bulid는 정상적으로 동작합니다. 핫리로딩을 적용하려고 해보니까 실행은 정상적으로 되는데 404오류가 떠서 질문드립니다. ( devMiddleware: { publicPath: '/dist/' }는 실행은 되는데 404오류 ) (publicPath: "/dist/"는 실행 자체에서 문제 ) http://localhost:3090, http://localhost:3090/dist 등 해볼만한건 다 해봐도 아무 파일을 받아오지 못하는데 뭐때문일까요...? index.html의 <script>도 /dist/app.js 랑 ./dist/app.js모두 실행해봤고, 다른 설정파일들은 모두 setting에 있던 파일들을 그대로 복사해서 붙여넣었기때문에 오타는 없습니다. package.json { "name": "sleact-front", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack", "dev": "cross-env TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack serve --env development" }, "author": "1-blue", "license": "ISC", "dependencies": { "@types/react": "^17.0.27", "@types/react-dom": "^17.0.9", "cross-env": "^7.0.3", "react": "^17.0.2", "react-dom": "^17.0.2", "typescript": "^4.4.3" }, "devDependencies": { "@babel/core": "^7.15.8", "@babel/preset-env": "^7.15.8", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.1", "@types/node": "^16.10.3", "@types/webpack": "^5.28.0", "@types/webpack-dev-server": "^4.3.1", "babel-loader": "^8.2.2", "css-loader": "^6.3.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0", "fork-ts-checker-webpack-plugin": "^6.3.4", "prettier": "^2.4.1", "react-refresh": "^0.10.0", "style-loader": "^3.3.0", "ts-node": "^10.2.1", "webpack": "^5.58.1", "webpack-cli": "^4.9.0", "webpack-dev-server": "^4.3.1" } } 아래는 webpack.config.ts 파일내용입니다. import path from 'path'; import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'; import webpack, { Configuration as WebpackConfiguration } from "webpack"; import { Configuration as WebpackDevServerConfiguration } from "webpack-dev-server"; import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; 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: ['.ts', '.tsx', '.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: /\.tsx?$/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { targets: { browsers: ['last 2 chrome versions'] }, debug: isDevelopment, }, ], '@babel/preset-react', '@babel/preset-typescript', ], env: { development: { plugins: [require.resolve('react-refresh/babel')], }, }, }, exclude: path.join(__dirname, 'node_modules'), }, { 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/' }, // 이거는 실행은 되는데 404오류입니다... publicPath: '/dist/', // 여기서 오류 ( 아래는 오류 문구입니다. ) /** * '{ historyApiFallback: true; port: number; publicPath: string; }' 형식은 'Configuration' 형식에 할당할 수 없습니다. * 개체 리터럴은 알려진 속성만 지정할 수 있으며 'Configuration' 형식에 'publicPath'이(가) 없습니다.ts(2322) */ }, }; if (isDevelopment && config.plugins) { config.plugins.push(new webpack.HotModuleReplacementPlugin()); config.plugins.push(new ReactRefreshWebpackPlugin({ overlay: { useURLPolyfill: true } })); } if (!isDevelopment && config.plugins) { } export default config;
- 미해결Slack 클론 코딩[실시간 채팅 with React]
webpack 설정 질문있습니다!
devMiddleware 1.해당 설정은 버전이 올라가면서 바뀐 거 같은데 해석을 읽어봐도 이해가 잘 안돼서요 혹시 devMiddleware 와 static 과 다른점이 있을까요 ? 2. 꼭 2개 다 설정해주어야하나요 ?? 더하여, 3.해당 오류 메시지들은 해당 패키지를 다 다운받아야하는걸까요? 4.pakage.json에서 script트 부분에 해당 라인이 어떤걸 의미하는지 궁금합니다. TS_NODE_PROJECT
- 미해결Slack 클론 코딩[실시간 채팅 with React]
제로초님 질문있습니다!
const Home = () => {}에는 JSX.Element를 포함하고 있는거죠? function Home(): JSX.Element {}위에 두 방식에서 차이점은 JSX.Element를 빼면 화살표 함수를 쓰냐 안쓰냐만 차이가 나는건가요?
- 미해결Slack 클론 코딩[실시간 채팅 with React]
사이트 초기 진입 시 output 경로인 dist에 요청하는 이유
안녕하세요 강사님. 웹팩 설정에 대해 짐작이 가는 키워드로 구글링해 보았는데 답을 찾을 수 없어 질문 드립니다. 현재 제가 수업 진행에 사용 중인 모듈은 webpack: 5.56 webpack-dev-server: 4.3 이고 강의 진행에 사용 중인 모듈은 webpack: 5.22 webpack-dev-server: 3.11.2 입니다. 우선 처음에 상위 버전으로 설치를해서 안되서 버전 다운 그레이드 후에 진행했을 때는 잘 되었습니다. 그래도 최신 버전으로 진행해보고싶어 공식 문서를 찾아서 핫 리로딩은 되는데, 사이트 초기진입 시 output 경로('dist')에 요청을 보내고 이후 root('/') 로 다시 요청을 보내 파일을 받아옵니다. 초기 진입 시 요청 (실패) 다음 요청 (성공) 제 생각에는 webpack 기본 설정 값 때문에 그런 거라고 생각해서 공식문서 찾아 봤는데 왜 그런지 잘 모르겠습니다... 소스코드 module.exports = { 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.tsx', }, output: { path: path.join(__dirname, 'dist'), filename: '[name].js', clean: true, publicPath: '/', }, devServer: { open: true, historyApiFallback: true, port: 3090, static: { directory: path.resolve(__dirname, 'dist'), publicPath: '/', }, }, module: { rules: [ { test: /\.[jt]sx?$/, use: [ { loader: require.resolve('babel-loader'), options: { presets: [ [ '@babel/preset-env', { targets: { browsers: ['last 2 chrome versions'] }, debug: isDevelopment, }, ], '@babel/preset-react', '@babel/preset-typescript', ], env: { development: { plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean), }, }, }, }, ], exclude: path.join(__dirname, 'node_modules'), }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, ], }, plugins: [ isDevelopment && new webpack.HotModuleReplacementPlugin(), isDevelopment && new ReactRefreshWebpackPlugin(), new HtmlWebpackPlugin({ template: './dist/index.html', filename: 'index.html', }), new ForkTsCheckerWebpackPlugin({ async: false, }), new webpack.EnvironmentPlugin({ NODE_ENV: isDevelopment ? 'development' : 'production' }), ].filter(Boolean), };