Готовые исполняемые приложения¶
Стабильность: 1 – Экспериментальная
Эта функция находится в стадии разработки и будет меняться.
Эта возможность позволяет удобно распространять приложение Node.js в системе, на которой не установлен Node.js.
Node.js поддерживает создание одноисполняемых приложений, позволяя внедрять подготовленный Node.js блоб, который может содержать пакетный скрипт, в двоичный файл node
. При запуске программа проверяет, не было ли что-либо инжектировано. Если блоб найден, она выполняет скрипт, содержащийся в блобе. В противном случае Node.js работает как обычно.
Функция одноисполняемого приложения в настоящее время поддерживает только запуск одного встроенного сценария с использованием системы модулей CommonJS.
Пользователи могут создать одноисполняемое приложение из своего встроенного скрипта с помощью самого бинарного файла node
и любого инструмента, который может внедрять ресурсы в бинарный файл.
Создание одноисполняемого приложения¶
Ниже приведены шаги по созданию одноисполняемого приложения с помощью одного из таких инструментов, postject:
1. Создайте файл JavaScript¶
Создайте файл JavaScript:
1 |
|
2. Создайте файл конфигурации¶
Создайте файл конфигурации, построив блоб, который можно внедрить в одноисполняемое приложение:
1 |
|
3. Создайте блоб¶
Создайте блоб для инъекции:
1 |
|
4. Создайте копию исполняемого файла¶
Создайте копию исполняемого файла node
и назовите его в соответствии с вашими потребностями:
1 |
|
5. Удалите подпись¶
Удалите подпись двоичного файла:
- На macOS:
1 |
|
- На Windows (опционально):
signtool можно использовать из установленного Windows SDK. Если этот шаг пропущен, игнорируйте все предупреждения postject, связанные с подписью.
1 |
|
6. Внедрите блоб¶
Внедрите блоб в скопированный двоичный файл, запустив postject
со следующими опциями:
hello
- Имя копии исполняемого файлаnode
, созданного на шаге 2.NODE_SEA_BLOB
- Имя ресурса / заметки / секции в бинарном файле, где будет храниться содержимое блоба.sea-prep.blob
- Имя блоба, созданного на шаге 1.--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
- fuse, используемый проектом Node.js для обнаружения инъекции файла.--macho-segment-name NODE_SEA
(нужен только на macOS) - Имя сегмента в бинарном файле, где будет храниться содержимое блоба.
Подводя итог, вот необходимая команда для каждой платформы:
- В системах, отличных от macOS:
1 2 |
|
- На macOS:
1 2 3 |
|
7. Подпишите бинарный файл¶
Подпишите бинарный файл:
- На macOS:
1 |
|
-
На Windows (опционально):
Для этого необходимо наличие сертификата. Однако неподписанный двоичный файл все равно можно будет запустить.
1 |
|
8. Запустите бинарный файл¶
Запустите бинарный файл:
1 2 |
|
Генерация подготовительных блобов для одноисполняемого файла¶
Подготовительные блобы для одноисполняемого файла, которые внедряются в приложение, могут быть сгенерированы с помощью флага --experimental-sea-config
в бинарном файле Node.js, который будет использоваться для сборки одноисполняемого файла. Он принимает путь к конфигурационному файлу в формате JSON. Если переданный ему путь не абсолютный, Node.js будет использовать путь относительно текущего рабочего каталога.
В настоящее время конфигурация считывает следующие поля верхнего уровня:
1 2 3 4 |
|
Если пути не абсолютные, Node.js будет использовать путь относительно текущего рабочего каталога. Версия бинарного файла Node.js, используемого для создания блоба, должна быть такой же, как и версия, в которую будет внедрен блоб.
Примечания¶
require(id)
в инжектируемом модуле не основан на файлах¶
require()
в инжектируемом модуле - это не то же самое, что require()
, доступное для модулей, которые не инжектируются. Он также не обладает ни одним из свойств, которыми обладает неинжектированный require()
, кроме require.main
. Его можно использовать только для загрузки встроенных модулей. Попытка загрузить модуль, который может быть найден только в файловой системе, приведет к ошибке.
Вместо того, чтобы полагаться на файловый require()
, пользователи могут упаковать свое приложение в отдельный JavaScript-файл для внедрения в исполняемый файл. Это также обеспечивает более детерминированный граф зависимостей.
Однако, если все же требуется require()
на основе файла, это также может быть достигнуто:
1 2 |
|
__filename
и module.filename
в инжектированном модуле¶
Значения __filename
и module.filename
в инжектированном модуле равны process.execPath
.
__dirname
в инжектируемом модуле¶
Значение __dirname
в инжектируемом модуле равно имени каталога process.execPath
.
Процесс создания одного исполняемого приложения¶
Инструмент, нацеленный на создание одного исполняемого Node.js приложения, должен инжектировать содержимое блоба, подготовленного с помощью --experimental-sea-config
:
- ресурс с именем
NODE_SEA_BLOB
, если двоичный файлnode
является PE файлом - секцию с именем
NODE_SEA_BLOB
в сегментеNODE_SEA
, если двоичный файлnode
является файлом Mach-O - примечание с именем
NODE_SEA_BLOB
, если двоичный файлnode
является файлом ELF.
Поиск в двоичном файле строки NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2:0
fuse и переверните последний символ в 1
, чтобы указать, что ресурс был инжектирован.
Поддержка платформ¶
Поддержка одноисполняемых файлов регулярно тестируется на CI только на следующих платформах:
- Windows
- macOS
- Linux (все дистрибутивы поддерживаемые Node.js, кроме Alpine, и все архитектуры поддерживаемые Node.js, кроме s390x и ppc64).
Это связано с отсутствием лучших инструментов для генерации одиночных исполняемых файлов, которые можно было бы использовать для тестирования этой функции на других платформах.
Предложения по другим инструментам/рабочим процессам инъекции ресурсов приветствуются. Пожалуйста, начните обсуждение по адресу https://github.com/nodejs/single-executable/discussions, чтобы помочь нам документировать их.