Javascript 로 브라우저 환경에서 구동되는 게임 을 만들던 도중, redux 라이브러리 가 필요 한 순간이 생겼다. 패키지를 설치하자 다음과 같은 에러가 발생했다.
Failed to resolve module specifier "some module". Relative references must start with either "/", "./", or "../"
해결이 잘 되지 않아 stackoverflow 에 글을 게시했고, 답변자와의 대화를 통해 내가 javascript 와 Node.js 의 차이에 대한 이해가 아주 부족하다는 것을 느꼈다.

해당 모듈을 사용하려면,
1. Node.js 를 사용하거나,
2. Node.js 스타일의 module resolution 이 가능한 webpack 을 사용하라고 한 것이다.
그렇다면 첫째로, Node.js 를 사용 한다는 것이 뭘까? Node.js 는 javascript runtime 의 일종이다. 그렇다면 runtime 은 무엇인가? 이는 사용자가 입력한 코드가 컴파일되고 난 후, 프로그램이 실행(동작) 하는 때, 그리고 그때의 환경을 통틀어 뜻한다. 즉 “Node.js 를 사용한다” 라는 뜻은 해당 코드가 Node.js 환경 에서 실행되게끔 해라라고 해석할 수 있겠다.
node index.js
이러한 javascript runtime 하나 더 있는데, browser 이다. 즉 나의 코드는 두 개의 javascript 런타임 중 Node.js 가 아닌, browser 에서 실행되고 있었기 때문에, 해당 모듈을 사용할 수 없었던 것이다.
두번째의 Node.js 스타일의 module resolution 은 뭘까? 그 이전에, module resolution 은 뭘까?
module resolution 이란 “컴파일러가 import가 무엇을 참조하는지 알아내기 위해 사용하는 프로세스” 라고 한다. 그리고 참조하는 방식에는 두 가지 방식이 있다.
상대적 import :
/,./혹은../. 중에 하나로 시작한다. e.g.import Entry from "./components/Entry";
비-상대적 import : 그 의 모든 import는 비-상대적 으로 간주된다. e.g. import { createSlice } from "@reduxjs/toolkit";
내가 하려는 방식 은 비-상대적 import 임 을 확인 했다. 이렇게 참조 하는 방식 이 나누어져 있다면 참조하여 해석하는 전략인 module resolution 도 나누어져 있다.
/root/src/folder/A.js 안에서 moduleB 라는 모듈을 로드해 오기 위해 다음과 같이 썼다고 해보자.
import { b } from "./moduleB"
이는 다음과 같이 모듈을 찾게 될 것 이다.
/root/src/folder/moduleB.js
그러나, 비-상대적 module import에서는, 컴파일러가 가져온 파일을 갖고 있는 디렉터리부터 시작해서 디렉터리 트리를 거슬러 올라가 맞는 정의 파일의 위치를 찾으려고 한다.
예를 들어:
/root/src/folder/A.js안에서 moduleB 를 찾기 위해 다음과 같이 썼다고 해보자.
import { b } from "moduleB"
다음과 같이 거슬러 올라가는 역순으로 moduleB 를 찾게 된다.
/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts/root/src/moduleB.ts/root/src/moduleB.d.ts/root/moduleB.ts/root/moduleB.d.ts/moduleB.ts/moduleB.d.tsNode는 node_modules로 부터 모듈을 찾는다. Node는 디렉터리 체인을 올라가, 로드하려는 모듈을 찾을 때까지 각 node_modules을 찾는다. 거슬러 올라가는 점에서 클래식과 같지만 Node 는 node_modules/{원하는 모듈} 을 찾는 점에서 클래식과 다르다.
예를 들어, /root/src/moduleA.js 에서
var x = require("moduleB");
와 같은 비-상대적 import 로 모듈을 로드하려고 한다고 보자. Node 는 다음과 같이 moduleB 를 찾으려고 할 것이다.
/root/src/node_modules/moduleB.js/root/src/node_modules/moduleB/index.js/root/node_modules/moduleB.js/root/node_modules/moduleB/index.js/node_modules/moduleB.js/node_modules/moduleB/index.js중간 정리를 하자면, node js 스타일의 module resolution 은 정확히 말하면 module resolution 의 해석하는 전략중 하나인 Node 방식에서 비-상대적 import 를 처리하는 방식인 것이다. 이는 클래식과 달리 node_modules 로부터 모듈을 찾기 때문에, npm 을 통해 node_modules 에 설치되는 외부 모듈, 나의 경우 “@reduxjs/toolkit” 과 같은 모듈을 손쉽게 찾을 수 있었던 것이다.
그리고 이러한 비-상대적 import 를 도와주는 라이브러리가 webpack 이다. 그래서 비로소 나는 webpack 으로 내 게임을 번들링 하고, 그 과정에서 비-상대적 import 를 node 방식의 module resolution 으로 해결할 수 있었다.