问题:

  公司有个工具型项目使用node.js 开发,需要部署到客户的服务器中,遇到的问题:

  1、客户的服务器没有外网。环境配置,依赖安装等都比较麻烦,只能手工上传,最好能一个文件直接搞定;

  2、直接包源码部署到客户的机器中,存在源码泄露的风险。

方案:

  使用pkg npm包可以很好的解决我们以上的问题。

  先参考前人的经验 : Egg.js线上部署——利用pkg打包Egg.js工程

pkg原理:

  pkg打包工具主要会按平台(支持window、mac、linux)分别打包。

  pkg中会包含node的可执行文件,还会包含你要打包进去的代码。代码通过一个虚拟的文件系统把所有的代码和资源文件都挂载到 /snapshot/${被打包项目的文件夹名} 下面(pkg hack了 fs 的很多方法,拦截文件操作,如果发现读的文件路径是在挂载目录下就特殊处理,返回打包进去的文件信息,如果不在挂载目录下,则按node默认逻辑进行)

  pkg 会根据被打包项目的package.json 中的licence声明判断是否要对源码进行编译,npm上安装的依赖包基本都是开源的,会以源码的形式打包;而用户的源码如果没有声明开源的协议,则会把js文件编译为v8字节码进行保存(在项目中也就没法通过fs读取到源码,会给出抛错,即使是破解安装包也只能拿到v8字节码)

实现:

1、安装(也可以考虑只安装到项目内,通过npm script 调用打包) 

npm install pkg -g

2、在egg配置文件中把涉及到写文件的路径都移到包外(pkg的虚拟文件系统只是用来应对读的行为,所有写相关都得移出包外)

// 通过process.cwd()获取当前执行文件执行的路径
config.rundir = process.cwd() + '/run';// 配置执行时临时文件的路径
config.logger = {
dir: path.join(process.cwd(), 'logs', logDir),//配置普通日志文件地址
};
config.customLogger = {
scheduleLogger: {
file: path.join(process.cwd(), 'logs', logDir, 'egg-schedule.log'),//配置定时任务日志的地址
},
};
config.static = { // 必须把public移出项目,否则在pkg的包中egg的static中间件会有对public操作(确保文件夹),会有抛错
prefix: '/',
dir: process.cwd() + '/public',//配置静态文件的地址
};

3、修改package.json文件

{
... "bin": "pkg-entry.js", // 执行包的入口文件,可执行包启动的时候默认会调用该文件 "pkg": {// 以下主要是声明那些文件需要被打包(pkg会解析require中的静态路径,但在egg.js中很多文件都是通过框架引用的,无法依赖解析)
"scripts": [ // 这里是声明需要打包的js文件,这里的声明的js文件都会被编译为v8字节码(建议主动声明,不要依赖pkg自动引入)
"./app/**/*.js",
"./config/**/*.js",
"./normalJs/**/*.js", // 不只是egg的文件,只要要用到就要声明打包
"./app.js",
"./agent.js"
],
"assets": [ // 这里是声明需要打包的静态文件(即使有js文件也不进行编译)。
"./lib/**/*",// lib中是我打算开放的一些egg组件,所有不需要编译
"./app/public/**/*",// 如果要把前端静态文件打包进来,就直接声明(但是在egg中static中间件会有抛错,需要hack egg或者 hack pkg)
"./node_modules/**/*"// npm安装的所有依赖包全部打包进来,不要依赖自动引入,很容易导致部分文件没打包,出现各种意料外的错误
]
},
}

4、增加入口文件pkg-entry.js(名字保持和package.json中一致)

const fs = require('fs');

// 如果是egg的ts项目,由于egg-script会给ts项目通过-r引入sourcemap的注入文件,但是pkg的spawn不支持,所以把项目标识为飞ts
// 如果不是ts项目忽略一下两行
const pkgInfo = require('./package');
pkgInfo.egg.typescript = false; // 防止egg-script识别为 typescript 自动添加soucemap支持(--require 在pkg的spawn中不支持) //我自己的工具包的配置文件是直接打包到安装包里面的,这样就不方便修改配置了。于是把提供给运维配置的配置都适用dotenv来配置,以下引入dotenv的预执行脚本
//也可以考虑把配置文件放到包外,不过因为包内执行包外js,会增加被攻击的风险
require('dotenv/config'); // 由于egg-script是默认以当前执行proccess.cwd() 路径为默认项目的,打包后需要每次输入 /snapshot/${项目文件夹名} 作为指定目录
// 所以,以下为修改参数,自动嵌入“/snapshot/${项目文件夹名}”
const baseDir = '/snapshot/' + fs.readdirSync('/snapshot')[0];
console.log('baseDir:', baseDir);
// 当 start 的时候,自动嵌入bashDir为 /snapshot/${项目文件夹名}
const startIndex = process.argv.indexOf('start');
if (startIndex > -1) {
process.argv = [].concat(
process.argv.slice(0, startIndex + 1),
baseDir,
process.argv.slice(startIndex + 1),
);
} // 然后直接调起egg-scripts执行
require('./node_modules/egg-scripts/bin/egg-scripts.js');

5、 执行打包

## --targets 用于制定平台和node版本,不指定时默认为3个平台以package.json中的node版本配置为准
## --out-path 指定执行包输出文件夹,默认为当前文件夹
## --debug 用于调试,可了解哪些文件被打包
pkg . --targets node8-linux-x64 --out-path /usr/dist --debug

6、运行

