Cannot find module 'msw/node' 에러 해결

 

NEXT.js 14버전 환경에서 jest를 사용한 테스트 환경 구축중에 

api요청등의 문제를 모킹서버로 해결하기 위해 

msw설치후 테스트를 돌렸는데 

 

msw/node 를 찾지 못한다는 에러가 발생을 하였다.

분명 패키지제이슨엔 설치가 되어 있는데도 오류가 발생하고 있어 

chatGpt에 물어봐도 다시 설치하라는 말만 하고 있어 다른 방법을 찾아 보던중

 

https://github.com/mswjs/msw/issues/1786

 

"Cannot find module 'msw/node'" in Jest JSDOM environment · Issue #1786 · mswjs/msw

Prerequisites I confirm my issue is not in the opened issues I confirm the Frequently Asked Questions didn't contain the answer to my issue Environment check I'm using the latest msw version I'm us...

github.com

이곳의 글을 확인 하였고 코멘트에서 해결방법을 찾았다.

 

jest.config.ts 파일의 설정중에 

testEnvironmentOptions: {
    customExportConditions: [""],
  },

이부분을 추가 하면 된다. 

에러가 난 이유를 설명한걸 해석해 보자면

 

JSDOM이 내보내기 조건을 강제하기 때문입니다 browser.

즉, JSDOM은 "타사 패키지가 browser필드를 내보내는 경우 해당 필드를 사용하십시오"라고 말합니다.

그것이 기본값이고 다소 위험한 기본값입니다. 왜? JSDOM은 여전히 ​​Node.js에서 실행되기 때문입니다 .

게다가 JSDOM은 설계상 100% 브라우저 호환성을 가질 수 없으므로 browser내보내기 조건을 강제하면

MSW와 같이 다양한 환경에 대해 다양한 코드를 제공하는 패키지로 작업할 때 테스트가 필요 이상으로 실패하게 됩니다.

이렇게(위와 같은 설정을) 하면 JSDOM이 올바른 동작인 node(또는 ) 내보내기 조건을 사용하게 됩니다 .default

이번 변경 이후 다른 수입 관련 문제가 발생하는 경우 관련이 없으므로 별도로 처리해야 합니다.

모든 사람이 따를 수 있도록 이 권장 사항을 마이그레이션 가이드에도 추가합니다.

 

라고 한다. 

간단하게 뭐 해볼거 없을까 찾다가

js로 만들었던 영웅뽑기 시뮬레이터를 react 버전으로 만들어 보았습니다.

블로그에서 실행되나 테스트 용입니다.

아직 테스트하고 예전에 했던 감찾기 용으로 가볍게 한거라 기존 시뮬레이터의 모든 기능이

들어가 있진 않습니다.

 

jsbin.com/goxetubuyo/edit?html,js,output

 

JS Bin

Sample of the bin:

jsbin.com

 

 

jsbin으로 만들었습니다.

 

[React.js] cannot resolve 'react-transition-group' 오류 해결 방법



애니메이션 효과같은것들 적용 하려고 했던 react-transition-group이 서버 구동중 에러가 난다.


cannot resolve 'react-transition-group' 라는 에러메세지가 뜨길래


분명히 해당 패키지도 받았고 제대로 추가 시켰는데 왜 못찾는거지?


하고 검색을 해 보았다.


NPM에 올라온 글을 확인해 보니


This package is deprecated and will no longer work with React 16+. We recommend you use CSSTransitionGroup from react-transition-group instead.

In particular, its version 1.1.1 is a drop-in replacement for the last released version of react-addons-css-transition-group.

Run npm install --save react-transition-group@1.1.1, and replace the imports in your code


1
2
3
4
5
// Old 
import CSSTransitionGroup from 'react-addons-css-transition-group';
 
// New 
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
cs



라고 올라와 있었다


내용인 즉슨


리액트 16 이상 버전 부터는 기존에 사용하던걸 지원하지 않고 아얘 동작도 되지 않게 되었으니


새로운 다른걸 써라~


라고 하는 것이다.


쟤네가 설치하라는거 설치 하고 임포트 문장도 아랫것 처럼 바꾸면


오류는 해결이 된다.

