요즘 자바스크립트를 열심히 공부하고 있다.
자바스크립트로 코딩을 많이 해보지는 않아서 서툴고 익숙하지 않다…
자바스크립트 코드를 짜던 중 코드 라인 수가 몇백 줄이 넘어가면서 생산성이 급격하게 하락하기 시작했다.
하나의 파일에 모든 코드를 다 때려박으며 코딩하다 보니 생긴 일이다.
처음에는 귀찮아서 그냥 코딩을 진행했다. 그렇지만 개발을 계속 이어가면서, 스크롤 지옥과 구조를 알 수 없어지는 미궁 속에 빠진 나 자신을 발견한 뒤 파일을 분리하여 관리해야겠다는 생각을 하게 되었다.
다른 언어에도 있는 모듈, 라이브러리, 임포트 개념이 자바스크립트에도 있지 않을까 하여 찾아보았는데, 자바스크립트의 모듈이 그 역할을 하고 있어 이에 대해 공부하는 계기가 되었다.
하나의 파일을 여러 개로 분리할 때, 분리된 파일 각각을 '모듈(module)'이라고 부른다.
모듈은 대개 클래스 하나 혹은 특정한 목적을 가진 복수의 함수로 구성된 라이브러리 하나로 구성된다.
모듈은 다른 언어에서의 라이브러리와 개념이 유사하다고 보면 된다.
내가 생각하는 라이브러리를 사용하는 이유는
인데, 자바스크립트 모듈을 사용하는 이유도 이와 크게 다르지 않을 것이다.
자바스크립트는 처음에는 웹 환경 스크립팅을 위해 태어났기 때문에 모듈이 필요 없었으나, 최근 서버, 데스크톱 앱 등 다양한 분야의 컴퓨팅에 활용되며 규모가 커지고 복잡해지자 모듈의 필요성이 대두되었다고 한다.
자바스크립트 모듈 시스템은 다음과 같은 종류들이 있다.
이전에는 위와 같은 모듈 시스템들을 사용했으나, 모듈 시스템이 2015년에 표준으로 등재되며 ES6 Modules(ESM)이라는 선택지가 생기게 되었다.
이 글에서는 ES6 Modules에 대해 알아본다.
ESM에서는 import
, export
와 같은 키워드들을 통해 모듈의 import, export를 지원하지만, 키워드를 사용하기만 함으로써 모듈 시스템을 활용할 수 있는 것이 아니다.
아무런 다른 설정 없이 import, export만 하게 되면 다음과 같은 에러를 마주할 것이다.
“Uncaught SyntaxError: Cannot use import statement outside a module”
이 때는 모듈 처리 방식을 활용한다고 알려줘야 한다.
구체적인 오류의 해결 방법 두 가지는 아래와 같다.
<script type=”module”>
추가가장 최상단에서 실행되는 파일에 해당 에러가 발생하는 파일의 script
태그를 추가해준다.
예시는 다음과 같다.
<script type="module" src="src/main.js"></script>
“type”: “module”
추가// package.json
{
...
"type": "module",
...
}
package.json에 type
필드가 없으면 common.js 방식이 기본값으로 적용되어 모듈을 불러오려면 다른 방식을 사용해야 한다고 한다.
루트 디렉토리에 있는 package.json 파일에 위와 같이 필드를 추가해주면 된다.
import
: import
지시자를 사용하면 외부 모듈의 기능을 가져올 수 있다.export
: export
지시자를 변수나 함수 앞에 붙이면 외부 모듈에서 해당 변수나 함수에 접근할 수 있다.// foo.js
// 1. 변수 선언 즉시 내보내기
export let a;
export const b;
export var c;
export function d () { ...}
export class E {...}
// 2. 변수 먼저 정의하고, 모아서 내보내기
const aa;
let bb;
var cc;
export { aa, bb, cc }
// 3. 먼저 정의된 함수를 별칭으로 변경해서 내보내기
let cosine;
export { cosine as cos } // 다른 모듈에서 import 할 때에는 var5 로 import 해야 함
위와 같이 변수와 함수 등을 export하면, 아래와 같이 import하여 사용할 수 있다.
// main.js
import { a, b, c, d, E } from "./foo.js";
import { aa, bb, cc } from "./foo.js";
import { cos } from "./foo.js";
// foo.js
// 하나씩 내보내기
export default expression;
export default let a; // 불가
export default const a; // 불가
export default var a; // 불가
export default function () { ... } // 익명함수
export default function func () { ... } // 기명함수
export default class { ... }
export default class classclass { ... }
export default function* () { ... } // 제너레이터도 동일
// 묶어 내보내기
const myModule = { ... }
const f = () => {}
export { myModule as default, f } // as 를 이용해 default export
default export는 모듈 당 하나의 export만 가능하며,
아래와 같이 import하여 사용할 수 있다.
// main.js
import func from "./foo.js";
import classclass as alias from "./foo.js";
import "./foo.js";
import * as foo from "./foo.js";
// 등등
주의할 점은 named export된 경우 {}
밖에, default export된 경우 {}
안에 함수, 변수 등을 담아 import해야 한다는 점이다.
import func, { a, b } from './util';
default export는 보통 파일 내에서 한개만 export하거나, 대표로 export할 것이 있을 때 많이 쓴다고 한다.
반면 named default는 여러 개를 export할 때 사용한다고 한다.
자세한 것은 export default를 쓰지 말아야 할 이유를 참고해보자.
자바스크립트 ESM의 문법을 정리하였다.
아직은 자바스크립트 경험이 많이 없어 언제 named export와 default export를 사용하는 것이 적합한지 잘 기준이 서지 않는데, 앞으로 자바스크립트 공부를 해나가며 기준을 세워나가 봐야겠다.