웹 프론트엔드 JS 튜토리얼 Node.js: cjs, 번들러, esm의 간략한 역사

Node.js: cjs, 번들러, esm의 간략한 역사

Dec 15, 2024 am 05:36 AM

Node.js: A brief history of cjs, bundlers, and esm

소개

Node.js 개발자라면 cjs와 esm 모듈에 대해 들어본 적이 있을 것입니다. 하지만 두 가지 모듈이 있는 이유와 Node.js 애플리케이션에서 이들 모듈이 어떻게 공존하는지 잘 모를 수도 있습니다. 이 블로그 게시물에서는 Node.js의 JavaScript 모듈 역사를 간략하게 설명하므로(예제 포함) 이러한 개념을 다룰 때 더욱 자신감을 가질 수 있습니다.

글로벌 범위

초기 JavaScript에는 모든 멤버가 선언된 전역 범위만 있었습니다. 두 개의 독립적인 파일이 멤버에 대해 동일한 이름을 사용할 수 있기 때문에 코드를 공유할 때 문제가 되었습니다. 예:

greet-1.js

function greet(name) {
  return `Hello ${name}!`;
}
로그인 후 복사
로그인 후 복사

greet-2.js

var greet = "...";
로그인 후 복사
로그인 후 복사

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Collision example</title>
  </head>
  <body>
    <!-- After this script, `greet` is a function -->
    <script src="greet-1.js"></script>

    <!-- After this script, `greet` is a string -->
    <script src="greet-2.js"></script>

    <script>
        // TypeError: "greet" is not a function
        greet();
    </script>
  </body>
</html>
로그인 후 복사
로그인 후 복사

CommonJS 모듈

Node.js는 CommonJS(cjs라고도 함)를 통해 JavaScript 모듈 개념을 공식적으로 도입했습니다. 개발자는 내보낼 항목(module.exports를 통해)과 가져올 항목(require()를 통해)을 결정할 수 있으므로 공유 전역 범위의 충돌 문제가 해결되었습니다. 예:

src/greet.js

// this remains "private"
const GREETING_PREFIX = "Hello";

// this will be exported
function greet(name) {
  return `${GREETING_PREFIX} ${name}!`;
}

// `exports` is a shortcut to `module.exports`
exports.greet = greet;
로그인 후 복사
로그인 후 복사

src/main.js

// notice the `.js` suffix is missing
const { greet } = require("./greet");

// logs: Hello Alice!
console.log(greet("Alice"));
로그인 후 복사
로그인 후 복사

npm 패키지

Node.js 개발은 개발자가 재사용 가능한 JavaScript 코드를 게시하고 사용할 수 있게 해주는 npm 패키지 덕분에 폭발적인 인기를 얻었습니다. npm 패키지는 기본적으로 node_modules 폴더에 설치됩니다. 모든 npm 패키지에 있는 package.json 파일은 "main" 속성을 통해 Node.js의 진입점을 나타낼 수 있기 때문에 특히 중요합니다. 예:

node_modules/greeter/package.json

{
  "name": "greeter",
  "main": "./entry-point.js"
  // ...
}
로그인 후 복사
로그인 후 복사

node_modules/greeter/entry-point.js

module.exports = {
  greet(name) {
    return `Hello ${name}!`;
  }
};
로그인 후 복사
로그인 후 복사

src/main.js

// notice there's no relative path (e.g. `./`)
const { greet } = require("greeter");

// logs: Hello Bob!
console.log(greet("Bob"));
로그인 후 복사
로그인 후 복사

번들러

npm 패키지는 다른 개발자의 작업을 활용할 수 있어 개발자의 생산성을 획기적으로 높였습니다. 그러나 cjs는 웹 브라우저와 호환되지 않는다는 큰 단점이 있었습니다. 이 문제를 해결하기 위해 번들러라는 개념이 탄생했습니다. browserify는 기본적으로 진입점을 탐색하고 모든 require() 코드를 웹 브라우저와 호환되는 단일 .js 파일로 "번들링"하여 작동하는 최초의 번들러였습니다. 시간이 지남에 따라 추가 기능과 차별화 요소를 갖춘 다른 번들러가 도입되었습니다. 가장 주목할만한 것은 webpack, 소포, 롤업, esbuild 및 vite입니다(연대순).

ECMA스크립트 모듈

Node.js 및 cjs 모듈이 주류가 되면서 ECMAScript 사양 관리자는 모듈 개념을 포함하기로 결정했습니다. 이것이 기본 JavaScript 모듈을 ESModules 또는 esm(ECMAScript 모듈의 약어)이라고도 하는 이유입니다.

esm은 멤버 내보내기 및 가져오기를 위한 새로운 키워드와 구문을 정의하고 기본 내보내기와 같은 새로운 개념을 도입합니다. 시간이 지남에 따라 esm 모듈은 동적 import() 및 최상위 대기와 같은 새로운 기능을 얻었습니다. 예:

src/greet.js

function greet(name) {
  return `Hello ${name}!`;
}
로그인 후 복사
로그인 후 복사

src/part.js

var greet = "...";
로그인 후 복사
로그인 후 복사

src/main.js

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Collision example</title>
  </head>
  <body>
    <!-- After this script, `greet` is a function -->
    <script src="greet-1.js"></script>

    <!-- After this script, `greet` is a string -->
    <script src="greet-2.js"></script>

    <script>
        // TypeError: "greet" is not a function
        greet();
    </script>
  </body>
</html>
로그인 후 복사
로그인 후 복사

