ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JavaScript 모듈 시스템
    프로그래밍 언어/JavaScript 2021. 12. 2. 01:43

    JavaScript의 모듈 시스템

    프로그램은 여러 작은 기능들이 합쳐져 있는 집합체라 볼 수 있다.

    그리고 개발자가 이러한 프로그램을 개발할 때, 보통은 각기 서로 다른 기능의 동작을 위한 코드들을 한 곳에 몰아서 작성하지 않는다. 즉, 하나의 프로그램을 한 파일에 몰아서 작성하지 않는다.

     

    이는 한 코드의 오류가 프로그램 전체로 퍼지는 것을 막음과 동시에, 각 코드들의 유지 보수를 간편하게 하기 위함이다.

    또한 보통 개발자가 자기 스스로 모든 코드를 다 작성하는 경우는 없다. 이미 세상엔 많은 선배 개발자들이 미리 만들어둔 라이브러리가 있고, 개발자들은 자신이 제작하려는 프로그램에 맞는 라이브러리들을 입맛에 맞춰 골라 사용하면 된다. 즉, 한번 작성된 코드가 다른 프로그램에서도 활용될 수 있는 코드의 재활용성이 극대화된 방식이라 볼 수 있다.

     

    이렇게 마치 레고 조각을 쌓아 올리는 방식을 모듈 시스템이라 할 수 있다. 위에서 설명한 각 라이브러리들 하나하나가 모듈 즉, 레고 조각이라 생각하면 된다. 필요한 모양의 레고 조각을 골라 완성품을 만드는 방식으로 개발을 하는 것이다.

    이때 특정한 기능을 구현하는데에 에러가 생기면, 해당 모듈만을 다시 점검하는 방식을 사용할 수 있다.

     

    따라서 어떠한 언어를 사용하여 개발을 하든, 어떠한 환경에서 개발을 하든 간에 이러한 모듈화는 필수적이라 볼 수 있다. 그리고 당연히 개발자들이 주로 사용하는 언어들은 대부분 이러한 모듈 시스템에 대한 표준이 정해져 있다.

     

    하지만 놀랍게도 ES6이전의 JavaScript는 모듈 시스템에 대한 표준이 없었다.

    JavaScript를 사용하는 개발자 역시 개발자이기 때문에 모듈에 관한 필요성을 느꼈고, 따라서 뜻이 맞는 개발자들이 모여 자체적으로 JavaScript에서 모듈을 사용하는 표준을 정하였다.

     

    다음은 이러한 표준을 위한 움직임으로 대표되는 2가지 모듈 방식인 CommonJS와 AMD이다.


    JavaScript 모듈 시스템의 역사 (CommonJS와 AMD)

    우선 JavaScript라는 언어는 본래 웹상에서만 동작하는 간단한 Script언어였다. 웹페이지의 동적인 작동을 위해서 도입된 초기의 JS는 많은 계산양이 필요하지 않고, 복잡하지 않은 형태였다. 따라서 모듈 시스템 또한 필요성이 적었다.

     

    JavaScript는 HTML에서 <script> 태그를 통해 불러져 동작되는데, 이때 서로 다른 JavaScript파일이라도 하나의 HTML 파일에서 로드된다면, 마치 한 파일에 작성된 듯이 동작한다. 즉, 각 JavaScript 소스 파일마다 독립적인 파일 스코프를 가질 수 없었기에, 모듈 시스템이 없는 JavaScript 시스템은 변수명의 충돌과 같은 기본적인 문제조차 잡을 수 없는 상황이었다.

     

    하지만 JavaScript의 중요성이 부각되고, Google에서 공개한 V8 JavaScript엔진이 많은 주목을 받으며, 이제 JS는 웹브라우저 밖에서도 사용되려는 움직임을 보였다. 따라서 JavaScript에서도 모듈화가 풀어야 할 문제가 되었다.

    CommonJS

    CommonJS는 JavaScript를 웹브라우저에서 벗어나 서버사이드나 개별 애플리케이션으로 사용하기 위해 뜻이 맞는 JavaScript 개발자들이 모인 단체이다.

     

    해당 단체에서는 JavaScript를 범용적으로 사용하기 위해 필요한 표준안(Specification)을 만드는 일을 한다. 즉, 직접적인 개발 툴을 만드는 것이 아니라, JavaScript를 웹브라우저 밖에서 어떠한 방식으로 사용해야 하는지에 대한 표준을 정의하는 것이다.

     

    이러한 CommonJS는 현재 JavaScript 서버사이드 플랫폼 중 가장 대중적으로 쓰이는 NodeJS가 따르고 있다.

    즉, NodeJS를 이용해 JavaScript 프로젝트를 구성한다면, CommonJS 방식으로 모듈을 사용할 수 있다.

    AMD (Aynchronous Monule Definition)

    CommonJS가 서버사이드 환경을 전제로하여 모듈화 표준을 진행한 그룹이라면, AMD는 비동기환경인 웹브라우저에서의 모듈화를 위한 그룹이다.

     

    본래는 JavaScript의 모듈화를 위해 함께였지만, 비동기환경에서의 JavaScript 모듈화를 위한 부분에서 서로 합의점을 찾지못하고 CommonJS에서 독립하여 AMD가 되었다.

     

    이러한 AMD는 비동기환경에서 JavaScript모듈을 네트워크를 이용해 내려받는 상황에서도 모듈을 사용하도록 표준을 만들었다. 이러한 AMD 방식은 RequireJS라는 JavaScript로더가 구현했다.

     

    하지만 현재 ES6 이상의 JavaScript에서는 공식적으로 모듈을 지원한다. 따라서 AMD의 방식을 사용할 이유는 없어보인다. 다만 CommonJS 방식은 NodeJS에서 여전히 유효하기 때문에, 아직까지 계속해서 사용된다.


    CommonJS 방식의 모듈 시스템

    위에서 말했듯이 NodeJS 환경에서 사용하는 모듈 시스템은 CommonJS의 방식을 따른다.

    (단, NodeJS 13.2.0 버전 이상부터는 ES에서 지원하는 모듈 시스템을 사용할 수 있다)

     

    이러한 CommonJS 방식을 적용한 모듈 시스템의 사용법은 아래와 같다.

    모듈 내보내기

    특정 모듈을 만들고, 이를 외부로 내보내기 위해서는 'module.exports'를 사용한다.

    이 'module.exports' 변수에 내보내고자 하는 데이터나 데이터를 담은 객체를 지정하면 끝이다.

    // 단순 데이터 내보내기
    module.exports = 158;
    module.exports = "Exports Data";
    
    // 데이터를 담은 객체 내보내기
    module.exports = { data: "Exports Data", code: 158 };

    이때 'exports' 변수를 사용하여 'module.exports'에 담긴 객체를 가리킬 수 있다.

    단, exports 자체에 다른 값을 대입하면 안된다.

    module.exports = { data: "Exports Data", code: 158 };
    exports.data = "Updated Data";
    exports = "Updated Data"; // 잘못된 사용방법

    모듈 불러오기

    외부 모듈의 데이터를 불러오기 위해서는 'require()' 함수를 사용한다.

    해당 함수의 인수로는 불러올 모듈의 경로를 써준다. 이때 require() 함수는 불러온 모듈의 module.exprots 객체를 반환한다.

    const moduleData = require("./myModules/firstModule");
    // moduleData에는 불러온 모듈의 module.exports 객체가 저장된다.
    // "./myModules/firstModule"는 불러올 모듈이 위치한 경로이다.

    ES 방식의 모듈 시스템

    위의 방식들은 모두 JavaScript에 표준 모듈 시스템이 없어서 생겨난 방법들이다. 하지만 ES6 이후 JavaScript도 자체적인 표준 모듈 시스템을 갖게 되었다. 따라서 비동기환경인 프론트엔드단에서도 모듈화를 간단하게 사용할 수 있게 되었다.

     

    단, 이러한 모듈 시스템을 브라우저에서 사용하려면 <script> 태그에 type="module" 속성을 부여해야 한다. 또한 불러오는 파일이 모듈임을 명확히 하기 위해, 해당 JavaScript 파일의 확장자는 'mjs'로 설정하도록 권장된다.

     

    이러한 ES 방식의 모듈 시스템 사용법은 아래와 같다.

    모듈 내보내기

    모듈을 외부로 내보내기 위해서는 export 키워드를 사용한다.

    export를 이용하여 데이터를 내보내는 방법은 아래와 같다.

    // 1. 변수, 함수 등을 선언하면서 동시에 내보내기
    export const myData = "exported Data"
    export const myFunction = (a, b) => {
      return a + b;
    };
    
    // 2. 변수명, 함수명 등을 모아서 내보내기
    const myData = "exported Data"
    const myFunction = (a, b) => {
      return a + b;
    };
    
    export { myData, myFunction };
    
    // 3. 다른이름으로 변경하여 내보내기
    const myData = "exported Data"
    export { myData as anotherName };

    또는 default 키워드를 이용해 이름을 정하지 않고 내보낼 수 있다.

    단, 이렇게 이름을 정하지 않고 내보내는 값은 최대 하나만 가능하다.

    // 1. 이름없이 선언과 동시에 내보내기
    export dafult const myData = "exported Data";
    
    // 2. 이름없이 내보내기
    const myData = "exported Data";
    export { myData as default };

    모듈 불러오기

    외부의 모듈을 불러오기 위해서는 import 키워드를 사용한다.

    import를 이용하여 데이터를 불러오는 방법은 아래와 같다.

    // 1. 이름없이 Default로 export된 데이터 불러오기 (원하는 이름으로 불러오기 가능)
    import AnythingCan from "./path";
    
    // 2. 이름이 지정된 상태로 export된 데이터 불러오기
    import { myData } from "./path";
    
    // 3. 이름이 지정된 상태로 export된 데이터 원하는 이름으로 변경하여 불러오기
    import { myData as anotherName } from "./path";
    
    // 4. 해당 경로의 파일에서 export된 데이터 객체형태로 한번에 가져오기
    import * as obj from "./path";

    [참조]

    https://d2.naver.com/helloworld/12864

    https://it-eldorado.tistory.com/92

    댓글