feat: standalone bundler

This commit is contained in:
calebboyd
2018-08-16 20:52:39 -05:00
committed by Caleb Boyd
parent c70d93b72f
commit 53ef02f87a
28 changed files with 638 additions and 2538 deletions
+8
View File
@@ -0,0 +1,8 @@
const express = require('express')
const path = require('path')
const app = express()
app.use('/', express.static(path.join(__dirname, 'public')))
app.listen(8888)
+373
View File
@@ -0,0 +1,373 @@
{
"name": "express-app",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"accepts": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
"integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
"requires": {
"mime-types": "~2.1.18",
"negotiator": "0.6.1"
}
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"body-parser": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
"requires": {
"bytes": "3.0.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.1",
"http-errors": "~1.6.2",
"iconv-lite": "0.4.19",
"on-finished": "~2.3.0",
"qs": "6.5.1",
"raw-body": "2.3.2",
"type-is": "~1.6.15"
}
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"content-disposition": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.16.3",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz",
"integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
"requires": {
"accepts": "~1.3.5",
"array-flatten": "1.1.1",
"body-parser": "1.18.2",
"content-disposition": "0.5.2",
"content-type": "~1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.1.1",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.2",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.3",
"qs": "6.5.1",
"range-parser": "~1.2.0",
"safe-buffer": "5.1.1",
"send": "0.16.2",
"serve-static": "1.13.2",
"setprototypeof": "1.1.0",
"statuses": "~1.4.0",
"type-is": "~1.6.16",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
}
},
"finalhandler": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.2",
"statuses": "~1.4.0",
"unpipe": "~1.0.0"
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"http-errors": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.0",
"statuses": ">= 1.4.0 < 2"
}
},
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
"integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
},
"mime-db": {
"version": "1.35.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
"integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
},
"mime-types": {
"version": "2.1.19",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
"integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
"requires": {
"mime-db": "~1.35.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"parseurl": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"proxy-addr": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
"integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.8.0"
}
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
"raw-body": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
"integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
"requires": {
"bytes": "3.0.0",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"unpipe": "1.0.0"
},
"dependencies": {
"depd": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
},
"http-errors": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
"integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
"requires": {
"depd": "1.1.1",
"inherits": "2.0.3",
"setprototypeof": "1.0.3",
"statuses": ">= 1.3.1 < 2"
}
},
"setprototypeof": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
"integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
}
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"send": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
"integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.6.2",
"mime": "1.4.1",
"ms": "2.0.0",
"on-finished": "~2.3.0",
"range-parser": "~1.2.0",
"statuses": "~1.4.0"
}
},
"serve-static": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
"integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.2",
"send": "0.16.2"
}
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
},
"statuses": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
"integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
},
"type-is": {
"version": "1.6.16",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.18"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
}
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"name": "express-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.3"
}
}
+1
View File
@@ -0,0 +1 @@
<h1>Hello World!</h1>
+19 -1
View File
@@ -1,6 +1,6 @@
{
"name": "nexe",
"version": "2.0.0-next.13",
"version": "2.0.0-next.14",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -106,6 +106,15 @@
"integrity": "sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww==",
"dev": true
},
"@types/multistream": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@types/multistream/-/multistream-2.1.1.tgz",
"integrity": "sha512-PqavtNFnMyXRZS5vuW16wMOKeJUCD5PIGHdNBHzF5Urjncsij90hRQ82Wcy9+uSdnmrR2Gfao6xoJVq1wAWzbA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "10.5.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.7.tgz",
@@ -1807,6 +1816,15 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"multistream": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz",
"integrity": "sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==",
"requires": {
"inherits": "^2.0.1",
"readable-stream": "^2.0.5"
}
},
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+4 -1
View File
@@ -2,7 +2,7 @@
"name": "nexe",
"description": "Create a single executable out of your Node.js application",
"license": "MIT",
"version": "2.0.0-next.13",
"version": "2.0.0-next.14",
"contributors": [
"Craig Condon <craig.j.condon@gmail.com> (http://crcn.io)",
"Jared Allard <jaredallard@outlook.com>",
@@ -33,6 +33,7 @@
"node": ">=6"
},
"dependencies": {
"@calebboyd/semaphore": "^1.3.1",
"app-builder": "^5.2.0",
"caw": "^2.0.1",
"chalk": "^2.4.1",
@@ -42,6 +43,7 @@
"got": "^8.3.1",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"multistream": "^2.1.1",
"ora": "^2.1.0",
"pify": "^4.0.0",
"resolve-dependencies": "^2.1.1",
@@ -55,6 +57,7 @@
"@types/minimist": "^1.2.0",
"@types/mkdirp": "^0.5.2",
"@types/mocha": "^5.2.0",
"@types/multistream": "^2.1.1",
"@types/ora": "^1.3.4",
"@types/pify": "3.0.2",
"@types/rimraf": "2.0.2",
-24
View File
@@ -1,24 +0,0 @@
{
"name": "nexe-daemon",
"version": "1.0.0",
"description": "Plugin for nexe to create installable services",
"main": "lib/index.js",
"scripts": {
"clean": "rimraf *.js",
"build": "tsc",
"postpublish": "npm run clean"
},
"files": [
"lib",
"winsw.exe"
],
"author": "Caleb Boyd",
"license": "MIT",
"devDependencies": {
"rimraf": "^2.6.2",
"typescript": "^2.5.2"
},
"dependencies": {
"nexe": "^2.0.0-rc.11"
}
}
-48
View File
@@ -1,48 +0,0 @@
import { NexeCompiler, NexeOptions } from 'nexe'
import { readFileSync } from 'fs'
import { join } from 'path'
interface NexeDaemonOptions {
id: string
name: string
description: string
executable: string
}
type DaemonOptions = NexeOptions & { daemon: { windows: NexeDaemonOptions } }
function renderWinswConfig(options: any) {
return (
'<configuration>\r\n' +
`${Object.keys(options).reduce((config: string, element: string) => {
return (config += `<${element}>${options[element]}</${element}>\r\n`)
}, '')}</configuration>\r\n`
)
}
export default function daemon(compiler: NexeCompiler<DaemonOptions>, next: () => Promise<void>) {
if (compiler.target.platform !== 'windows') {
return next()
}
compiler.addResource(
'./nexe/plugin/daemon/winsw.exe',
readFileSync(require.resolve('../winsw.exe'))
)
const name = compiler.options.name,
options = (compiler.options.daemon && compiler.options.daemon.windows) || {},
defaults: NexeDaemonOptions = {
id: name,
name,
description: name,
executable: '%BASE%\\' + compiler.output
}
compiler.addResource(
'./nexe/plugin/daemon/winsw.xml',
Buffer.from(renderWinswConfig(Object.assign(defaults, options)))
)
compiler.addResource('./nexe/plugin/daemon/app.js', Buffer.from(compiler.input))
compiler.input = '{{replace:plugins/nexe-daemon/lib/nexe-daemon.js}}'
return next()
}
-66
View File
@@ -1,66 +0,0 @@
const installCommands = ['-i', '--install']
const installIndex = process.argv.findIndex(x => installCommands.includes(x))
import * as path from 'path'
import * as fs from 'fs'
import * as cp from 'child_process'
function mkdirp(r: string, t?: any): any {
;(t = t || null), (r = path.resolve(r))
try {
fs.mkdirSync(r), (t = t || r)
} catch (c) {
if ('ENOENT' === c.code) (t = mkdirp(path.dirname(r), t)), mkdirp(r, t)
else {
var i
try {
i = fs.statSync(r)
} catch (r) {
throw c
}
if (!i.isDirectory()) throw c
}
}
return t
}
if (~installIndex) {
console.log('DIRECTORY FOUND')
const directory = process.argv[installIndex + 1]
if (directory) {
mkdirp(path.dirname(directory))
const filename = path.join(directory, path.basename(process.execPath))
const readStream = fs.createReadStream(process.execPath)
const writeStream = fs.createWriteStream(filename)
const onError = function() {
readStream.removeAllListeners()
writeStream.removeAllListeners()
//TODO
}
readStream
.on('error', onError)
.pipe(writeStream)
.on('error', onError)
.on('close', () => {
const winsw = filename.replace('.exe', '-service.exe')
fs.writeFileSync(winsw, fs.readFileSync('./nexe/plugin/daemon/winsw.exe'))
fs.writeFileSync(
filename.replace('.exe', '-service.xml'),
fs.readFileSync('./nexe/plugin/daemon/winsw.xml')
)
installService(winsw)
})
}
} else {
console.log('DIRECTORY NOT FOUND')
require('./nexe/plugin/daemon/app.js')
}
function installService(filename: string) {
cp.exec(filename + ' install', error => {
if (error && !error.message.includes('already exists')) {
throw error
}
})
}
-13
View File
@@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": [ "es2016" ],
"outDir": "lib",
"strict": true
},
"include": [
"src/**/*.ts"
],
"exclude": []
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
-11
View File
@@ -1,11 +0,0 @@
{
"name": "nexe-bundle-fs",
"version": "1.0.0",
"description": "Set of fs patches for nexe bundles",
"main": "patch.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Caleb Boyd",
"license": "MIT"
}
View File
+32 -32
View File
@@ -1,7 +1,7 @@
import { delimiter, dirname, normalize, join } from 'path'
import { Buffer } from 'buffer'
import { createReadStream } from 'fs'
import { Readable } from 'stream'
import { Readable, Stream } from 'stream'
import { spawn } from 'child_process'
import { Logger, LogStep } from './logger'
import { readFileAsync, writeFileAsync, pathExistsAsync, dequote, isWindows, bound } from './util'
@@ -10,6 +10,8 @@ import { NexeTarget } from './target'
import download = require('download')
import { getLatestGitRelease } from './releases'
import { IncomingMessage } from 'http'
import combineStreams = require('multistream')
import { Bundle, toStream } from './fs/bundle'
const isBsd = Boolean(~process.platform.indexOf('bsd'))
const make = isWindows ? 'vcbuild.bat' : isBsd ? 'gmake' : 'make'
@@ -23,29 +25,23 @@ export interface NexeFile {
export { NexeOptions }
interface NexeHeader {
resources: { [key: string]: number[] }
version: string
}
export class NexeCompiler {
private start = Date.now()
private env = { ...process.env }
private bundle: Bundle
private compileStep: LogStep | undefined
public log = new Logger(this.options.loglevel)
public src: string
public files: NexeFile[] = []
public shims: string[] = []
public input: string | undefined
public startup: string = ''
public entrypoint: string | undefined
public bundledInput?: string
public targets: NexeTarget[]
public target: NexeTarget
public resources: { bundle: Buffer; index: { [key: string]: number[] } } = {
index: {},
bundle: Buffer.from('')
}
public output = this.options.output
private nodeSrcBinPath: string
constructor(public options: NexeOptions) {
const { python } = (this.options = options)
this.targets = options.targets as NexeTarget[]
@@ -55,7 +51,7 @@ export class NexeCompiler {
? join(this.src, 'Release', 'node.exe')
: join(this.src, 'out', 'Release', 'node')
this.log.step('nexe ' + version, 'info')
this.bundle = new Bundle(options)
if (isWindows) {
const originalPath = process.env.PATH
delete process.env.PATH
@@ -71,10 +67,16 @@ export class NexeCompiler {
}
@bound
addResource(file: string, contents: Buffer) {
const { resources } = this
resources.index[file] = [resources.bundle.byteLength, contents.byteLength]
resources.bundle = Buffer.concat([resources.bundle, contents])
addResource(file: string, content?: Buffer | string) {
return this.bundle.addResource(file, content)
}
get binaryConfiguration() {
return { resources: this.bundle.index }
}
get resourceSize() {
return this.bundle.blobSize
}
@bound
@@ -234,27 +236,25 @@ export class NexeCompiler {
}
code() {
return [this.shims.join(''), this.input].join(';')
return [this.shims.join(''), this.startup].join(';')
}
private _assembleDeliverable(binary: NodeJS.ReadableStream) {
if (!this.options.mangle) {
return binary
}
const artifact = new Readable({ read() {} })
binary.on('data', (chunk: Buffer) => {
artifact.push(chunk)
})
binary.on('close', () => {
const content = this.code()
artifact.push(content)
artifact.push(this.resources.bundle)
const lengths = Buffer.from(Array(16))
lengths.writeDoubleLE(Buffer.byteLength(content), 0)
lengths.writeDoubleLE(this.resources.bundle.byteLength, 8)
artifact.push(Buffer.concat([Buffer.from('<nexe~~sentinel>'), lengths]))
artifact.push(null)
})
return artifact
const startup = this.code(),
codeSize = Buffer.byteLength(startup)
const lengths = Buffer.from(Array(16))
lengths.writeDoubleLE(codeSize, 0)
lengths.writeDoubleLE(this.bundle.blobSize, 8)
return combineStreams([
binary,
toStream(startup),
this.bundle.toStream(),
toStream(Buffer.concat([Buffer.from('<nexe~~sentinel>'), lengths]))
])
}
}
+53
View File
@@ -0,0 +1,53 @@
# nexe-fs
This module contains a set of patches used to create (and use) the nexe virtual filesystem
---
### Getting Started:
To patch the module loader, monkey patches must be installed on a few methods at the time that node boots up. This requires a special build of node. Nexe provides these builds or the patch can be applied from this module manually in your own build setup.
```javascript
const bootstrapPatch = fs.readFileSync(require.resolve('nexe-fs/bootstrap'), 'utf-8')
// insert boostrapPatch wherever node starts up. For reference, Nexe does this
// in third-party-main.ts
```
To create a virtual file system use the `Bundle` Object
```javascript
const { Bundle } = require('nexe-fs')
const bundle = new Bundle({ cwd })
await bundle.addResource(absoluteFileName)
bundle.toStream().pipe(fs.createWriteStream('./myFsBlob'))
// You'll also want to save the bundle index to use at runtime
// It can be saved by accessing bundle.index (object/hash) or serializing the bundle with JSON.stringify(bundle)
```
In the entrypoint of the custom node build, the fs patch needs to be applied
```javascript
const fakeFs = fs.readFileSync(require.resolve('nexe-fs/patch'), 'utf-8')
//apply this code to your entrypoint
```
The patch exposes two methods, `shimFs` and `restoreFs` to be used as follows:
```javascript
shimFs({
blobPath: 'location/of/myFsBlob',
resources: bundle.index,
layout: {
stat: blobStats //fs.Stats object about the blob at blobPath
resourceStart: 0 // the offset within the blob that is referenced by the bundle index
}
})
```
At this point executing the original entrypoint shoudl result in usage of the virtual filesystem.
+70
View File
@@ -0,0 +1,70 @@
import { stat as getStat, Stats, createReadStream } from 'fs'
import { relative } from 'path'
import { Readable } from 'stream'
import combineStreams = require('multistream')
const stat = (file: string): Promise<Stats> => {
return new Promise((resolve, reject) => {
getStat(file, (err, stats) => (err ? reject(err) : resolve(stats)))
})
}
function makeRelative(cwd: string, path: string) {
return './' + relative(cwd, path)
}
export function toStream(content: Buffer | string) {
const readable = new Readable({ read() {} })
readable.push(content)
readable.push(null)
return readable
}
export type File = { absPath: string; contents: string; deps: FileMap }
export type FileMap = { [absPath: string]: File | null }
export interface BundleOptions {
entries: string[]
cwd: string
expand: boolean
loadContent: boolean
files: FileMap
}
export class Bundle {
constructor({ cwd }: { cwd: string } = { cwd: process.cwd() }) {
this.cwd = cwd
}
cwd: string
blobSize: number = 0
index: { [relativeFilePath: string]: [number, number] } = {}
streams: (Readable | (() => Readable))[] = []
async addResource(absoluteFileName: string, content?: Buffer | string) {
let length = 0
if (content) {
length = Buffer.byteLength(content)
} else {
const stats = await stat(absoluteFileName)
length = stats.size
}
const start = this.blobSize
this.blobSize += length
this.index[makeRelative(this.cwd, absoluteFileName)] = [start, length]
this.streams.push(() => (content ? toStream(content) : createReadStream(absoluteFileName)))
}
concat() {
throw new Error('Not Implemented')
}
toStream() {
return combineStreams(this.streams)
}
toJSON() {
return this.index
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"name": "nexe-fs",
"version": "1.0.1",
"description": "Virtual File System used by nexe",
"main": "bundle.js",
"files": [
"*.d.ts",
"*.js"
],
"author": "Caleb Boyd",
"dependencies": {
"multistream": "^2.1.1"
},
"license": "MIT"
}
+14 -4
View File
@@ -13,16 +13,24 @@ export interface NexeBinary {
}
let originalFsMethods: any = null
let nexeBinary: NexeBinary | null = null
function restoreFs(fs: any) {
if (!originalFsMethods) {
return
function restoreFs(fs: any = require('fs')): NexeBinary | false {
if (!nexeBinary) {
return false
}
const source = nexeBinary
Object.assign(fs, originalFsMethods)
nexeBinary = originalFsMethods = null
return source
}
function shimFs(binary: NexeBinary, fs: any = require('fs')) {
if (originalFsMethods !== null) {
return
}
originalFsMethods = Object.assign({}, fs)
nexeBinary = binary
const { blobPath, resources: manifest } = binary
const { resourceStart, stat } = binary.layout
const directories: { [key: string]: { [key: string]: boolean } } = {},
@@ -325,6 +333,8 @@ function shimFs(binary: NexeBinary, fs: any = require('fs')) {
process.nextTick(() => cb(exists))
}
}
Object.assign(fs, nfs)
return true
}
export { shimFs as applyFsPatch, restoreFs }
export { shimFs, restoreFs }
+1 -1
View File
@@ -21,9 +21,9 @@ async function compile(
const nexe = compose(
clean,
resource,
cli,
bundle,
shim,
cli,
options.build ? [download, artifacts, ...patches, ...(options.patches as NexePatch[])] : [],
options.plugins as NexePatch[]
)
+1 -1
View File
@@ -63,7 +63,7 @@ export default async function main(compiler: NexeCompiler, next: () => Promise<v
})
const fileLines = file.contents.split('\n')
fileLines.splice(location.start.line, 0, '{{replace:lib/patches/bootstrap.js}}' + '\n')
fileLines.splice(location.start.line, 0, '{{replace:lib/fs/bootstrap.js}}' + '\n')
file.contents = fileLines.join('\n')
await compiler.setFileContentsAsync(
+8 -35
View File
@@ -1,49 +1,22 @@
import { NexeCompiler } from '../compiler'
import { readFileAsync, writeFileAsync } from '../util'
import { resolve, relative } from 'path'
import { resolve } from 'path'
import { each } from '@calebboyd/semaphore'
import resolveFiles from 'resolve-dependencies'
function makeRelative(cwd: string, path: string) {
return './' + relative(cwd, path)
}
let producer = async function(compiler: NexeCompiler): Promise<string> {
const { cwd, input } = compiler.options
const { files, entries } = await resolveFiles(input, { cwd, expand: true })
const mainFileContents = (entries[input].contents as string) || ''
Object.keys(files).forEach(filename => {
const file = files[filename]!
if (file && file.contents) {
compiler.addResource(makeRelative(cwd, filename), Buffer.from(file.contents))
}
})
return Promise.resolve(mainFileContents)
}
export default async function bundle(compiler: NexeCompiler, next: any) {
const { bundle, cwd, empty, input } = compiler.options
const { bundle, cwd, input } = compiler.options
if (!bundle) {
compiler.input = await readFileAsync(resolve(cwd, input), 'utf-8')
await compiler.addResource(resolve(cwd, input))
return next()
}
if (!input) {
compiler.input = ''
return next()
}
if (typeof bundle === 'string') {
producer = require(resolve(cwd, bundle)).createBundle
}
compiler.input = await producer(compiler)
const debugBundle = compiler.options.debugBundle
if (debugBundle) {
let bundleDebugFile = typeof debugBundle === 'string' ? debugBundle : 'nexe-debug.bundle.js'
await writeFileAsync(resolve(cwd, bundleDebugFile), compiler.input)
}
const { files } = await resolveFiles(input, { cwd, expand: true, loadContent: false })
await each(Object.keys(files), (filename: string) => compiler.addResource(filename), {
concurrency: 10
})
return next()
}
+9 -4
View File
@@ -1,10 +1,11 @@
import { normalize, relative } from 'path'
import { normalize, relative, resolve } from 'path'
import { createWriteStream, chmodSync, statSync } from 'fs'
import { dequote } from '../util'
import { Readable } from 'stream'
import { NexeCompiler } from '../compiler'
import { NexeTarget } from '../target'
function getStdIn(stdin: NodeJS.ReadStream): Promise<string> {
function getStdIn(stdin: Readable): Promise<string> {
return new Promise(resolve => {
let out = ''
stdin
@@ -38,9 +39,13 @@ export default async function cli(compiler: NexeCompiler, next: () => Promise<vo
let stdInUsed = false
if (!process.stdin.isTTY && compiler.options.enableStdIn) {
stdInUsed = true
compiler.input = dequote(await getStdIn(process.stdin))
compiler.entrypoint = './__nexe_stdin.js'
const code = dequote(await getStdIn(process.stdin))
await compiler.addResource(resolve(compiler.options.cwd, compiler.entrypoint), code)
} else {
compiler.entrypoint = './' + relative(compiler.options.cwd, compiler.options.input)
}
compiler.startup = ';require("module").runMain();'
await next()
const target = compiler.options.targets.shift() as NexeTarget
+3 -6
View File
@@ -1,11 +1,9 @@
import { readFileAsync, isDirectoryAsync, each } from '../util'
import { isDirectoryAsync, each } from '../util'
import * as globs from 'globby'
import { NexeCompiler } from '../compiler'
export default async function resource(compiler: NexeCompiler, next: () => Promise<any>) {
const resources = compiler.resources
const { cwd } = compiler.options
if (!compiler.options.resources.length) {
return next()
}
@@ -17,9 +15,8 @@ export default async function resource(compiler: NexeCompiler, next: () => Promi
}
count++
step.log(`Including file: ${file}`)
const contents = await readFileAsync(file)
compiler.addResource(file, contents)
await compiler.addResource(file)
})
step.log(`Included ${count} file(s). ${(resources.bundle.byteLength / 1e6).toFixed(3)} MB`)
step.log(`Included ${count} file(s). ${(compiler.resourceSize / 1e6).toFixed(3)} MB`)
return next()
}
+10 -16
View File
@@ -1,13 +1,12 @@
import { NexeCompiler } from '../compiler'
import { relative } from 'path'
import { wrap } from '../util'
export default function(compiler: NexeCompiler, next: () => Promise<void>) {
compiler.shims.push(
wrap(
`process.__nexe = ${JSON.stringify({ resources: compiler.resources.index })};\n` +
'{{replace:lib/bundle/fs/patch.js}}' +
'\nshimFs(process.__nexe, require("fs"))'
`process.__nexe = ${JSON.stringify(compiler.binaryConfiguration)};\n` +
'{{replace:lib/fs/patch.js}}' +
'\nshimFs(process.__nexe)'
)
)
compiler.shims.push(
@@ -20,18 +19,13 @@ export default function(compiler: NexeCompiler, next: () => Promise<void>) {
`)
)
if (compiler.options.fakeArgv !== false) {
const nty = !process.stdin.isTTY
const input = nty
? '[stdin]'
: JSON.stringify(relative(compiler.options.cwd, compiler.options.input))
compiler.shims.push(
wrap(`
var r = require('path').resolve;
process.argv.splice(1,0, ${nty ? `'${input}'` : `r(${input})`});`)
)
}
compiler.shims.push(
wrap(`
if (!process.send) {
process.argv.splice(1,0, require.resolve("${compiler.entrypoint}"))
}
`)
)
return next()
}
+2 -1
View File
@@ -10,7 +10,8 @@ inject('lib/patches/third-party-main.js')
inject('lib/steps/shim.js')
inject('lib/options.js', JSON.stringify(require('../package.json').version))
cp('src/bundle/fs/package.json', 'lib/bundle/fs/package.json')
cp('src/fs/package.json', 'lib/fs/package.json')
cp('src/fs/README.md', 'lib/fs/README.md')
function inject(filename: string, ...replacements: string[]) {
let contents = readFileSync(filename, 'utf8')
View File