react-router v4  browserHistory.push 오류 해결 방법


리엑트 라우터가 버전3에서 버전4로 올라감에 따라 


엄청나게 많은 것들이 변했다.


지금 새로운 프로젝트를 만들고 새로운 버전의


패키지들을 받은 후 코딩을 하려면 불과 한달전에 공부했던 코드들이 동작하지 않게 되었다.



망할.. 예전 webpack 버전1에서 2버전으로 올라가면서 바뀐거 찾아내느라 생고생 했는데



이젠 react-router가 문제다




Link를 사용하지 않고 바로 함수 내에서 리다이렉트를 시키는 방법으로


v3에서는 



1
browserHistory.push('/');
cs


이렇게 사용 하였으나


v4에선


Uncaught (in promise) ReferenceError: browserHistory is not defined


브라우저 콘솔창에 위와 같은 에러 메세지가 나타난다.


해결방법


생각보다 간단했다. 위의 코드 대신에


1
this.props.history.push('/');
cs



이렇게 사용해주면 된다.


물론 상단에 리엑트 라우터를 임포트시킬 필요는 없다.


그냥 기능이 넘어와 버린건지 정확하게는 알 수 없지만


깃터브를 뒤져보니 아래와 같은 의견을 찾았다.


걍 이전버전에서는 됐는데 v4에선 안된다 라는 말 같다.





@wyze @timdorr first of all thanks for the v4. I have a few questions and I could not find any solutions for this anywhere, so asking here.

In the earlier versions of the react-router, we could push the the URL using browserHistroy.push() method. When you use browserHistroy the query which you pass, will be transformed to the search key in the history object. The below is an example which used to work in earlier versions.

let query = {
  reportType: 'summary',
  timeZone: 'UTC'
}
  browserHistroy.push({
    pathname: 'some_path',
    query
  })

This will resolve the URL to - test.com/some_path/?reportType=summary&timeZone=UTC

In the current version (v4), it is not possible to pass the query object to the history.push() method.

  histroy.push({
    pathname: 'some_path',
    query
  })

This will resolve the URL to - test.com/some_path/

How to get this working with v4.

함수형 컴포넌트 만들기


react에서 컴포넌트를 정의할때 class 문법을 사용하는데 


라이프사이클API를 사용하거나 state를 사용하는 경우에는 class 문법을 사용해 컴포넌트를 만들어야 한다.


일반적으로 지금까지 만들어왔던


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//파일 및 컴포넌트의 첫 문자를 대문자로 하는건 React의 naming convention 입니다.
import React from 'react'//import JavaScript ES6 에 새로 도입된 키워드로서, require('..') 의 역할을 합니다.
/*
* 컴포넌트에서 immutable (변하지 않는)  데이터가 필요 할 땐,
* render() 메소드의 내부에 안에 { this.props.propsName } 형식으로 넣고,
* 컴포넌트를 사용 할 때, < > 괄호 안에 propsName="value" 를 넣어 값을 설정합니다.
*
* */
class Header extends React.Component {
    render(){
        return (
            <h1>this.props.title }</h1>
        );
    }
}
export default Header; //export는 JavaScript ES6 에 새로 도입된 키워드로서, module.export = Header 와 같습니다.
cs



이런식이다.


주석이 많아 좀 보기 힘들지만.. 주석을 지우면


1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react'
 
class Header extends React.Component {
 
    render(){
        return (
            <h1>this.props.title }</h1>
        );
    }
 
}
 
export default Header; 
cs


이런식이 되겠다.



그런데 라이프사이클API도 사용하지 않고 state도 사용하지 않고


단순히 props만 전달해 뷰를 렌더링해주는 역할만 한다면 


함수형 컴포넌트 형식으로 컴포넌트를 정의 할 수 있다.




1
2
3
4
5
6
7
8
9
10
import React from 'react'
 
    function Header(){
        return (
            <h1>{props.title }</h1>
        );
    }
 
 
export default Header; 
cs



이런식으로 말이다.


뭔가 아까보다 단순해지지 않았는가?



여기서 ES6의 애로우펑션(화살표 함수)를 사용하여 만들 수도 있다.



