фон спроса
Служба nodeJS, разработанная с помощью Egg.js, должна быть развернута на сайте клиента.В соответствии с обычной операцией развертывания вам необходимо установить среду разработки NodeJS на сервере, затем настроить прокси-сервер, зеркальный источник, установить зависимости, а затем запустить службу через команду запуска npm.
В реальном бизнесе сервер управляется и обслуживается на стороне клиента.Такой сложный процесс работы явно неприемлем.Пользователю нужен исполняемый exe-файл, который может быть автоматически запущен двойным щелчком по сервису.
Да, тогда вы можете упаковать только среду выполнения NodeJs, зависимости npm и исходный код, а также выполнить предварительный поиск доступных инструментов упаковки NodeJs:
- pkg
- node-packer
- Nexe
- EncloseJS (deprecated)
Репутация pkg относительно хороша, и даже автор EncloseJS настоятельно рекомендует пользователям перейти на pkg.
Dear users of EncloseJS. I highly encourage you to switch to github.com/zeit/pkg.
Начало.
Инициализировать проект яйца
яйцаофициальная документацияЭто очень подробно, следуйте инструкциям, чтобы сначала инициализировать проект. Если вы уже знакомы с проектом Egg, можете пропустить эту главу.
npm init egg --type=simple
Если вы столкнулись с проблемой тайм-аута загрузки шаблона, вы можете попробовать добавить параметры прокси в командную строку инициализации:
npm init egg --type=simple -r https://registry.npm.taobao.org/
После выполнения структура каталогов проекта выглядит следующим образом:
egg-project
├── package.json
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
├── config
| ├── plugin.js
| ├── config.default.js
└── test
└── controller
└── home.test.js
Выполните npm install для установки зависимостей проекта:
npm install
Чтобы служба могла запускаться нормально, вам также необходимо глобально установить egg-bin и egg-scripts:
npm install -g egg-bin egg-scripts
На этом этапе выполните скрипт npm run dev, чтобы запустить сервер в режиме разработки:
npm run dev
Затем откройте браузерlocalhost:7001Порт показывает привет, яйцо, даже если сервисная среда яйца отлажена.
начать шагать
Сначала установите pkg глобально, чтобы команды pkg можно было выполнять из командной строки:
npm install -g pkg
в соответствии с упаковкойREADME, мы можем указать файл входа в проект тремя способами:
The entrypoint of your project is a mandatory CLI argument. It may be:
- Path to entry file. Suppose it is
/path/app.js
, then packaged app will work the same way asnode /path/app.js
- Path to
package.json
.Pkg
will followbin
property of the specifiedpackage.json
and use it as entry file.- Path to directory.
Pkg
will look forpackage.json
in the specified directory. See above.
Перевести для перевода:
- Явно укажите файл входа, например, укажите файл входа как /path/app.js, pkg будет работать как узел /path/app.js;
- Укажите package.json, pkg будет использовать свойство bin файла package.json в качестве входного файла;
- Укажите каталог, и pkg будет использовать атрибут bin файла package.json в каталоге в качестве файла входа.
Мы знаем, что обычно есть файл app.js в качестве входного файла в корневом каталоге проекта express, так где же входной файл egg?
Спрятано яйцом.
Ссылаться наРешение для запуска приложения egg с использованием pm2, мы можем добавить server.js в качестве файла входа в корневой каталог.
// server.js
const egg = require('egg');
const workers = Number(process.argv[2] || require('os').cpus().length);
egg.startCluster({
workers,
baseDir: __dirname,
});
Также укажите файл записи в package.json
{
...
+ "bin": "server.js"
...
}
Как упакован pkg?
pkg проходит через все зависимости проекта из файла ввода, указанного пользователем.При импорте файла javascript pkg компилирует его в байт-код v8 и упаковывает в исполняемый файл (скрипты); при импорте статического ресурса pkg исходное содержимое будет копируется непосредственно в исполняемый файл (Активы).
Можно ли обработать все файлы js и статические ресурсы pkg?
Нет, это зависит от того, как загружается ресурс. pkg автоматически упаковывает ресурсы с путями, указанными в __dirname и __filename, в исполняемые программы, такие как метод require (который использует __direname для внутреннего поиска ресурсов) и метод path.join(__dirname, "../path/to/asset") для ввести статические файлы:
require('./router.js')
path.join(__dirname, './app/public/index.html')
Однако pkg не может распознавать и автоматически импортировать импорт ресурсов небуквенных параметров, таких как:
require('./build/' + cmd + '.js')
path.join(__dirname, 'views/' + viewName)
В настоящее время нам нужно активно отображать ресурсы, которые необходимо упаковать, в атрибуте pkg файла package.json. В проекте яйца мы сначала настроим его следующим образом, а настроим позже, когда столкнемся с ямами:
// package.json
{
...
"pkg": {
"scripts": [
"./app/**/*.js",
"./config/*.js"
],
"assets": [
"./app/public/**/*"
]
}
...
}
На данный момент давайте рассмотрим эту проблему. Во время выполнения ресурсы, изначально указывающие на локальную файловую систему, больше не существуют. Как работает программа? Например, код пишет require("./server.js" ), но текущий каталог файлов имеет только один исполняемый файл, а файл server.js отсутствует, как работает программа?
Здесь мы поговорим о механизме загрузки файловых ресурсов pkg.
pkg волшебным образом изменил fs API узла, перехватил операции с файлами и проксировал их в свою собственную виртуальную файловую систему моментальных снимков (snapshot filesystem). Например, во время выполнения для загрузки server.js в require("./server.js") pkg будет проксировать путь /snapshot/server.js (c:\snapshot в Windows) и загружать из фиктивного файл Содержимое ранее упакованного файла возвращается в систему моментальных снимков.
Какие формы чтения и записи файлов повлияют на систему моментальных снимков виртуальных файлов pkg? Автор приводит следующую таблицу:
value |
with node
|
packaged |
__filename | /project/app.js | /snapshot/project/app.js |
__dirname | /project | /snapshot/project |
process.cwd() | /project | /deploy |
process.execPath | /usr/bin/nodejs | /deploy/app-x64 |
process.argv[0] | /usr/bin/nodejs | /deploy/app-x64 |
process.argv[1] | /project/app.js | /snapshot/project/app.js |
process.pkg.entrypoint | undefined | /snapshot/project/app.js |
process.pkg.defaultEntrypoint | undefined | /snapshot/project/app.js |
require.main.filename | /project/app.js | /snapshot/project/app.js |
То есть,Если вы хотите, чтобы ресурсы автоматически упаковывались в исполняемые файлы, используйте локаторы путей, такие как __filename и __direname. С другой стороны, если вы хотите получить доступ к реальной файловой системе, например, загрузить файлы переменных среды, вы должны использовать локатор пути, такой как process.cwd(), что позволяет динамически изменять параметры запуска или работы службы, например, изменять номер порта службы.
На этот раз давайте подумаем над вопросом, как поступить в ситуации с локальной записью рабочего лога?
Да, нам нужно указать путь журнала через process.cwd() в файле конфигурации яйца, чтобы выполнять операции записи в реальную файловую систему. Точно так же все операции чтения и записи в реальную файловую систему должны быть объявлены в файле конфигурации через process.cwd():
// config/config.default.js
const path = require("path");
module.exports = appInfo => {
...
// 配置运行时相关文件存储路径
config.rundir = process.cwd() + '/run';
// 配置日志目录
config.logger = {
dir: path.join(process.cwd(), 'logs'),
};
// 配置静态资源路径
config.static = {
prefix: '/',
dir: process.cwd() + '/public',
};
...
}
При выполнении команды упаковки нам нужно добавить параметр --targets, чтобы указать формат цели упаковки: [nodeRange]-[platform]-[arch], где:
- nodeRange: укажите версию узла, например node${n} или последнюю
- платформа: укажите операционную систему, например, freebsd, linux, alpine, macos, win
- arch: указать архитектуру ЦП, например x64, x86, armv6, armv7
Например: node12-win-x64, несколько целевых форматов упаковки могут быть разделены запятыми.
Параметр target также можно указать в свойстве pkg файла package.json:
// package.json
{
"pkg": {
"scripts": [
"./app/**/*.js",
"./config/*.js"
],
"assets": [
"./app/public/**/*"
],
"targets": [
"node12-win-x64"
]
}
}
При этом для облегчения упаковки создадим новый скрипт упаковки npm:
// package.json
{
"scripts": {
"build": "pkg . --out-path D:/ --debug"
}
}
Обратите внимание, что выходной каталог, отличный от текущего пути проекта, специально указывается здесь с помощью параметра --out-path, чтобы убедиться, что упакованный исполняемый файл также доступен за пределами текущей среды проекта, и чтобы избежать некоторых ресурсов, которые не упакованы, но К исполняемым файлам по-прежнему можно получить доступ из реальной файловой системы, что упрощает обнаружение проблем как можно раньше.
На этом этапе мы выполняем следующие команды для предварительной попытки упаковки:
npm run build
В это время возникла первая проблема: загрузка бинарного файла узла не удалась из-за интранет-прокси или других сетевых причин. Ссылаться наIssues #419, допустимыйpkg-fetch ReleaseВручную загрузите бинарный файл узла на странице, поместите его в каталог C:\Users\username\.pkg-cache\v2.6\, продолжайте выполнять команду сборки npm run и, наконец, завершите сборку пакета:
В это время при запуске исполняемого файла будет обнаружена следующая ошибка:
Взгляните на сообщение об ошибке:
Error: [egg-core] load file: D:\snapshot\egg-pkg-template\node_modules\egg-security\app\extend\ context.js, error: Cannot find module 'nanoid/non-secure'
На самом деле это означает, что файл в пакете egg-security не упакован в наш исполняемый файл, в результате чего файл не может быть найден во время выполнения.
Мы можем явно указать для упаковки отсутствующих ресурсов js в скриптах pkg:
// package.json
{
"pkg": {
"scripts": [
"./app/**/*.js",
"./config/*.js",
+ "./node_modules/nanoid/**/*.js"
],
"assets": [
"./app/public/**/*"
],
"targets": [
"node12-win-x64"
]
}
}
Снова выполните команду упаковки, затем запустите исполняемый файл:
В это время, хотя служба успешно запустилась, но ошибка все еще есть, мы затем анализируем журнал ошибок:
2020-07-28 23:11:43,493 ERROR 37628 nodejs.ENOENTError: ENOENT: no such file or directory, watch 'D:\snapshot\egg-pkg-template\app'
at FSWatcher.start (internal/fs/watchers.js:169:26)
at Object.watch (fs.js:1415:11)
at Walk.<anonymous> (D:\snapshot\egg-pkg-template\node_modules\wt\index.js:183:20)
at Walk.emit (events.js:315:20)
at D:\snapshot\egg-pkg-template\node_modules\ndir\lib\ndir.js:107:16
at zalgoSafe (pkg/prelude/bootstrap.js:260:10)
at pkg/prelude/bootstrap.js:962:9
at pkg/prelude/bootstrap.js:336:5
at pkg/prelude/bootstrap.js:314:14
at FSReqCallback.wrapper [as oncomplete] (fs.js:516:5)
Кажется, что функция плагина Watcher ненормальна в локальной среде разработки и выполнения.В режиме реального времени, когда мы упаковываем и генерируем исполняемые файлы, он должен применяться к производственной среде по умолчанию, поэтому в настоящее время нам нужно добавьте файл env в каталог конфигурации, чтобы указать текущую среду как рабочую среду. Кроме того, не забудьте изменить конфигурацию pkg, чтобы убедиться, что этот файл будет упакован.
// package.json
{
"pkg": {
"scripts": [
"./app/**/*.js",
- "./config/*.js",
+ "./config/*",
"./node_modules/nanoid/**/*.js"
],
"assets": [
"./app/public/**/*"
],
"targets": [
"node12-win-x64"
]
}
}
Выполните команду упаковки еще раз и запустите исполняемую программу, и запуск пройдет гладко:
В это время порт localhost:7001 открыт, служба яйца работает нормально, а журнал, запуск и общие папки также добавляются в текущий каталог, что подтверждает конфигурацию, записанную ранее реальной файловой системой.
Это всего лишь руководство, а последующая разработка бизнес-кода предоставляется каждому. Код проекта этой статьи загружен на github.Coodool/egg-pkg-template, пожалуйста, поставьте звезду, если вам это нравится.
использованная литература
- Используйте pkg для упаковки проекта node.js (среда яйца) в виде исполняемого пакета.
- Онлайн-развертывание Egg.js — используйте pkg для упаковки проекта Egg.js
- Упаковка приложений Node.js с помощью pkg
- github vercel/pkg
- Официальная документация яйца