Skip to content

단일 실행 파일 애플리케이션

[기록]

버전변경 사항
v20.6.0"useSnapshot" 지원 추가.
v20.6.0"useCodeCache" 지원 추가.
v19.7.0, v18.16.0다음 버전에서 추가됨: v19.7.0, v18.16.0

[안정성: 1 - 실험적]

안정성: 1 안정성: 1.1 - 활발한 개발

소스 코드: src/node_sea.cc

이 기능은 Node.js가 설치되지 않은 시스템에 Node.js 애플리케이션을 편리하게 배포할 수 있도록 합니다.

Node.js는 번들된 스크립트를 포함할 수 있는 Node.js에서 준비한 Blob을 node 바이너리에 삽입할 수 있도록 하여 단일 실행 파일 애플리케이션 생성을 지원합니다. 시작 시 프로그램은 삽입된 내용이 있는지 확인합니다. Blob이 발견되면 Blob의 스크립트를 실행합니다. 그렇지 않으면 Node.js는 정상적으로 작동합니다.

단일 실행 파일 애플리케이션 기능은 현재 CommonJS 모듈 시스템을 사용하여 단일 임베디드 스크립트 실행만 지원합니다.

사용자는 node 바이너리 자체와 바이너리에 리소스를 삽입할 수 있는 도구를 사용하여 번들된 스크립트에서 단일 실행 파일 애플리케이션을 만들 수 있습니다.

다음은 postject와 같은 도구를 사용하여 단일 실행 파일 애플리케이션을 만드는 단계입니다.

단일 실행 파일 준비 Blob 생성

애플리케이션에 삽입되는 단일 실행 파일 준비 Blob은 단일 실행 파일을 빌드하는 데 사용될 Node.js 바이너리의 --experimental-sea-config 플래그를 사용하여 생성할 수 있습니다. 이 플래그는 JSON 형식의 구성 파일 경로를 사용합니다. 전달된 경로가 절대 경로가 아니면 Node.js는 현재 작업 디렉터리를 기준으로 경로를 사용합니다.

현재 구성은 다음과 같은 최상위 필드를 읽습니다.

json
{
  "main": "/path/to/bundled/script.js",
  "output": "/path/to/write/the/generated/blob.blob",
  "disableExperimentalSEAWarning": true, // 기본값: false
  "useSnapshot": false,  // 기본값: false
  "useCodeCache": true, // 기본값: false
  "assets": {  // 선택 사항
    "a.dat": "/path/to/a.dat",
    "b.txt": "/path/to/b.txt"
  }
}

경로가 절대 경로가 아니면 Node.js는 현재 작업 디렉터리를 기준으로 경로를 사용합니다. Blob을 생성하는 데 사용된 Node.js 바이너리의 버전은 Blob이 삽입될 바이너리의 버전과 동일해야 합니다.

참고: 교차 플랫폼 SEA를 생성할 때(예: darwin-arm64에서 linux-x64용 SEA 생성), 호환되지 않는 실행 파일 생성을 방지하려면 useCodeCacheuseSnapshot을 false로 설정해야 합니다. 코드 캐시와 스냅샷은 컴파일된 동일한 플랫폼에서만 로드할 수 있으므로 생성된 실행 파일은 다른 플랫폼에서 빌드된 코드 캐시 또는 스냅샷을 로드하려고 할 때 시작 시 충돌할 수 있습니다.

에셋

사용자는 assets 필드로 키-경로 사전을 구성에 추가하여 에셋을 포함할 수 있습니다. 빌드 시 Node.js는 지정된 경로에서 에셋을 읽어 준비 Blob에 번들로 묶습니다. 생성된 실행 파일에서 사용자는 sea.getAsset()sea.getAssetAsBlob() API를 사용하여 에셋을 검색할 수 있습니다.

json
{
  "main": "/path/to/bundled/script.js",
  "output": "/path/to/write/the/generated/blob.blob",
  "assets": {
    "a.jpg": "/path/to/a.jpg",
    "b.txt": "/path/to/b.txt"
  }
}

단일 실행 파일 애플리케이션은 다음과 같이 에셋에 액세스할 수 있습니다.

