안녕하세요 수코딩님 갑자기 의문이 든 생각인데 next js 는 보면 프레임워크라서 여러 기능을 제공하고 편리하게 사용할수있는것같습니다 seo문제도 해결해주고 무엇보다 use client를 사용하면 클라이언트 컴포넌트로서 작동도 되고요 근데 그럼 의문이 드는게 둘다 가능하고 선택가능한 next를 쓰는게 무조건 이득이 아닌가 라는 생각이 들엇습니다. 그냥 서버사이드쪽만 서버사이드 좀하고 리액트가 필요한쪽은 클라이언트 사이드 렌더링으로 하면 되는 이야기인것같아서요
FormEvent는 deprecated 되고 SubmitEvent를 사용하는 것으로 권장된다고 합니다. 그런데 (e: SubmitEvent<HTMLFormElement>) 방식은 FormEvent가 제네릭을 지원하지 않아서 안 된다고 하고 (e: SubmitEventHandler<HTMLFormElement>) 처럼 시도해도 빨간줄이 자꾸 뜹니다. 여기저기 알아보고 const handleSubmit: SubmitEventHandler<HTMLFormElement> = (e) => { ... } 로 하면 된다는데 이들의 차이점과 FormEvent를 사용할 때 처럼 사용하면 안 되는 이유가 궁금합니다.
안녕하세요 영보님 영보님의 빅팬 수강생 한명입니다 영보님 강의 믿고보는 강의기에, 제가 이렇게나 많이 수강중에 있습니다. 텐서플로우 강의는 안샀습니다. 텐서플로우가 뭐지? 라는 의문이 있긴했지만, 웹 개발자에게 텐서플로우가 필요한 강의인가? 자바스크립트로 텐서플로우를 설명해주는 강의인 것은 좋은것 같습니다. 제가 텐서플로우를 현업에서 다루지 않더라도, 강의를 들으면 어떤 이점이 있을지 매우 궁금합니다. 솔직히 이야기해서 영보님이 해주시는 이야기가 궁금해서 듣고싶은 마음이 크고요. 두번째로는 웹개발자가 텐서플로우를 들으면 얻게되는 것이 어떤것이 있는지 궁금합니다.
강의를 들으며 장바구니 페이지에 대해 Cypress로 테스트 코드를 작성하다가 궁금한 점이 몇가지 있어서 질문을 작성합니다 :) 장바구니 페이지에서 '장바구니의 상품을 삭제한 후 장바구니에 담겨있는 총 수량과 가격이 변경된다.'라고 테스트 시나리오를 작성했는데 이런 걸 e2e로 테스트 하는 게 맞는지 잘 모르겠습니다. 이런 부분은 unit 테스트로 넘겨야 하는 부분일까요? e2e테스트는 어떤 걸 중심으로 하면 좋을지 잘 모르겠습니다. 그냥 제가 필요하다고 생각되는 게 있으면 진행을 하면 되는 걸까요? 저도 모르게 저 대신 클릭 등을 수행하고 값을 확인하는 용도로 다루게 되는 것 같습니다. 그래도 일단 1번 질문에서 작성한 테스트 시나리오에 대한 코드를 직접 작성해봤습니다. 이 때, 장바구니 페이지에서 장바구니 아이템 데이터가 getServerSideProps를 통해 주입되고 있더라구요. 이 상황에서 API 모킹을 어떻게 해야할지 몰라서 Claude Sonnet 4.6이랑 구글링을 통해 몇가지 코드를 작성해봤습니다. 단순하게 테스트 코드가 작성되지 않고 다소 복잡하게 작성이 되는 것 같아서 뭔가 이 방향이 맞지 않는 것 같다는 생각이 들었습니다. 그래서 테스트 시나리오 자체를 제가 잘못 생각한 것 같다는 생각이 들기도 했습니다. SSR 환경에서 어떤 코드로 작성을 하는 게 맞는 방식인지 알 수가 없어서 한 번 확인해봐주시면 감사하겠습니다 :) a. nock + intercept 사용 - SSR은 서버 프로세스에서 진행되기 때문에 intercept 할 수 없다고 하여 nock을 사용했습니다. 코드는 해당 링크 를 참고 했습니다. - 그리고 router.replace를 통해 데이터를 refetch 될 때도 백엔드 api를 intercept를 할 수 없다고 해서 '/_next/data/**/*.json'를 intercept 했습니다. - 개인적으로 아래 코드는 'nock'과 'intercept'를 혼용해서 쓰다보니 장기적으로 봤을 때 유지보수성 측면에서 좋지 않은 코드라고 느꼈습니다. it.only('장바구니의 상품을 삭제한 후 총 수량과 가격이 변경된다', () => { // 1) 초기 로드용 nock (SSR - 서버사이드 fetch) cy.task('nock', { hostname: Cypress.env('API_URL'), method: 'GET', path: '/carts', statusCode: 200, body: FIVE_CART_ITEMS, }); // 2) router.replace 후 재조회용 intercept (클라이언트사이드 fetch) cy.intercept('GET', '/_next/data/**/cart.json', { body: { pageProps: { carts: FOUR_CART_ITEMS_AFTER_DELETE }, __N_SSP: true, }, }).as('refetch'); // 삭제 API mock cy.intercept('POST', '/api/cart', { statusCode: 200, body: { data: { name: '4' } }, }).as('deleteCart'); cy.visit('/cart'); // action cy.getByCy('cart-item-delete-button').first().click(); cy.wait('@deleteCart'); cy.wait('@refetch'); // 페이지 갱신 대기 // assertion cy.contains('Unbranded Rubber Chair').should('not.exist'); cy.getByCy('cart-item').should('have.length', 4); cy.getByCy('cart-item-total-amount').should('have.text', '4'); cy.getByCy('cart-item-total-price').should('have.text', '836.00'); }); b. intercept 사용 그래서 초기 로드에도 intercept를 사용했습니다. it.only('장바구니의 상품을 삭제한 후 총 수량과 가격이 변경된다', () => { // 1) 초기 로드용 (SSR - 서버사이드 fetch) cy.intercept('GET', '/_next/data/**/*.json', { body: { pageProps: { carts: FIVE_CART_ITEMS }, __N_SSP: true, }, }); // 2) router.replace 후 재조회용 intercept (클라이언트사이드 fetch) cy.intercept('GET', '/_next/data/**/*.json', { body: { pageProps: { carts: FOUR_CART_ITEMS_AFTER_DELETE }, __N_SSP: true, }, }).as('refetch'); // 삭제 API mock cy.intercept('POST', '/api/cart', { statusCode: 200, body: { data: { name: '4' } }, }).as('deleteCart'); cy.visit('/cart'); // action cy.getByCy('cart-item-delete-button').first().click(); cy.wait('@deleteCart'); cy.wait('@refetch'); // 페이지 갱신 대기 // assertion cy.contains('Unbranded Rubber Chair').should('not.exist'); cy.getByCy('cart-item').should('have.length', 4); cy.getByCy('cart-item-total-amount').should('have.text', '4'); cy.getByCy('cart-item-total-price').should('have.text', '836.00'); }); c. API 모킹을 사용하지 않기 - ssr 환경에서 delete 테스트를 위해 api 모킹을 사용하는 게 오히려 복잡하게 느껴져서 API 모킹을 사용하지 않고 코드를 작성하는 방식을 생각했습니다. - 대신에 테스트 할 때마다 수량과 가격이 변경될 거라고 생각해서 수량과 가격을 캡쳐하는 코드를 추가했습니다. it.only('장바구니의 상품을 추가한 뒤 삭제하면 해당 상품이 사라진다', () => { const cartItem = { "id": "24", "name": "Practical Frozen Pants", "price": "607.00", "imageUrl": "https://cdn.pixabay.com/user/2023/05/21/19-38-51-804_250x250.jpg" } // prepare: API로 상품 직접 추가 cy.request('POST', `${Cypress.env('API_URL')}/carts`, cartItem).then(({ body }) => { cy.visit('/cart'); // 삭제 전 수량과 가격 캡처 cy.getByCy('cart-item-total-amount').invoke('text').then((beforeAmount) => { cy.getByCy('cart-item-total-price').invoke('text').then((beforePrice) => { // action: 방금 추가한 항목 삭제 cy.contains('Practical Frozen Pants') .closest('[data-cy="cart-item"]') .find('[data-cy="cart-item-delete-button"]') .click(); // assertion cy.contains('Practical Frozen Pants').should('not.exist'); cy.getByCy('cart-item-total-amount').should('have.text', String(Number(beforeAmount) - 1)); cy.getByCy('cart-item-total-price').should('have.text', (Number(beforePrice) - cartItem.price).toFixed(2)); }); }); }); }); 일반적으로 delete에 대해 테스트할 때 어떤 식으로 하는지 궁금합니다. 삭제 성공 여부 / 해당 데이터가 보이지 않는지 체크 정도만 하고 삭제가 진행됨으로써 총 아이템 개수 수량이 변경되는 것에 대해서는 테스트 코드로 굳이 짚고 넘어가지 않나요? 실무에서 테스트 데이터는 보통 어떻게 관리하나요? 전부 api 모킹으로 테스트 해야하는 건지, 아니면 테스트용 DB를 따로 생성해서 거기서 테스트를 진행해야하는 건지 궁금합니다. 아니면 상황에 따라서 api 모킹을 해야할 때가 있고, DB를 연결해서 테스트 해야할 때가 있나요? 한번에 질문이 다소 많아서 죄송합니다 ㅠㅠ 완강하고 며칠동안 혼자서 공부해보다가 제대로 제가 하고 있는 건지 모르겠어서 여쭤봅니다 ㅠㅠ 긴 글 읽어주셔서 감사합니다!!
프로젝트 생성 시 위와 같이 선택 하시면 됩니다. (Create TypeScript project 체크 박스 꼭 선택 하세요.) Create 버튼 클릭 하시면 화면 하단 터미널에 설치 옵션을 물어보는 화면이 보이게 됩니다. 그런데, 강의 와는 다르게 터보팩 사용 여부는 물어보지 않아요. Next.js 13 이상 버전에는 터보팩이 이미 내장되어 있습니다. 이 부분은 무시하고 진행 하시면 됩니다. 설치 완료 후, package.json 파일에 아래와 같이 개발 스크립트 부분을 수정 하세요. --turbo 추가 하시면 됩니다. "scripts": { "dev": "next dev --turbo", "build": "next build", "start": "next start", "lint": "eslint" }, 실행은 상단 우측 보시면 아래와 같은게 보이실 겁니다. client-side 와 server-side 가 있는데 server-side 선택 하셔서 실행 하시면 됩니다. (안보이면 웹스톰 재시작 하세요. 지금 단계 에서 client-side 는 선택 하지 마세요. 이 강의를 계속 들어 보시면 저 두가지가 무슨 의미 인지 알게 됩니다.) 터보팩 적용 하여 올바르게 실행 되면 아래와 같이 보일 겁니다.
강사님 안녕하세요 강의 잘 듣고 있습니다. 좋은 강의 감사합니다. 질문이 하나 있습니다. OrderableProductItem 컴포넌트를 따로 만든다는 건 결국 base인 ProductItem 컴포넌트에 주문하기 버튼이 추가된 것인데, 따로 만들거라면 base 컴포넌트인 ProductItem은 진짜 기본적인 상품 정보만 보여주는 컴포넌트로 두고 buton 컴포넌트를 OrderaleComponentItem에서 렌더링 해주면서 order 로직도 여기에 두는 게 좋지 않나? 라는 생각이 들어서요!
Node.js에서는 req와 res 사이에 인증 처리와 같은 로직을 넣기 위해 미들웨어를 직접 만들어야 할 것 입니다. Express에서의 미들웨어 구현과 동작 방식은 최선의 방식인지 궁금합니다! 즉 Express가 아닌 Node.js로 미들웨어를 직접 구현했을때 Express 방식보다 더 나은 설계가 될 수 있는지 궁금합니다. 또 Nest.js (nest 아니더라도 다른 프레임워크) 에서는 Express가 미들웨어를 구현하고 동작시키는 방식을 그대로 따르고 있는지 아니면 설계 상의 차이를 두었는지도 궁금합니다. 감사합니다!
불편해죽겠네요. ai한테 물어봐도, document.querySelectorAll(".CodeMirror-hints-wrapper").forEach((el) => el.remove()) 이런식으로 콘솔에 쳐서 없애라는데, 항상 이렇게 하고 있는데 더 편한 방법은 없나 싶어서 여쭤봅니다.
Next 최신 버전으로 수업 듣고 있습니다. 강의 자료에 이 파일이 들어가있는데 오히려 이 설정을 적용하면 1MB 제한이 걸려 업로드 되지 않습니다 발생된 오류 메시지 Error: Body exceeded 1 MB limit. To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit at ignore-listed frames { statusCode: 413 } ⨯ uncaughtException: Error: Body exceeded 1 MB limit. To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit at ignore-listed frames { statusCode: 413 } ⨯ uncaughtException: Error: Body exceeded 1 MB limit. To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit at ignore-listed frames { statusCode: 413 } ⨯ Error: Body exceeded 1 MB limit. To configure the body size limit for Server Actions, see: https://nextjs.org/docs/app/api-reference/next-config-js/serverActions#bodysizelimit at ignore-listed frames { statusCode: 413, digest: '2270266421@E394' } 강의에서 알려주는 설정으로 해야 1MB 이상 이미지가 정상 업로드 되었습니다. experimental: { // 'experimental' 아래에 serverActions를 정의해야 합니다. serverActions: { bodySizeLimit: "1000mb", // 원하는 크기로 조절하세요 (예: '50mb', '100mb') }, }, 강의 자료 수정이 필요할 것 같습니다.
안녕하세요 이벤트 핸들러 실습하는데 onMouseEnter 가 잘 실행이 안 돼서 문의드립니다. 버튼에 마우스를 대면 콘솔이 출력된다고 하셨는데 일단 코딩은 이렇게 했고 실행했습니다. 주로 크롬에서 하는데 크롬은 마우스를 대면 실행이 안 되고 버튼을 클릭하니까 콘솔이 2개씩 실행이 되고, 엣지에서는 정상적으로 실행을 합니다. 이 문제는 해결할 수 있는 방법이 있을까요?