1
2
3
4
5
6
7
8
9
10
import React from 'react'
 
    const Header = (props) => {
        return (
            <h1>{ props.title }</h1>
        );
    }
 
 
export default Header; 
cs




이 코드를 비구조화 할당 문법을 사용한다면




1
2
3
4
5
6
7
8
9
10
import React from 'react'
 
    const Header = ({title}) => {
        return (
            <h1>{ title }</h1>
        );
    }
 
 
export default Header; 
cs


이렇게 만드는게 가능 하다.



class문법을 사용하는 것 보다 훨씬 간단해 졌다.


그러나 함수형 컴포넌트에 따로 성능최적화가 이뤄진 것이 아니기 떄문에 


성능에선 클래스형 컴포넌트와 다르지 않다.


리액트 팀에서 함수형 컴포넌트의 성능을 최적화하겠다고 했지만 


일부 상황에서 제대로 동작하지 않는 오류가 있다고 하는데


레딧에서 본 정보이니 자세한 내용은 아니다.


리액트 컴포넌트 라이프 사이클 API



이 포스팅은


VELOPERT 님의 포스팅을 아주많이 참조하였습니다;;


(출처 : https://velopert.com/1130 )





1. 컴포넌트 라이프 사이클 API 순서


컴포넌트를 생성 할 때는 


constructor -> componentWillMount -> render -> componentDidMount 


순으로 진행됩니다.


컴포넌트를 제거 할 때는 componentWillUnmount 메소드만 실행됩니다.


컴포넌트의 prop이 변경될 때엔 


componentWillReceiveProps -> shouldComponentUpdate -> 

componentWillUpdate-> render -> componentDidUpdate 


순으로 진행됩니다.


 state가 변경될 떄엔 props 를 받았을 때 와 비슷하지만 shouldComponentUpdate 부터 시작됩니다.


그림으론 아래와 같이 보시면 됩니다.





2. 각 메소드들이 하는 역할


1) constructor

3
4
constructor(props){
    super(props);
    console.log("constructor");
}

1
2
3
4
5
6
7
8
9
10
11
12
13
  constructor(props) {
        console.log("컨텍트 생성자 시작");
        super(props);
        this.state = {
            contactData: [
                {name: "Abet", phone: "010-0000-00035"},
                {name: "Betty", phone: "010-0000-0002"},
                {name: "Charlie", phone: "010-0000-0003"},
                {name: "David", phone: "010-0000-0004"}
            ]
        };
        console.log("컨텍트 생성자 끝");
    }
cs


-> 생성자 메소드 입니다. 컴포넌트가 처음 만들어질때 실행되며 이곳에서 기본 state를 정할 수 있습니다.




2) componentWillMount

componentWillMount(){
    console.log("componentWillMount");
}


-> 컴포넌트가 DOM 위에 만들어지기 전에 실행 됩니다.





3) render

1
2
3
4
5
6
7
render() {
        return (
            <button onClick={this.handleClick.bind(this)}>
                Remove selected contact
            </button>
        );
    }
cs

-> 컴포넌트 렌더링을 담당합니다.



4) componentDidMount

componentDidMount(){
    console.log("componentDidMount");
}


-> 컴포넌트가 만들어지고 첫 렌더링을 다 마친 후 실행되는 메소드 입니다.

이 안에서 다른 JS 프레임워크를 연동하거나. setTomeout, setInterval및 Ajax 처리를 넣습니다.

--> https://medium.com/@taeho.leon.kim/javascript-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EB%93%A4%EC%97%90-%EB%8C%80%ED%95%9C-%EC%9D%B4%EC%95%BC%EA%B8%B0-8fc74fab2140#.8nmyw5gjt

이곳에서는 해당 API가 렌더링을 시잓하는 즉시 실행한다고 이야기 한다. 즉 렌더링이 끝날때까지 기다려주지 않는다고 말이다.

아직 정확히 확인을 해보지 못하였다. 





5) componentWillReceiveProps

componentWillReceiveProps(nextProps){
    console.log("componentWillReceiveProps: " + JSON.stringify(nextProps));
}


-> 컴포넌트가 prop을 새로 받았을 때 실행 됩니다. porp에 따라 state를 업데이트 해야 할 떄 사용 하면 유용 합니다.

     이 안에서 this.setState()를 해도 추가적으로 렌더링 하지 않습니다.




