모듈

지니씨·2023년 3월 3일
0

프론트엔드

목록 보기
65/86

모듈

https://ko.javascript.info/modules-intro
모듈은 대개 클래스 하나 혹은 특정한 목적을 가진 복수의 함수로 구성된 라이브러리 하나로 구성된다.
모듈은 단지 파일 하나에 불과하며 스크립트 하나는 모듈 하나이다.

모듈 시스템 종류

  • AMD
    가장 오래된 모듈 시스템 중 하나로 require.js라는 라이브러리를 통해 처음 개발 됨
  • CommonJS
    Node.js 서버를 위해 만들어진 모듈 시스템
  • UMD
    AMD와 CommonJS와 같은 다양한 모듈 시스템을 함께 사용하기 위해 만들어짐

위와 같은 모듈 시스템은 오래된 스크립트에서 여전히 존재하지만 사라지는 추세
모듈 시스템은 2015년 표준에 등재되어 이제는 대부분의 주요 브라우저와 Node.js가 모듈 시스템을 지원함

모듈은 특수한 키워드나 기능과 함께 사용되므로 <script type="module"> 와 같이 속성을 설정해 해당 스크립트가 모듈이라는걸 브라우저에게 알려줘야 한다.

모듈의 핵심 기능

일반 스크립트와 모듈의 차이? (모든 호스트 환경에 공통으로 적용되는 모듈의 핵심 기능)

  • 엄격 모드로 실행됨
  • 모듈 레벨 스코프
    : 외부에 공개하려는 모듈은 export 해야 하고 exportt된 모듈을 가져와 사용하려면 import 해줘야 함
    : 브라우저 환경에서 부득이하게 window 레벨 전영 변수를 만들어야 한다면 window 객체에 변수를 명시적으로 할당하고 window.[name]으로 접근하면 되지만 이 방법은 정말 필요한 경우에만 사용하길 권장.
  • import.meta
    현재 모듈에 대한 정보 제공
    호스트 환경에 따라 제공하는 정보의 내용이 다름
    브라우저 환경에서는 스크립트의 URL 정보, HTML 안에 있는 모듈이라면 현재 실행중인 웹페이지의 URL 정보 제공
  • this는 undefined
<script>
  alert(this); // window
</script>

<script type="module">
  alert(this); // undefined
</script>
  • nomodule
<script type="module">
  alert("모던 브라우저를 사용하고 계시군요.");
</script>

<script nomodule>
  alert("type=module을 해석할 수 있는 브라우저는 nomodule 타입의 스크립트는 넘어갑니다. 따라서 이 alert 문은 실행되지 않습니다.")
  alert("오래된 브라우저를 사용하고 있다면 type=module이 붙은 스크립트는 무시됩니다. 대신 이 alert 문이 실행됩니다.");
</script>

빌드툴

브라우저 환경에서 모듈을 단독으로 사용하는 경우는 흔치 않다. 대개 웹팩과 같은 빌드 툴을 사용해 모듈을 번들링하여 프로덕션 서버에 올리는 방식을 사용한다.

빌드 툴의 역할

  • HTML 의 <script type="module">에 넣을 주요 모듈(진입점 역할을 하는 모듈) 선택
  • 주요 모듈에 의존하고 있는 모듈 분석을 시작으로 모듈 간의 의존 관계 파악
  • 모듈 전체를 한데 모아 하나의 큰 파일을 만듬(설정에 따라 다수 파일 생성도 가능).
    import, export문은 특별한 번들러 함수로 대체됩니다. 번들링 과정이 끝나면 기존 스크립트에서 import, export가 사라지기 때문에 type="module"이 필요 없어집니다. 따라서 아래와 같이 번들링 과정을 거친 스크립트는 일반 스크립트처럼 취급할 수 있습니다.
  • 이런 과정 중 변형이나 최적화도 함께 수행 됨
    : 도달 가능하지 않은 코드 삭제
    : 내보내진 모듈 중 사용하지 않는 모듈은 삭제(가지치기(tree-shaking))
    : console, debugger 같은 개발 관련 코드 삭제
    : 공백 제거, 변수 이름 줄이기 등으로 산출물 크기 줄임
    : 여러 로더 적용
  • 번들링 과정의 결과물은 일반 스크립트

export, import

export

변수, 함수, 클래스 선언 시 맨 앞에 export 붙이면 내보내기 가능
마지막줄에 export { name1, name2 };로도 내보내기 가능

클래스나 함수를 내보낼 땐 세미콜론을 붙이지 마세요.
클래스나 함수 선언 시, 선언부 앞에 export를 붙인다고 해서 함수 선언 방식이 함수 선언문에서 함수 표현식(function expression) 으로 바뀌지 않습니다. 내보내 지긴 했지만 여전히 함수 선언문입니다.
대부분의 자바스크립트 스타일 가이드는 함수나 클래스 선언 끝에 세미콜론을 붙이지 말라고 권유합니다.
같은 이유로 export class나 export function 끝에 세미콜론을 붙이지 않습니다.

as

as를 사용해 이름을 바꿔서 모듈을 내보낼 수 있음 가져올 수 있음
export {sayHi as hi, sayBye as bye};

default

이렇게 default를 붙여서 모듈을 내보내면 중괄호 {} 없이 모듈을 가져올 수 있습니다.
import User from './user.js';