시간이 지남에 따라 esm 구문을 cjs로 변환할 수 있는 TypeScript와 같은 언어 및 번들러 덕분에 esm은 개발자들 사이에서 널리 채택되었습니다.

Node.js cjs/esm 상호 운용성

수요 증가로 인해 Node.js는 버전 12.x에 esm에 대한 지원을 공식적으로 추가했습니다. cjs와의 하위 호환성은 다음과 같이 달성되었습니다.

  • Node.js는 package.json이 "type" 속성을 "module"로 설정하지 않는 한 .js 파일을 cjs 모듈로 해석합니다.
  • Node.js는 .cjs 파일을 cjs 모듈로 해석합니다.
  • Node.js는 .mjs 파일을 esm 모듈로 해석합니다.

npm 패키지 호환성과 관련하여 esm 모듈은 cjs 및 esm 진입점을 사용하여 npm 패키지를 가져올 수 있습니다. 그러나 그 반대에는 몇 가지 주의 사항이 있습니다. 다음 예를 들어보세요:

node_modules/cjs/package.json

// this remains "private"
const GREETING_PREFIX = "Hello";

// this will be exported
function greet(name) {
  return `${GREETING_PREFIX} ${name}!`;
}

// `exports` is a shortcut to `module.exports`
exports.greet = greet;
로그인 후 복사
로그인 후 복사

node_modules/cjs/entry.js

// notice the `.js` suffix is missing
const { greet } = require("./greet");

// logs: Hello Alice!
console.log(greet("Alice"));
로그인 후 복사
로그인 후 복사

node_modules/esm/package.json

{
  "name": "greeter",
  "main": "./entry-point.js"
  // ...
}
로그인 후 복사
로그인 후 복사

node_modules/esm/entry.js

module.exports = {
  greet(name) {
    return `Hello ${name}!`;
  }
};
로그인 후 복사
로그인 후 복사

다음은 정상적으로 실행됩니다.

src/main.mjs

// notice there's no relative path (e.g. `./`)
const { greet } = require("greeter");

// logs: Hello Bob!
console.log(greet("Bob"));
로그인 후 복사
로그인 후 복사

그러나 다음은 실행되지 않습니다.

src/main.cjs

// this remains "private"
const GREETING_PREFIX = "Hello";

// this will be exported
export function greet(name) {
  return `${GREETING_PREFIX} ${name}!`;
}
로그인 후 복사

이것이 허용되지 않는 이유는 esm 모듈은 최상위 대기를 허용하는 반면 require() 함수는 동기식이기 때문입니다. 동적 import()를 사용하도록 코드를 다시 작성할 수 있지만 Promise를 반환하므로 다음과 같은 결과가 발생합니다.

src/main.cjs

// default export: new concept
export default function part(name) {
  return `Goodbye ${name}!`;
}
로그인 후 복사

이 호환성 문제를 완화하기 위해 일부 npm 패키지는 조건부 내보내기와 함께 package.json의 "내보내기" 속성을 활용하여 cjs 및 mjs 진입점을 모두 노출합니다. 예:

node_modules/esm/entry.cjs:

// notice the `.js` suffix is required
import part from "./part.js";

// dynamic import: new capability
// top-level await: new capability
const { greet } = await import("./greet.js");

// logs: Hello Alice!
console.log(greet("Alice"));

// logs: Bye Bob!
console.log(part("Bob"));
로그인 후 복사

node_modules/esm/package.json:

{
  "name": "cjs",
  "main": "./entry.js"
}
로그인 후 복사

"exports" 속성을 지원하지 않는 Node.js 버전과의 하위 호환성을 위해 "main"이 어떻게 cjs 버전을 가리키는지 확인하세요.

결론

cjs 및 esm 모듈에 대해 (2024년 12월 기준) 알아야 할 (거의) 전부입니다. 아래에 여러분의 생각을 알려주세요!

위 내용은 Node.js: cjs, 번들러, esm의 간략한 역사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

JavaScript로 문자열 문자를 교체하십시오 JavaScript로 문자열 문자를 교체하십시오 Mar 11, 2025 am 12:07 AM

JavaScript로 문자열 문자를 교체하십시오

jQuery 날짜가 유효한지 확인하십시오 jQuery 날짜가 유효한지 확인하십시오 Mar 01, 2025 am 08:51 AM

jQuery 날짜가 유효한지 확인하십시오

jQuery는 요소 패딩/마진을 얻습니다 jQuery는 요소 패딩/마진을 얻습니다 Mar 01, 2025 am 08:53 AM

jQuery는 요소 패딩/마진을 얻습니다

10 JQuery Accordions 탭 10 JQuery Accordions 탭 Mar 01, 2025 am 01:34 AM

10 JQuery Accordions 탭

10 JQuery 플러그인을 확인할 가치가 있습니다 10 JQuery 플러그인을 확인할 가치가 있습니다 Mar 01, 2025 am 01:29 AM

10 JQuery 플러그인을 확인할 가치가 있습니다

노드 및 HTTP 콘솔로 HTTP 디버깅 노드 및 HTTP 콘솔로 HTTP 디버깅 Mar 01, 2025 am 01:37 AM

노드 및 HTTP 콘솔로 HTTP 디버깅

사용자 정의 Google 검색 API 설정 자습서 사용자 정의 Google 검색 API 설정 자습서 Mar 04, 2025 am 01:06 AM

사용자 정의 Google 검색 API 설정 자습서

jQuery div에 스크롤 바를 추가합니다 jQuery div에 스크롤 바를 추가합니다 Mar 01, 2025 am 01:30 AM

jQuery div에 스크롤 바를 추가합니다

See all articles