ES Modules(ESM) 이란?

민갱·2023년 2월 2일
0

JS

목록 보기
1/2

기업 공모 자격란에 ESM, ESModule 이라는 단어를 종종 볼 수 있다.
준비해야지~?

ES Module이란 무엇인가

  • ES6에 도입된 모듈 시스템
  • import, export를 사용해 분리된 자바스크립트 파일끼리 서로 접근할 수 있다.

brower에서의 ESM

  1. 초기 자바스크립트는 독립적인 작업을 수행하며 큰 스크립트가 필요하지 않았다. jQuery가 생겨나고 어플리케이션의 규모가 커지면서 script파일을 나누기 시작했고, 파일간의 변수, 함수 등을 전달하고 받는 방법이 필요했다.

  2. ESM 이전에는 각각의 script 파일을 전역 스코프처럼 사용했다. HTML 파일에서 보다 위에 있는 script 파일은 전역 스코프처럼 하위의 script 태그에서 접근, 변경이 가능했다.

  3. 이 때문에 jQuery script를 최상단에 두고, 순서를 올바르게 구성하는게 중요했다.

    • 이 구조는 파일 순서가 뒤틀리면 에러가 발생하고,
    • 하위 script가 상위 script의 값을 쉽게 변경시키는 '전역 오염'이 발생하기 쉬우며,
    • 해당 script가 어떤 script에 의존성을 갖고 있는지 파악하기 힘들다.
    • 즉, 유지보수가 힘들다.
  • 실제로 사내에서 담당했던 프로젝트에서 위 같은 이유로 에러들이 발생하고 스크립트 파일 선언 위치가 중요했고,, 위 문제점을 모두 경험 했다..

해결책 - 모듈화

문제속에서 모듈화에 대한 필요성이 높아져 ES Module이 등장하게 되었다.
모듈은 함수와 변수를 모듈 스코프에 넣고, 각 함수는 함수 스코프를 가진다.
다만 export로 해당 변수, 함수를 "다른 모듈에서 import를 통해 의존할 수 있도록" 지정할 수 있다.

장점

  • import - export의 명시적 관계로, 하나의 모듈이 제거되면 어떤 모듈이 손상되었는지 알 수 있다.
    • 즉, 의존성 파악에 용이하다.(A가 import B를 하고 있을 때, B가 사라지거나 오류가 생기면 not found B 에러가 뜨는 등)
  • 코드들을 각각 독립적으로 작동할 수 있는 단위로 나누기 수월하다.
    • 이는 모듈을 재사용함으로써 다양한 종류의 어플리케이션을 만들 수도 있다.
  • import - export로 관계되지 않은 모듈간의 오염은 일어나지 않는다.

Node.js에서의 ESM

  • nodejs는 brower보다 빨리 모듈화를 위한 대책을 보유하고 있었다.
  • CommonJS ( require ), AMD, Webpack-Babel 등
  • 이중 CommonJS가 가장 널리 사용되었으며, ESM과의 차이는 아래 동작부분에서 설명하겠다.

어떻게 동작하는가

  • 브라우저에서 ES Module은 구성, 인스턴스화, 평가의 단계를 거쳐 동작한다.
  • 브라우저의 자바스크립트는 파일 자체를 사용할 수 없다. 때문에 모듈 레코드(Module Record)라고 하는 데이터 구조로 변환해야한다. 이 과정에서 해당 파일들의 모든 구문을 분석할 필요가 있다.
  • 파일을 불러오는 것은 로더(loader)가 하며, 이는 ES 모듈 명세가 아닌 HTML 명세를 따른다. script태그에 type="module"을 적어두어 entry 파일로 지정한다.

구성

  • (로더) entry 파일부터 import문을 찾아가며 필요한 모든 파일을 모듈 레코드로 구문 분석한다.
    • 모듈이 들어있는 파일을 어디서 다운로드 할 것인지 확인
    • 파일을 가져온다.(URL을 통해 or 파일 시스템에서)
    • 파일을 모듈 레코드로 구문 분석

인스턴스화

  • export된 값을 모두 배치하기 위한 메모리 공간을 찾는다.
  • export와 import들이 이런 메모리 공간을 가리키도록한다.
  • 이를 연결(linking)이라고 한다.
  • 이 과정은 메모리 공간을 찾고 지정할 뿐 실제 값을 채우진 않는다.

평가

  • 코드를 실행하여 메모리를 변수의 실제 값으로 채운다.

CommonJS와 차이점

CommonJS

  • 파일 시스템에서 파일을 로드한다.
  • 파일을 불러오는 동안 주 스레드를 차단한다.
  • 파일 로드 - 구문 분석 - 인스턴스화 - 평가가 각 파일마다 바로 실행되고, 모듈 지정자에 변수를 넣을 수 있다.
  • export 객체에 값을 복사해서 넣는다.

    common.js 사용법
    https://www.daleseo.com/js-module-require/

ES Module

  • entry 파일의 구문 분석 후 의존성(import)을 확인해서 해당 의존성 파일을 찾아서 다시 구문 분석을 반복한다.
  • 파일을 불러오는 동안 주 스레드를 차단하지 않는다.
  • 인스턴스화, 평가는 더 이상 구문 분석할 의존성이 발견되지 않으면 실행하고, 모듈 지정자에 변수를 넣을 수 없다(다만 동적 import를 쓰면 가능)
  • export는 참조를 반환하는 함수를 정의한다.
  • 동적 import는 별개의 entry 파일로 취급되어 새로운 그래프를 만든다.

+더하기

프로세스(process)란?
  • 프로세스(process)란 단순히 실행 중인 프로그램(program)이라고 할 수 있습니다.
  • 즉, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것을 말합니다.
  • 프로세스는 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 스레드로 구성됩니다.
스레드(thread)란?
  • 스레드(thread)란 프로세스(process) 내에서 실제로 작업을 수행하는 주체를 의미합니다.
  • 모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행합니다.
  • 또한, 두 개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스(multi-threaded process)라고 합니다.

이 차이는 어떤 결과를 부르는가?

  • export하는 파일에서 비동기 처리로 값이 바뀐다면, CommonsJS에서는 반영이 되지 않지만 ESM은 반영 될 수 있다(비동기로 다시 호출한다면).
  • 순환 참조의 경우 CommonJS는 빈 객체를, ESM은 RefernceError를 발생시킨다.
  • 자세한 설명은 여기에서 확인

예제

export

named export

  1. 내보내고자 하는 변수, 함수 앞에 export 붙이기
export const a = 1
export function fn(){}
export class Class{}
  1. 묶어서 내보내기
const a = 1
function fn(){}
class Class{}

export { a, fn, Class }

default export

  1. 내보내고자 하는 변수, 함수 앞에 export default 붙이기
// 변수값은 default로 선언, 내보내기가 동시에 되지 않는다
export default const a = 1 // xx

// fn.js
export default function fn(){}

// Class.js
export default class Class{}
  • default export는 모듈 당 하나만 가능하다.
  1. 선언 후 내보내기
//a.js
const a = 1
export default a

// fn.js
function fn(){}
export default fn

// Class.js
class Class{}
export default Class

import

named export를 import하는 경우

import {a} from 'a.js'
import {fn} from 'fn.js'
import {Class} from 'class.js'

defualt export를 import하는 경우

import a from 'a.js'
import fn from 'fn.js'
import Class from 'class.js'

//default의 경우 변수명은 원하는대로 바꿔도 된다.

import DD from 'class.js'

참조
https://velog.io/@jjunyjjuny/ES-Modules-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0

profile
가보자고

0개의 댓글