export default를 사용하면 '해당 모듈엔 개체가 하나만 있다’는 사실을 명확히 나타낼 수 있습니다. (default export가 아닌 경우엔 이름이 없어도 정상 동작하지만 그렇지 않으면 이름이 꼭 필요합니다.)

named export는 내보냈을 때 사용한 이름 그대로 가져오므로 관련 정보를 파악하기 쉽습니다. 그런데 아래와 같이 내보내기 할 때 쓴 이름과 가져오기 할 때 쓸 이름이 동일해야 한다는 제약이 있죠.
named export와는 다르게 default export는 가져오기 할 때 개발자가 원하는 대로 이름을 지정해 줄 수 있습니다.

다시 내보내기

import {login, logout} from './helpers.js'; export {login, logout};
// 동일
export {login, logout} from './helpers.js';

export as namespace foo

https://www.typescriptlang.org/docs/handbook/modules.html#umd-modules

import

import {...} from '경로'; 로 가져오기 가능
import * as name from '경로'; 로 가져와서 name.?? 로 접근도 가능
웹팩과 같은 모던 빌드 툴은 로딩 속도를 높이기 위해 모듈들을 한데 모으는 번들링과 최적화를 수행한다. 이 과정에서 사용하지 않는 리소스가 삭제되기도한다. 따라서 어떤 걸 가져올 땐 그 대상을 구체적으로 명시하는 게 좋다.

as

as를 사용해 이름을 바꿔서 모듈을 가져올 수 있음
import {sayHi as hi, sayBye as bye} from './say.js';


ES6 문법(export/import) vs CommonJs 문법(exports/require)

https://inpa.tistory.com/entry/NODE-%F0%9F%93%9A-require-%E2%9A%94%EF%B8%8F-import-CommonJs%EC%99%80-ES6-%EC%B0%A8%EC%9D%B4-1

( require / exports ) 는 NodeJS에서 사용되고 있는 CommonJS 키워드이고 Ruby 언어 스타일과 비슷하다라고 볼수 있다.
Babel과 같은 ES6 코드를 변환(transpile)해주는 도구를 사용할 수 없는 상황에서는 좋든 싫든 require 키워드를 사용해야 합니다

CommonJS 방식으로 모듈을 내보낼 때는 ES6처럼 명시적으로 선언하는 것이 아니라 특정 변수나 그 변수의 속성으로 내보낼 객체를 세팅해줘야 합니다. 특히, 제일 햇갈리는 부분이 바로 유사해보이는 exports 변수와 module.exports 변수를 상황에 맞게 잘 사용해야 한다는 점입니다. 기본적으로 다음 2가지 규칙만 기억하시면 됩니다.

  • 여러 개의 객체를 내보낼 경우, exports 변수의 속성으로 할당한다.
  • 딱 하나의 객체를 내보낼 경우, module.exports 변수 자체에 할당한다.

( import / export ) 는 ES6(ES2015)에서 새롭게 도입된 키워드로서 Java나 Python 언어 방식과 비슷하다.

차이점

  • require()는 CommonJS를 사용하는 node.js문이지만 import()는 ES6에서만 사용됩니다.
  • require()는 파일(어휘가 아님)에 들어있는 곳에 남아 있으며 import()는 항상 맨 위로 이동합니다.
  • require()는 프로그램의 어느 지점에서나 호출 할 수 있지만 import()는 파일의 시작 부분에서만 실행할 수 있습니다. (하지만 import전용 비동기 문법으로 처리 가능)
  • 대부분의 사람들은 require()문으로 직접 코드를 실행하지만 import()로 작업 할 때 실험적 모듈 기능 플래그를 사용하는 것을 선호합니다.
  • 프로그램에서 동시에 사용할 수 없습니다.
  • 일반적으로 import()는 사용자가 필요한 모듈 부분만 선택하고 로드할 수 있기 때문에 더 선호됩니다. 이 명령문은 require()보다 성능이 우수하며 메모리를 절약합니다.

ES6 문법(export/import)

/** export **/
export default module;
//혹은
export module;

/** import **/
import module from "module";
//혹은
import {module} from "module";

CommonJs 문법(exports/require)

/** export **/
module.exports = module;
//혹은
exports.module = () => {};

/** import **/
const module = require("module");
//혹은
const {module} = require("module");





export 지시자를 변수나 함수 앞에 붙이면 외부 모듈에서 해당 변수나 함수에 접근할 수 있습니다(모듈 내보내기). import 지시자를 사용하면 외부 모듈의 기능을 가져올 수 있습니다(모듈 가져오기).

javascript에서 모듈화 시켜 나눠져있는 파일의 값을 내보내고 가져올 때 export, import, require 사용

export
: 모듈에서 함수, 객체, 원시값을 내보냄

exports
: 모듈에서 함수, 객체, 원시값을 객체의 형태로 내보냄

exports default
: 분리되어 있는 파일에서 하나의 고정된 값만 내보냄

export는 내보낼 변수 하나하나의 값을 선언하여 내보냄
exports는 exports 객체를 내보내므로 객체의 프로퍼티 형태로 내보냄

exports.xx ?

export default
=> import
from '...' O / import { ** } from '...' X

exports.default

// import '@popperjs/core';
// import * as Popper from '@popperjs/core';
import { createPopper } from '@popperjs/core';
profile
하루 모아 평생 🧚🏻

0개의 댓글