js
const { getAsset, getAssetAsBlob, getRawAsset } = require('node:sea');
// ArrayBuffer에서 데이터의 복사본을 반환합니다.
const image = getAsset('a.jpg');
// 에셋에서 UTF8로 디코딩된 문자열을 반환합니다.
const text = getAsset('b.txt', 'utf8');
// 에셋을 포함하는 Blob을 반환합니다.
const blob = getAssetAsBlob('a.jpg');
// 복사하지 않고 원시 에셋을 포함하는 ArrayBuffer를 반환합니다.
const raw = getRawAsset('a.jpg');

자세한 내용은 sea.getAsset(), sea.getAssetAsBlob()sea.getRawAsset() API 설명서를 참조하십시오.

시작 스냅샷 지원

useSnapshot 필드를 사용하여 시작 스냅샷 지원을 활성화할 수 있습니다. 이 경우 최종 실행 파일이 시작될 때 main 스크립트가 실행되지 않습니다. 대신 단일 실행 파일 애플리케이션 준비 Blob이 빌드 시스템에서 생성될 때 실행됩니다. 생성된 준비 Blob에는 main 스크립트에 의해 초기화된 상태를 캡처하는 스냅샷이 포함됩니다. 준비 Blob이 삽입된 최종 실행 파일은 런타임에 스냅샷을 역직렬화합니다.

useSnapshot이 true이면 메인 스크립트는 v8.startupSnapshot.setDeserializeMainFunction() API를 호출하여 사용자가 최종 실행 파일을 시작할 때 실행해야 하는 코드를 구성해야 합니다.

단일 실행 파일 애플리케이션에서 스냅샷을 사용하는 일반적인 패턴은 다음과 같습니다.

시작 스냅샷 스크립트의 일반적인 제약 조건은 단일 실행 파일 애플리케이션에 대한 스냅샷을 빌드하는 데 사용되는 메인 스크립트에도 적용되며, 메인 스크립트는 v8.startupSnapshot API를 사용하여 이러한 제약 조건에 적응할 수 있습니다. Node.js의 시작 스냅샷 지원에 대한 설명서를 참조하십시오.

V8 코드 캐시 지원

구성에서 useCodeCachetrue로 설정된 경우, 단일 실행 파일 준비 blob을 생성하는 동안 Node.js는 main 스크립트를 컴파일하여 V8 코드 캐시를 생성합니다. 생성된 코드 캐시는 준비 blob의 일부가 되어 최종 실행 파일에 주입됩니다. 단일 실행 파일 애플리케이션이 시작되면 Node.js는 main 스크립트를 처음부터 컴파일하는 대신 코드 캐시를 사용하여 컴파일 속도를 높인 다음 스크립트를 실행하여 시작 성능을 향상시킵니다.

참고: useCodeCachetrue이면 import()가 작동하지 않습니다.

주입된 main 스크립트에서

단일 실행 파일 애플리케이션 API

node:sea 내장 모듈은 실행 파일에 내장된 JavaScript main 스크립트에서 단일 실행 파일 애플리케이션과의 상호 작용을 허용합니다.

sea.isSea()

추가된 버전: v21.7.0, v20.12.0

  • 반환 값: <boolean> 이 스크립트가 단일 실행 파일 애플리케이션 내에서 실행 중인지 여부입니다.

sea.getAsset(key[, encoding])

추가된 버전: v21.7.0, v20.12.0

이 메서드를 사용하여 빌드 시 단일 실행 파일 애플리케이션에 번들로 묶도록 구성된 자산을 검색할 수 있습니다. 일치하는 자산을 찾을 수 없으면 오류가 발생합니다.

  • key <string> 단일 실행 파일 애플리케이션 구성의 assets 필드에 지정된 사전에서 자산의 키입니다.
  • encoding <string> 지정된 경우 자산은 문자열로 디코딩됩니다. TextDecoder에서 지원하는 모든 인코딩이 허용됩니다. 지정하지 않으면 자산의 복사본이 포함된 ArrayBuffer가 대신 반환됩니다.
  • 반환 값: <string> | <ArrayBuffer>

sea.getAssetAsBlob(key[, options])