6) shouldComponentUpdate

2
3
4
shouldComponentUpdate(nextProps, nextState){
    console.log("shouldComponentUpdate: " + JSON.stringify(nextProps) + " " + JSON.stringify(nextState));
    return true;
}


-> 이전 포스팅에서 사용했던 메소드. prop나 state가 변경 되었을때 리렌더링을 할지 말지 정하는 메소드.

    실제로 활용 할때는 필요하는 값을 비교해서 반환하도록 사용 한다. (이전 포스팅 참조)

2017/02/27 - [Yame Programmer/react.js] - [react.js] 변경된 값만 렌더링 되도록 하기 shouldComponentUpdate()


7) componentWillUpdate

componentWillUpdate(nextProps, nextState){
    console.log("componentWillUpdate: " + JSON.stringify(nextProps) + " " + JSON.stringify(nextState));
}


-> 컴포넌트가 업데이트 되기 전에 실행된다. 이 메소드 안에서는 this.setState()를 사용하면 안된다. 무한루프에 빠져들어 버린다.



8) componentDidUpdate

2
3
componentDidUpdate(prevProps, prevState){
    console.log("componentDidUpdate: " + JSON.stringify(prevProps) + " " + JSON.stringify(prevState));
}


-> 컴포넌트가 리렌더링을 마친 후 실행된다




9) componentWillUnmount

componentWillUnmount(){
    console.log("componentWillUnmount");
}



-> 컴포넌트가 dom 에서 사라진 후 실행되는 메소드















변경된 값만 렌더링 되도록 하기 shouldComponentUpdate()


react 강좌를 보며 예제를 따라해보고 하던 도중


라이프사이클이나 실행유무 어떤 메소드가 먼저 실행되는지


여기에 있는 this와 저기에 있는 this 가 무슨 차이가 있는지


알아보기 위해 여기저기 온갖곳에 console.log를 사용하여


개발자모드 화면에서 콘솔들을 보는 도중


특정값이 바뀌는데도 맵안에 들어가 있는 녀석들을 전부 하나씩


다시 렌더링 한다는걸 알게 되었다


역시나 그에 대한 해답도 강좌에 마지막 부분에 써있었는데


기록해놔야 겠다 싶어서 포스팅을 한다



1
2
3
4
// 컴포넌트를 다시 렌더링 해야 할 지 말지 정의해준다
    shouldComponentUpdate(nextProps, nextState){
        return (JSON.stringify(nextProps) != JSON.stringify(this.props));
    }
cs




shouldComponentUpdate


요 함수가 다시 렌더링을 할지 말지 정의를 해주는데 리턴값을 보면


다음 props와 현재 props를 비교 해서 렌더링 할지 말지 정해주는 것 같다.


리턴이 true false로 가니 좀 더 다른 방법으로도 응용이 가능 할 것 같다.


ES6에는 생소한 문법들도 많고 평소 사용하던 방식과 너무나도 많이 달라 


react를 공부하는데 어려움이 엄청나게 많다. 


심지어 나는 bind나 this를 자주 사용하지 않았기 때문에 더 심한것 일수도...


현재 공부중인 리액트 예제들은


https://github.com/cheesu/react-tu


이곳에 올려놨으니 받아서 보는 것도 좋을 것이다.


왜냐하면 주석을 여기저기 엄청나게 달아놓고 console.log도 엄청나게 달아놨기 때문에 


혹여나 관심있는 사람들은 받아보면 도움이 될 것 같다.



react.js 에서 Jquery 사용 하는 방법(unused import $ from jquery )



nodejs사용 babel, webpack 사용하는 사람들에게 적용 가능 한 방법입니다.


다른건 모르겠네요 어차피 여긴 야매 가이드니까 신경 ㄴㄴ



이제 튜토리얼 하고 있는데 세상에 바닐라JS는 나에겐 너무 높은 벽이었고


3년전 처음 배울때나 바닐라 JS 사용했지 실무투입하고 난 이후부턴


제이쿼리만 주구장창 썻는데 getelementById 라니 이건 나에게 너무나 가혹한것 같아


