问题:

  公司有个工具型项目使用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. javascript学习3、数据类型、数据类型转换、运算符

    数据类型包括:基本数据类型和引用数据类型 基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象. 当我们把变量赋值给一个变量时,解析器首先要确认的就是这个值是基本类型值还是引用类型值 ...

  2. Dart 知识点:位置参数(必选)、位置参数(可选)、命名参数(都是可选)

    先后顺序:位置参数(必选).位置参数(可选).命名参数(都是可选) 位置参数(可选).命名参数(都是可选),不能同时使用

  3. 范式(Paradigm)是什么?

    Paradigm (范式) 是一个领域中主流的行事套路,它包括 philosophy (理念) 和 methods (方法)两部分.Philosophy (理念) 这个概念很好理解.比如,购物理念就是 ...

  4. 协程 和 async await

    协程, 是 为了 避免 闭包传递变量 的 性能损耗 而产生  . 如果不是 为了 避免 闭包传递变量 的 性能损耗 ,    线程池 和 Task 已经够了,  不需要 再设计 出 协程 来  . 闭 ...

  5. 2017EC Final L SOS——找规律&&博弈

    题意 有n个格子排成一行,两人轮流填,可填入"S"或"0",先得到"SOS"的人胜:如果全部填完也没有出现"SOS",则 ...

  6. 学习:STL_vector容器

    vector基本概念: 功能: vector数据结构和数组非常相似,也称为单端数组 vector与普通数组区别: 不同之处在于数组是静态空间,而vector可以动态扩展 动态扩展: 并不是在原空间之后 ...

  7. vuex2 mapActions 报错 `unknown action type: xxxx`

    export const setBreadCrumb = ({ dispatch }, data) => { dispatch('SET_BREADCRUMB', data) } 当调用的时候报 ...

  8. centos 7 开启外网方法端口方法

    firewall-cmd --zone=public --add-port=80/tcp --permanent  开启80端口 systemctl stop firewalld.service sy ...

  9. csp-s 考前刷题记录

    洛谷 P2615 神奇的幻方 洛谷 P2678 跳石头 洛谷 P1226 [模板]快速幂||取余运算 洛谷 P2661 信息传递 LOJ P10147 石子合并 LOJ P10148 能量项链 LOJ ...

  10. node.js封装数据库增删改查

    数据库增删改查的封装 小编不容易 const sql = { insert: function (Collection, insertData) { return new Promise((resol ...