Added in: v21.7.0, v20.12.0

sea.getAsset()과 유사하지만, 결과를 Blob으로 반환합니다. 일치하는 에셋을 찾을 수 없으면 오류가 발생합니다.

  • key <string> 단일 실행 파일 애플리케이션 구성의 assets 필드에 지정된 사전에서 에셋의 키입니다.

  • options <Object>

    • type <string> Blob의 선택적 MIME 유형입니다.
  • 반환: <Blob>

sea.getRawAsset(key)

Added in: v21.7.0, v20.12.0

이 메서드를 사용하여 빌드 시 단일 실행 파일 애플리케이션에 번들로 묶이도록 구성된 에셋을 검색할 수 있습니다. 일치하는 에셋을 찾을 수 없으면 오류가 발생합니다.

sea.getAsset() 또는 sea.getAssetAsBlob()과 달리 이 메서드는 복사본을 반환하지 않습니다. 대신, 실행 파일 내부에 번들로 묶인 원시 에셋을 반환합니다.

현재 사용자는 반환된 배열 버퍼에 쓰는 것을 피해야 합니다. 삽입된 섹션이 쓰기 가능으로 표시되지 않거나 올바르게 정렬되지 않은 경우 반환된 배열 버퍼에 쓰면 충돌이 발생할 가능성이 높습니다.

  • key <string> 단일 실행 파일 애플리케이션 구성의 assets 필드에 지정된 사전에서 에셋의 키입니다.
  • 반환: <ArrayBuffer>

주입된 메인 스크립트의 require(id)는 파일 기반이 아닙니다.

주입된 메인 스크립트의 require()는 주입되지 않은 모듈에서 사용할 수 있는 require()와 동일하지 않습니다. 또한 주입되지 않은 require()가 가진 require.main을 제외한 어떤 속성도 없습니다. 내장 모듈을 로드하는 데만 사용할 수 있습니다. 파일 시스템에서만 찾을 수 있는 모듈을 로드하려고 하면 오류가 발생합니다.

파일 기반 require()에 의존하는 대신 애플리케이션을 독립 실행형 JavaScript 파일로 번들로 묶어 실행 파일에 주입할 수 있습니다. 이렇게 하면 보다 결정적인 종속성 그래프도 보장됩니다.

그러나 파일 기반 require()가 여전히 필요한 경우 다음과 같이 달성할 수도 있습니다.

js
const { createRequire } = require('node:module');
require = createRequire(__filename);

주입된 메인 스크립트의 `__filename` 및 `module.filename`

주입된 메인 스크립트에서 `__filename` 및 `module.filename`의 값은 [process.execPath](/ko/api/process#processexecpath)와 같습니다.

주입된 메인 스크립트의 `__dirname`

주입된 메인 스크립트에서 `__dirname`의 값은 [process.execPath](/ko/api/process#processexecpath)의 디렉터리 이름과 같습니다.

참고 사항

단일 실행 파일 애플리케이션 생성 프로세스

단일 실행 파일 Node.js 애플리케이션을 만드는 도구는 --experimental-sea-config로 준비된 blob의 내용을 다음 위치에 주입해야 합니다.

  • node 바이너리가 PE 파일인 경우 NODE_SEA_BLOB이라는 리소스
  • node 바이너리가 Mach-O 파일인 경우 NODE_SEA 세그먼트의 NODE_SEA_BLOB이라는 섹션
  • node 바이너리가 ELF 파일인 경우 NODE_SEA_BLOB이라는 노트

바이너리에서 NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0 fuse 문자열을 검색하고 마지막 문자를 1로 뒤집어 리소스가 주입되었음을 나타냅니다.

플랫폼 지원

단일 실행 파일 지원은 다음 플랫폼에서만 CI에서 정기적으로 테스트됩니다.

이는 다른 플랫폼에서 이 기능을 테스트하는 데 사용할 수 있는 단일 실행 파일 생성 도구가 부족하기 때문입니다.

다른 리소스 주입 도구/워크플로에 대한 제안을 환영합니다. https://github.com/nodejs/single-executable/discussions에서 토론을 시작하여 문서화하는 데 도움을 주세요.