제이쿼리를 어떻게 쓸수 있을까 하고 또 구글링을 시작 했습니다.


역시 인터넷엔 없는게 없었고


1
import $ from "jquery";
cs


이렇게 js에 추가해 주면 사용 할수 있다고 스택오버플로우 형들이 알려주길래


그대로 적용 시켰더니



왜 죽은 동태눈알 색깔을 하고 있는걸까..


unused import $ from jquery 라는 메세지와


메세지창을 확장시키면


checks that javascript or typescript import binding ... 어쩌구 저쩌구


라고 나오면 실행되지 않는다.


아!


npm에서 제이쿼리를 다운받지 않아서 그런건가? 


그렇지 제이쿼리가 없으면 못쓰는거겟지 라는 생각으로


npm install jquery --save


명령어를 입력후 제이쿼리를 설치 했으나


역시 죽은동태눈깔은 돌아오지 않았다.



조금더 구글링을 해보니


1
2
import jQuery from "jquery";
window.$ = window.jQuery = jQuery;
cs


이렇게 하면 된다고 한다


오오 신기하다 된다된다


이제 리액트에서 제이쿼리를 사용할수 있겟구나 하고


테스트해보니 


제이쿼리 정상작동 하는 것을 확인 할 수 있었다.




module not found error cannot resolve 'babel' in 에러와 the node api for babel has been moved to babel-core  해결 방법




드디어 리액트에 입문!


아직 뭐가 뭔지도 잘 모르고


바벨이라는 녀석이 ES6문법으로 바꿔주고 웹팩이라는 녀석이 번들js로 


관리해준다는 대략적인 정보만 알고 난 상태에서


https://velopert.com/814


이분의 강좌를 보면서 공부를 하기로 시작 했는데 시작과 동시에 에러가 날 반겨준다.




1. the node api for babel has been moved to babel-core  해결 방법




<으아악 불길한 붉은 텍스트라니>



the node api for babel has been moved to babel-core


이 에러는 뭐 대충 설치 할때 경로 문제나 디펜던시 설정 문제 인듯 하다


pakage.json 파일의 디펜던시를 아래와 같이 바꿔주면 해결이 된다.


아마 위의 에러가 나는 것은 딘펜던시와 덴펜던시스 둘다 바벨이 들어가 있는 경우이며


글로벌로 babel과 webpack를 설치 한 후


또 종속성으로 --save 명령어로 설치하는 경우에 나타나는 에러 인듯 하다.



1
2
3
4
5
6
7
8
9
10
11
12
 "dependencies": {
    "react": "^15.4.2",
    "react-dom": "^15.4.2"
  },
  "devDependencies": {
    "babel-core": "^6.23.1",
    "babel-loader": "^6.3.2",
    "babel-preset-es2015": "^6.22.0",
    "babel-preset-react": "^6.23.0",
    "webpack": "^2.2.1",
    "webpack-dev-server": "^2.4.1"
  }
cs


디펜던시 목록을 위와같이 수정해주면 사라지며


그래도 계속 나타날 경우엔 어차피 튜토리얼 단계니까 


폴더 지우고 다시 순서대로 받아주면 해결 된다.




2.module not found error cannot resolve 'babel' in 에러 해결 방법





이 에러는 webpack.config.js 파일을 수정해 주어야 한다.


이 파일은 webpack의 설정파일인데


ECMAScript6를 컴파일 해주고 개발서버를 열어주는 webpack의 설정 파일인데


모듈 로더 부분이


1
2
3
4
5
6
7
8
9
10
11
12
13
    module: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel',
                exclude: /node_modules/,
                query: {
                    cacheDirectory: true,
                    presets: ['es2015''react']
                }
            }
        ]
    }
cs



이런식으로 loader:'babel'

로 되어있는 경우 발생한다


바벨을 참조하지 못해서 생기는 오류인듯 한


loader:'babel' -> loader:'babel-loader' 이렇게 바꿔주면 간단히 해결이 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
   module: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                    cacheDirectory: true,
                    presets: ['es2015''react']
                }
            }
        ]
    }
cs



이제 npm start 명령어를 실행하면 complied successfully 라는 반가운 문구를 볼 수가 있게 된다.



+ Recent posts