Konva 사용해보기 (2편) (err : compiled against a different Node.js version using NODE_MODULE_VERSION )
1. 미니멀 코드 예제
1.1. html 로 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 첫번째로 스테이지 생성하기
var stage = new Konva.Stage({
container: "container", // id of container <div>
width: 500,
height: 500,
});
// 그다음에 layer 생성하기
var layer = new Konva.Layer();
// shape 만들어주기
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 70,
fill: "red",
stroke: "black",
strokeWidth: 4,
});
// shape 을 layer 에 추가하기
layer.add(circle);
// layer를 shape 에 추가하기
stage.add(layer);
// 이미지 그리기
layer.draw();
1.2. react 로 만들어보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// npm i react-konva konva --save
import { Stage, Layer, Text, Star, Group } from "react-konva";
import React from "react";
import Seo from "components/Seo";
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
function generateShapes() {
return [...Array(10)].map((_, i) => ({
id: i.toString(),
x: Math.random() * screenWidth,
y: Math.random() * screenHeight,
rotation: Math.random() * 180,
isDragging: false,
}));
}
const INITIAL_STATE = generateShapes();
const DrawKonva = () => {
const [stars, setStars] = React.useState(INITIAL_STATE);
const handleDragStart = (e: any) => {
const id = e.target.id();
setStars(
stars.map((star) => {
return {
...star,
isDragging: star.id === id,
};
})
);
};
const handleDragEnd = (e: any) => {
setStars(
stars.map((star) => {
return {
...star,
isDragging: false,
};
})
);
};
return (
<div>
<Seo title="Konva" />
<h1>Konva</h1>
<Stage width={screenWidth} height={screenHeight} visible={true}>
<Layer>
<Text text="Try to drag a star" />
{stars.map((star) => (
<>
<Group>
<Text
key={star.id + 10}
x={star.x}
y={star.y}
text={`x: ${star.x}, y: ${star.y} `}
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
/>
<Star
key={star.id}
id={star.id}
x={star.x}
y={star.y}
numPoints={5}
innerRadius={20}
outerRadius={40}
fill="#b7172a"
opacity={0.8}
draggable
rotation={star.rotation}
shadowColor="black"
shadowBlur={10}
shadowOpacity={0.6}
shadowOffsetX={star.isDragging ? 10 : 5}
shadowOffsetY={star.isDragging ? 10 : 5}
scaleX={star.isDragging ? 1.2 : 1}
scaleY={star.isDragging ? 1.2 : 1}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
/>
</Group>
</>
))}
</Layer>
</Stage>
</div>
);
};
export default DrawKonva;
2. 문제점 Err 발생!
첫 렌더링 시에는 문제가 없었다. 문제는 페이지를 새로고침 했을 때 이다.
다음과 같은 에러문구가 나왔다.
1
2
3
4
Error: The module '/Users/feel/node_modules/canvas/build/Release/canvas.node' was compiled against a
different Node.js version using NODE_MODULE_VERSION 102(108). This version of Node.js requires
NODE_MODULE_VERSION 93(102). Please try re-compiling or re-installing the module (for instance, using `npm
rebuild` or `npm install`).
대충 요약하자면 다음과 같다.
- 지금 버전의 Node.js는 Node_MODULE_VERSION 93 을 필요로 한다.
- re-compiling 이나 re-installing the module을 시도해봐라.
라는 안내가 나왔다.
근데 디렉토리를 보니 이상하다. 나는 canvas 를 받은적이 없는데 canvas 디렉토리에서 컴파일 하는데 에러가 났다. npm i canvas
를 했으나, 설치가 되지 않고 에러가 또 발생했다… err code 1 이 나면서, 설치가 되지 않았다.
다음은 내가 시도해봤던 것들이다.
2.1. 내가 시도해 본 것들
2.1.1 모듈 새로 설치하기
- 기존 node_modules 파일 삭제
- package-lock.json 파일 삭제
npm install
을 통해서 package.json 에 있는 모듈을 모두 새로받기
하지만 위의 방법으로도 동일한 문제가 발생했다.
2.1.2 노드버전 변경해보기
nvm ls
명령어로 node 의 default 버전이나 , 현재 사용중인 버전 확인이 가능하다.- 당시 node 의 lts 버전으로는 18.12.1 이었다.
- NODE_MODULE_VERSION 102 는 lts/gallium 이라서 다운그레이드 해 보았다.
nvm alias default 16.19.0(lts/gallium)
으로 default node 를 변경하였다.nvm use 18.12.1
로 변경 후 ,- 혹시 모르게 이전버전이 사용될까봐 이전버전은 삭제했다.
nvm uninstall 16.19.0
- 변경하였더니 위 에러문구에서 NODE_MODULE_VERSION 의 숫자가 다르게 나왔다. requires 102 에서 requires 93 으로 되어버렸다. 즉, 문제가 해결되지 않았다.
2.1.3 npmjs 공식 홈페이지 찾아보기 (해결됨!!!!!!!!)
- 공식 홈페이지에서 다음과 같은 방법을 찾았다.
Mac OS X v10.11+: If you have recently updated to Mac OS X v10.11+ and are experiencing trouble when compiling, run the following command:
xcode-select --install
. Read more about the problem on Stack Overflow. If you have xcode 10.0 or higher installed, in order to build from source you need NPM 6.4.1 or higher. - 요약하자면, 10.11 + 버전에서 compilling 과정중에 문제가 생긴다면,
xcode-select --install
을 해보라는 것이었다. - 다운받는데 15-20분 정도가 소요된것 같다.
- 와 ,,, 드디어
npm i canvas
가 정상적으로 작동하였다…!!!
xcode-select 가 무엇을 도와줬는지 찾아보았다. 다음은 Stack Overflow 에서 찾은 결과다.
You should install the Xcode Command Line tools with
xcode-select --install
to get a version of clang that searches /usr/local by default. Otherwise, you’re using the versions provided by Xcode proper, which only search the OS X SDK paths. (/usr/bin/gcc and /usr/bin/g++ both invoke clang and are not actually versions of gcc.)
번역해보면 다음과 같다.
기본적으로 /usr/local을 검색하는 clang 버전을 가져오려면 Xcode 명령줄 도구를 설치해야 합니다 . 그렇지 않으면 OS X SDK 경로만 검색하는 Xcode에서 제공하는 버전을 사용하고 있는 것입니다. (/usr/bin/gcc 및 /usr/bin/g++ 모두 clang을 호출하며 실제로는 gcc 버전이 아닙니다.)
즉, 디렉토리를 검색하는 xcode-select 가 맥 10.11+ 버전에서 없어져서 그런것이다.
2.2. 새로운 문제 발생( require(), dynamic import() )
1
require() of ES Module ... ...to a dynamic import() which is available in all CommonJS modules.
즉 es module 이 require() 을 쓰고있어서 안된다고 한다. 모든 CommonJS modules 에서 쓸수 있는 다이나믹 import() 를 쓰라고 하고 있다.
require / exports 와 import / export
commonjs => require / exports es6 module => import( import * as name from ‘name’)/ export / export default
특정 파일이나 모듈을 불러오거나 내보내기 할 떄 사용할 수 있는 것은 require / exports
또는import / export
이다. import / export 는 es6에서 발생한것 -> package.json 파일에서 "type: "module"
을 설정해 줌으로써 사용할 수 있다. (참고로 require / exports 는 "type": "commonjs"
임)
es6 모듈로 설정된 환경에서 commonjs 문법을 사용하거나, 반대로 commonjs로 설정된 환경에서 es6문법을 사용하는 경우 에러가 나게 된다.
아래의 사진은 commonjs 환경에서 import 를 사용하려해서 발생한 에러.
아래의 사진은 es6 module 환경에서 require를 사용하려 해서 발생한 에러.
하지만 어떠한 모듈은 import 를 통해서만 가져오거나 require 를 통해 가져오는 것만 허용되는 경우가 있다. 또는 함수내에서와 같은 경우는 require를 통해서만 모듈을 가져올 수 있고, import 는 함수 안에서 사용될 수 없다. 이런 경우 import 와 require 모두를 한 프로젝트 내에서 사용해야하만 한다.
** 함수 내에서 import 를 사용하려 하면 에러가 발생.
** 반면에 require는 함수 내에서 사용시에도 에러가 나지 않음.
다음은 해결하기 위해 내가 해보았던 방법들이다.
2.2.1. Package.json 파일에 있는 노드 패키지 버전들을 업그레이드 해주기 (해결안됨)
1
2
3
npm install upgrade
npm audit fix --force
위의 두개의 명령어로 업그레이드 하였지만 동일한 문제가 발생하였다. 해결되지 않음.
2.2.2. node-fetch 삭제후 v2 로 재다운로드 (해결안됨)
npm uninstall node-fetch
npm install node-fetch@2
CommonJS node-fetch from v3 is an ESM-only module - you are not able to import it with require().
If you cannot switch to ESM, please use v2 which remains compatible with CommonJS. Critical bug fixes will continue to be published for v2. (출처 - https://www.npmjs.com/package/node-fetch)
2.2.3. commonjs 와 es6 module 환경에서 둘다(require, import) 사용하는 법(해결안됨…)
1
2
3
4
5
6
7
// package.json
{
...
"type" : "module",
...
}
require 가 필요한 부분에서 아래와 같이 사용하면된다.
1
2
3
4
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const react_1 = __importDefault(require("react"));
2.2.4. dynamic import(해결됨… 미친 2틀동안 방법 찾아가면서했는데 next로 검색을 안했다)
일단 konva 공식 깃헙 Issues에 동일한 상황이 있었다… konva 깃헙 Issues
Next공식 깃헙 dynamic import example
nextjs 공식 홈페이지 dynamic import 사용법
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// pages/drawcenter.tsx
import dynamic from "next/dynamic";
const DrawCenter = () => {
const DynamicDrawKonva = dynamic(() => import("../components/DrawKonva"), {
ssr: false,
});
return (
<>
<DynamicDrawKonva />
</>
);
};
export default DrawCenter;
drawcenter 페이지에서는 konva를 이용해 작업한 DrawKonva 컴포넌트를 불러온다.
- dynammic import 를 이용해서 컴포넌트를 불러온다.
- 서버사이드렌더링을 false 로 한다.
- 불러온 컴포넌트를 DynamicDrawKonva 에 할당하고, 해당컴포넌트를 return 해준다.
이후로는 drawcenter 페이지를 리로드하여도 에러가 발생하지 않고 정상적으로 동작하였다…
느낀점
이번 문제가 발생하고 나서 검색키워드가 잘못되었다는 걸 알았다. 역시 next 는 프레임 워크라 그런지, 일반적인 react 패키지 라이브러리 사용법이 따로있다는 것을 알게 되었다. 앞으로는 next 기준으로 검색해 봐야 겠다…… 너무 삽질해서 힘이 빠진다.