> chmod a+x ./appName #给可执行包增加执行权限
> ./appName start # 启动项目,除项目路径其它参数都和egg-scripts一致 可以用--title指定egg服务名
>./appName stop # 关闭项目(会关闭当前服务器的所有egg服务,如果有多个,最好用--title来指定要关闭的项目)

ps:

  如果需要动态配置或者包中使用了c++编译的node依赖包,可参考该文章  Egg.js线上部署——利用pkg打包Egg.js工程 。

可能遇到问题:

第一次打包的时候,会遇到下包很慢很可能超时的问题。如下:

到https://github.com/zeit/pkg-fetch/releases下载对应的包,然后
~/.pkh-cache/2.5/目录下,改名为fetched-v8.11.3-macos-x64(参考运行时下的包名字改)即可。参考https://github.com/zeit/pkg/issues/419

使用pkg打包node.js项目(egg框架)为可执行包的更多相关文章

  1. 使用pkg打包Node.js应用的方法步骤

    Node.js应用不需要经过编译过程,可以直接把源代码拷贝到部署机上执行,确实比C++.Java这类编译型应用部署方便.然而,Node.js应用执行需要有运行环境,意味着你需要先在部署机器上安装Nod ...

  2. Node.JS 项目打包 JXCore

    哈哈,又回来了 当你开发完成了Node.JS项目,你应该需要打包发行吧 好,JXCore就是干这个的啦! 嗯,可能你会这样来安装 1. curl http://jxcore.com/xil.sh | ...

  3. [Node.js] Node.js项目的持续集成

    原文地址:http://www.moye.me/2016/03/03/nodejs_ci_by_jenkins 引子 持续集成 (Continuous Integration,简称CI)是一种软件工程 ...

  4. node.js Web应用框架Express.js(一)

    什么是Express.js Express 是一个简洁而灵活的 node.js Web应用框架, 提供一系列强大特性帮助你创建各种Web应用,提供丰富的HTTP工具以及来自Connect框架的中间件随 ...

  5. WebStorm中Node.js项目配置教程(1)——创建项目

    Node.js绝对是一个web开发的热点话题,作为web神器的WebStorm也是开发Node.js的佼佼者. 接下来就Node.js项目在WebStorm的配置操作就行详细的讲解,首先是创建项目.两 ...

  6. node.js使用express框架进行文件上传

    关于node.js使用express框架进行文件上传,主要来自于最近对Settings-Sync插件做的研究.目前的研究算是取得的比较好的进展.Settings-Sync中通过快捷键上传文件,其实主要 ...

  7. 基于 Token 的身份验证:JSON Web Token(附:Node.js 项目)

    最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twitter,Google+,Github 等等,比起传统的身份验证方法,Token 扩展性更强, ...

  8. [Node.js]Express web框架

    摘要 Express是一个简洁灵活的node.js web应用框架,提供了一系列强大特性帮助你创建各种web应用和丰富的http工具.使用express可以快速创建一个完整功能的网站. Express ...

  9. WebStorm中Node.js项目配置教程——项目设置

    上一章讲解了Node.js项目在WebStorm中的两种创建方式,当完成Node.js项目创建以后,剩下的就是涉及配置设置工作. 为了确保Node.js全局和Node.js核心模块的代码完成功能,打开 ...

随机推荐

  1. server 2012/2016上,任务管理器性能页面增加磁盘监控

    1.用管理员身份启动命令行 2.命令行中输入:diskperf -y 3.关闭之前打开的任务管理,重新打开,发现可爱的磁盘监视器出现了.

  2. python 获取当前,上级,上上级路径

    import os print '***获取当前目录***' print os.getcwd() print os.path.abspath(os.path.dirname(__file__)) pr ...

  3. IDEA 中 Git Commit message 编写

    IDEA安装插件 Git Commit Template 1. HeaderHeader的部分只有一行,包括三个字段: type(必需), scope(可选), subject(必需) 对应到idea ...

  4. tomcat catalina

    脚本catalina用于启动和关闭tomcat服务器,是最关键的脚本 在tomcat里有此文件 写这个脚本的人为什么命名为catalina一开始我还以为是其初恋女友,后来才知道原来是一个小岛的名字.

  5. 严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener

    十月 30, 2019 11:12:35 下午 org.apache.catalina.core.StandardContext listenerStart 严重: Exception sending ...

  6. 判断json对象是否在数组中

    // 判断对象是否在数组中function objinArrar(check,param){ var isExisted = false; var index = -1; for(var i=0;i& ...

  7. [iOS] 利用 NSAttributedString 进行富文本处理

    /iOS /[iOS] 利用 NSAttributedString 进行富文本处理 2016年4月4日 刘小龙 iOS 许多时候我们需要以各种灵活的形式展现文本信息,即富文本.普通的 text 属性显 ...

  8. UFUN函数 UF_CURVE函数(UF_CURVE_create_line、UF_CURVE_create_arc、UF_CURVE_ask_arc_data、UF_CURVE_ask_line_data)

    UF_initialize(); //CSYS_ask_wcs tag_t wcs_id=NULL_TAG; //CSYS_ask_csys_info ]={0.0}; //CURVE_create_ ...

  9. WinDbg常用命令系列---!findstack

    简介 !findstack扩展查找所有包含指定的符号或模块的堆栈.此命令搜索线程调用堆栈中的特定符号,并显示匹配的线程. 使用形式 !findstack Symbol[DisplayLevel] !f ...

  10. [Java] Spring boot 的 SrpingSecurity 框架搭建

    参考: SrpingSecurity]之一:框架搭建https://blog.csdn.net/qq_28296925/article/details/82021092 [SpringSecurity ...