chore(bundling): start alternate bundling strategy

This commit is contained in:
calebboyd
2018-02-03 23:17:02 -06:00
committed by Caleb Boyd
parent ce9cdcba46
commit 92058b6137
36 changed files with 2524 additions and 3333 deletions
+1 -3
View File
@@ -1,5 +1,3 @@
{
"recommendations": [
"esbenp.prettier-vscode"
]
"recommendations": [ "eg2.tslint" ]
}
+3 -5
View File
@@ -1,9 +1,7 @@
{
"typescript.tsdk": "./node_modules/typescript/lib",
"prettier.semi": false,
"prettier.singleQuote": true,
"prettier.typescriptEnable": ["typescript"],
"editor.trimAutoWhitespace": true,
"tslint.enable": true,
"tslint.run": "onType",
"tslint.autoFixOnSave": true,
"files.exclude": {
"**/.git": true,
"**/.svn": true,
+2 -2
View File
@@ -237,9 +237,9 @@ $ npm test
## Maintainers
[![Jared Allard](https://avatars.githubusercontent.com/u/2391349?s=130)](https://jaredallard.me/) | [![Caleb Boyd](https://avatars.githubusercontent.com/u/5818726?s=130)](https://github.com/calebboyd) | [![Christopher Karper](https://avatars.githubusercontent.com/u/653156?s=130)](https://github.com/ckarper) | [![Dustin Greif](https://avatars.githubusercontent.com/u/3026298?s=130)](https://github.com/dgreif) |
[![Jared Allard](https://avatars.githubusercontent.com/u/2391349?s=130)](https://jaredallard.me/) | [![Caleb Boyd](https://avatars.githubusercontent.com/u/5818726?s=130)](https://github.com/calebboyd) | [![Dustin Greif](https://avatars.githubusercontent.com/u/3026298?s=130)](https://github.com/dgreif) |
---|---|---|---
[Jared Allard](https://github.com/jaredallard) | [Caleb Boyd](http://github.com/calebboyd) | [Christopher Karper](https://github.com/ckarper) | [Dustin Greif](https://github.com/dgreif) |
[Jared Allard](https://github.com/jaredallard) | [Caleb Boyd](http://github.com/calebboyd) | [Dustin Greif](https://github.com/dgreif) |
### Former
+2
View File
@@ -0,0 +1,2 @@
const { echo } = require('shelljs')
echo('hello world')
+37
View File
@@ -0,0 +1,37 @@
const { resolve } = require('resolve-dependencies')
const path = require('path')
module.exports.createBundle = async function createBundle (options) {
console.log(path.isAbsolute(options.input))
const { entries, files } = await resolve(options.input)
const lcp = findLcp(Object.keys(files))
const relFiles = relativize(files, lcp)
console.log('LCP', relFiles)
return Promise.resolve(`console.log('hello world')`)
}
function relativize (files, lcp) {
const result = {}
for(const absPath in files) {
const relPath = '.' + path.sep + path.relative(lcp, absPath)
const file = files[absPath]
file.relPath = relPath
result[relPath] = file
}
return result
}
function findLcp(paths, sep = path.sep) {
let position, first = paths[0] || ''
findPosition: {
for (position = 0;; position++) {
for (let i = 0; i < paths.length; i++) {
if (paths[i][position] && paths[i][position] === first[position])
continue
while (position > 0 && first[--position] !== sep) {}
break findPosition
}
}
}
return first.slice(0, position)
}
+126
View File
@@ -0,0 +1,126 @@
{
"name": "dynamic-modules",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"circular-json": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.1.tgz",
"integrity": "sha512-UjgcRlTAhAkLeXmDe2wK7ktwy/tgAqxiSndTIPiFZuIPLZmzHzWMwUIe9h9m/OokypG7snxCDEuwJshGBdPvaw=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.8"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1.0.2"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-parse": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
},
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
"requires": {
"resolve": "1.5.0"
}
},
"resolve": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
"integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==",
"requires": {
"path-parse": "1.0.5"
}
},
"shelljs": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.1.tgz",
"integrity": "sha512-YA/iYtZpzFe5HyWVGrb02FjPxc4EMCfpoU/Phg9fQoyMC72u9598OUBrsU8IrtwAKG0tO8IYaqbaLIw+k3IRGA==",
"requires": {
"glob": "7.1.2",
"interpret": "1.1.0",
"rechoir": "0.6.2"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"name": "dynamic-modules",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"circular-json": "^0.5.1",
"shelljs": "^0.8.1"
}
}
+3 -1
View File
@@ -10,7 +10,9 @@ if (require.main === module) {
process.stderr.write(showHelp ? options.help : options.version + eol)
} else {
const nexe = require('./lib/nexe')
nexe.compile(argv)
nexe.compile(argv).catch(() => {
process.exit(1)
})
}
} else {
module.exports = require('./lib/nexe')
+2112
View File
File diff suppressed because it is too large Load Diff
+29 -31
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-rc.34",
"version": "2.0.0-next.10",
"contributors": [
"Craig Condon <craig.j.condon@gmail.com> (http://crcn.io)",
"Jared Allard <jaredallard@outlook.com>",
@@ -11,10 +11,9 @@
"scripts": {
"asset-compile": "ts-node tasks/asset-compile",
"test": "mocha",
"fmt": "prettier --parser typescript --no-semi --print-width 100 --single-quote --write \"{src,plugins,tasks}/**/*.ts\"",
"prepare": "npm run build",
"prepublishOnly": "npm test",
"prebuild": "rimraf lib && npm run fmt",
"lint": "tslint \"{src,plugins,tasks}/**/*.ts\" --fix",
"prepublishOnly": "npm run lint && npm run build && npm test",
"prebuild": "rimraf lib",
"build": "tsc --declaration",
"postbuild": "ts-node tasks/post-build"
},
@@ -23,8 +22,7 @@
"url": "git://github.com/nexe/nexe.git"
},
"files": [
"lib",
"source-map-support.js"
"lib"
],
"typings": "lib/nexe.d.ts",
"main": "index.js",
@@ -35,37 +33,37 @@
"node": ">=6"
},
"dependencies": {
"app-builder": "^5.1.0",
"typescript": "2.5.3",
"app-builder": "^5.2.0",
"caw": "^2.0.1",
"chalk": "^1.1.3",
"download": "^6.2.0",
"fuse-box": "^3.1.0",
"globby": "^6.1.0",
"got": "^8.0.3",
"chalk": "^2.3.2",
"download": "^6.2.5",
"globby": "^8.0.1",
"got": "^8.3.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"ora": "^1.2.0",
"ora": "^2.0.0",
"pify": "^3.0.0",
"rimraf": "^2.6.1",
"uglify-es": "^3.3.9",
"uglify-js": "3.0.28"
"resolve-dependencies": "^1.1.0",
"rimraf": "^2.6.2"
},
"devDependencies": {
"@types/chai": "^4.0.4",
"@types/chalk": "^0.4.31",
"@types/execa": "^0.7.0",
"@types/globby": "^0.6.0",
"@types/chai": "^4.1.2",
"@types/execa": "^0.8.1",
"@types/globby": "^6.1.0",
"@types/minimist": "^1.2.0",
"@types/mkdirp": "^0.3.29",
"@types/mocha": "^2.2.42",
"@types/ora": "^0.3.31",
"@types/pify": "0.0.28",
"@types/rimraf": "0.0.28",
"@types/mkdirp": "^0.5.2",
"@types/mocha": "^2.2.48",
"@types/ora": "^1.3.1",
"@types/pify": "3.0.0",
"@types/rimraf": "2.0.2",
"chai": "^4.1.2",
"execa": "^0.8.0",
"mocha": "^3.5.0",
"prettier": "^1.6.1",
"ts-node": "3.3.0"
"execa": "^0.9.0",
"mocha": "^5.0.0",
"prettier": "^1.10.2",
"ts-node": "4.1.0",
"tslint": "^5.9.1",
"tslint-config-prettier": "^1.7.0",
"tslint-plugin-prettier": "^1.3.0",
"typescript": "2.7.1"
}
}
File diff suppressed because one or more lines are too long
-70
View File
@@ -1,70 +0,0 @@
import { BindingsRewrite } from './bindings-rewrite'
import { embedDotNode, EmbedNodeModuleOptions } from './embed-node'
export interface FuseBoxFile {
info: { absPath: string }
absPath: string
contents: string
analysis: {
dependencies: string[]
requiresRegeneration: boolean
}
consume(): void
loadContents(): void
makeAnalysis(
parsingOptions?: any,
traversalPlugin?: {
plugins: Array<{
onNode(file: FuseBoxFile, node: any, parent: any): void
onEnd(file: FuseBoxFile): void
}>
}
): void
}
export default function(options: EmbedNodeModuleOptions = {}) {
return new NativeModulePlugin(options)
}
export class NativeModulePlugin {
public test = /node_modules.*(\.js|\.node)$|\.node$/
public limit2Project = false
private modules: (keyof EmbedNodeModuleOptions)[]
constructor(public options = {}) {}
init(context: any) {
context.allowExtension('.node')
}
transform(file: FuseBoxFile) {
file.loadContents()
if (file.absPath.endsWith('.node')) {
embedDotNode(this.options, file)
return
}
const bindingsRewrite = new BindingsRewrite()
file.makeAnalysis(null, {
plugins: [
{
onNode(file, node, parent) {
bindingsRewrite.onNode(file.absPath, node, parent)
},
onEnd(file) {
if (bindingsRewrite.rewrite) {
const index = file.analysis.dependencies.indexOf('bindings')
if (~index) {
file.analysis.dependencies.splice(index, 1)
}
file.analysis.dependencies.push(...bindingsRewrite.nativeModulePaths)
file.analysis.requiresRegeneration = true
}
}
}
]
})
}
}
-1
View File
@@ -1 +0,0 @@
export * from './fuse-native-module-plugin'
-1
View File
@@ -1 +0,0 @@
//TODO
+11 -28
View File
@@ -29,15 +29,15 @@ interface NexeHeader {
version: string
}
export class NexeCompiler<T extends NexeOptions = NexeOptions> {
export class NexeCompiler {
private start = Date.now()
private env: any
private compileStep: LogStep
private env = { ...process.env }
private compileStep: LogStep | undefined
public log = new Logger(this.options.loglevel)
public src: string
public files: NexeFile[] = []
public shims: string[] = []
public input: string
public input: string | undefined
public bundledInput?: string
public targets: NexeTarget[]
public target: NexeTarget
@@ -47,7 +47,7 @@ export class NexeCompiler<T extends NexeOptions = NexeOptions> {
}
public output = this.options.output
private nodeSrcBinPath: string
constructor(public options: T) {
constructor(public options: NexeOptions) {
const { python } = (this.options = options)
this.targets = options.targets as NexeTarget[]
this.target = this.targets[0]
@@ -136,7 +136,7 @@ export class NexeCompiler<T extends NexeOptions = NexeOptions> {
private _runBuildCommandAsync(command: string, args: string[]) {
if (this.log.verbose) {
this.compileStep.pause()
this.compileStep!.pause()
}
return new Promise((resolve, reject) => {
spawn(command, args, {
@@ -146,13 +146,13 @@ export class NexeCompiler<T extends NexeOptions = NexeOptions> {
})
.once('error', (e: Error) => {
if (this.log.verbose) {
this.compileStep.resume()
this.compileStep!.resume()
}
reject(e)
})
.once('close', (code: number) => {
if (this.log.verbose) {
this.compileStep.resume()
this.compileStep!.resume()
}
if (code != 0) {
const error = `${command} ${args.join(' ')} exited with code: ${code}`
@@ -171,14 +171,14 @@ export class NexeCompiler<T extends NexeOptions = NexeOptions> {
}
private async _buildAsync() {
this.compileStep.log(
this.compileStep!.log(
`Configuring node build${
this.options.configure.length ? ': ' + this.options.configure : '...'
}`
)
await this._configureAsync()
const buildOptions = this.options.make
this.compileStep.log(
this.compileStep!.log(
`Compiling Node${buildOptions.length ? ' with arguments: ' + buildOptions : '...'}`
)
await this._runBuildCommandAsync(make, buildOptions)
@@ -211,30 +211,13 @@ export class NexeCompiler<T extends NexeOptions = NexeOptions> {
let current = 0
res.on('data', data => {
current += data.length
this.compileStep.modify(`Downloading...${(current / total * 100).toFixed()}%`)
this.compileStep!.modify(`Downloading...${(current / total * 100).toFixed()}%`)
})
}
)
return createReadStream(filename)
}
getHeader() {
const version =
['configure', 'vcBuild', 'make'].reduce((a, c) => {
return (a += (this.options as any)[c]
.slice()
.sort()
.join())
}, '') + this.options.enableNodeCli
const header = {
resources: this.resources.index,
version: createHash('md5')
.update(version)
.digest('hex')
}
return `process.__nexe=${JSON.stringify(header)};`
}
async compileAsync(target: NexeTarget) {
const step = (this.compileStep = this.log.step('Compiling result'))
const build = this.options.build
+14 -19
View File
@@ -1,10 +1,10 @@
import { EOL } from 'os'
import { compose, Middleware } from 'app-builder'
import { rimrafAsync } from './util'
import { NexeTarget } from './target'
import { NexeCompiler } from './compiler'
import { normalizeOptions, NexeOptions, NexePatch } from './options'
import resource from './steps/resource'
import clean from './steps/clean'
import cli from './steps/cli'
import bundle from './steps/bundle'
import download from './steps/download'
@@ -18,26 +18,19 @@ async function compile(
) {
const options = normalizeOptions(compilerOptions)
const compiler = new NexeCompiler(options)
const build = compiler.options.build
const build = options.build
if (options.clean) {
let path = compiler.src
if (!options.build) {
path = compiler.getNodeExecutableLocation(compiler.options.targets[0] as NexeTarget)
}
const step = compiler.log.step('Cleaning up nexe build artifacts...')
step.log(`Deleting contents at: ${path}`)
await rimrafAsync(path)
step.log(`Deleted contents at: ${path}`)
return compiler.quit()
}
const nexe = compose(
clean,
resource,
bundle,
shim,
cli,
options.build ? [download, artifacts, ...patches, ...(options.patches as NexePatch[])] : [],
options.plugins as NexePatch[]
)
const buildSteps = build
? [download, artifacts, ...patches, ...(options.patches as NexePatch[])]
: []
const nexe = compose(resource, bundle, shim, cli, buildSteps, options.plugins as NexePatch[])
let error = null
try {
await nexe(compiler)
} catch (e) {
@@ -46,12 +39,14 @@ async function compile(
if (error) {
if (compiler.options.loglevel !== 'silent' && error) {
process.stderr.write(EOL + error.stack + EOL)
console.log(error)
process.stderr.write(EOL + error.message + EOL)
}
compiler.quit()
if (callback) return callback(error)
return Promise.reject(error)
}
if (callback) callback(null)
}
+10 -8
View File
@@ -4,8 +4,7 @@ import { isWindows, padRight } from './util'
import { basename, extname, join, isAbsolute, relative, dirname, resolve } from 'path'
import { getTarget, NexeTarget } from './target'
import { EOL, homedir } from 'os'
import * as c from 'chalk'
import c from 'chalk'
const caw = require('caw')
export const version = '{{replace:0}}'
@@ -140,12 +139,15 @@ function flatten(...args: any[]): string[] {
function extractCliMap(match: RegExp, options: any) {
return Object.keys(options)
.filter(x => match.test(x))
.reduce((map: { [key: string]: string }, option: keyof NexeOptions) => {
const key = option.split('-')[1]
map[key] = options[option]
delete options[option]
return map
}, {})
.reduce(
(map: any, option: any) => {
const key = option.split('-')[1]
map[key] = options[option]
delete options[option]
return map
},
{} as any
)
}
function tryResolveMainFileName(cwd: string) {
+1 -1
View File
@@ -1,7 +1,7 @@
const fs = require('fs')
const fd = fs.openSync(process.execPath, 'r')
const stat = fs.statSync(process.execPath)
const footer = Buffer.from(Array(32))
const footer = Buffer.alloc(32, 0)
fs.readSync(fd, footer, 0, 32, stat.size - 32)
+17
View File
@@ -0,0 +1,17 @@
//add placeholder patches so methods can be monkeypatched after being dereferenced
const __nexe_patches = ((process as any).nexe = { patches: {} }).patches as any
function __nexe_noop_patch(this: any, original: any, ...args: any[]) {
return original.call(this, ...args)
}
function __nexe_patch(obj: any, method: string, patch: any) {
__nexe_patches[method] = patch
const original = obj[method]
obj[method] = function(this: any, ...args: any[]) {
return __nexe_patches[method].call(this, original, ...args)
}
}
__nexe_patch((process as any).binding('fs'), 'internalModuleReadFile', __nexe_noop_patch)
__nexe_patch((process as any).binding('fs'), 'internalModuleStat', __nexe_noop_patch)
+6
View File
@@ -1,8 +1,14 @@
import { NexeCompiler } from '../compiler'
import { readFileSync } from 'fs'
import { join } from 'path'
import { wrap } from '../util'
export default async function main(compiler: NexeCompiler, next: () => Promise<void>) {
const file = await compiler.readFileAsync('lib/internal/bootstrap_node.js')
const parts = file.contents.split('function(process) {')
file.contents =
parts[0] + `function(process) {` + '{{replace:lib/patches/bootstrap.js}}' + parts[1]
await compiler.setFileContentsAsync(
'lib/_third_party_main.js',
'{{replace:lib/patches/boot-nexe.js}}'
+1 -1
View File
@@ -59,7 +59,7 @@ export async function getUnBuiltReleases(options?: any) {
platforms.forEach(platform => {
architectures.forEach(arch => {
if (arch === 'x86' && platform === 'mac') return
if (arch === 'arm71' && platform !== 'linux') return
if (arch === 'arm7l' && platform !== 'linux') return
versions.push(getTarget({ platform, arch, version }))
})
})
-1
View File
@@ -39,7 +39,6 @@ function maybeReadFileContentsAsync(file: string) {
* - After the patch functions have run, the temporary directory is emptied
* - Original versions of sources to be patched are written to the temporary directory
* - Finally, The patched files are written into source.
*
*/
export default async function artifacts(compiler: NexeCompiler, next: () => Promise<void>) {
const { src } = compiler
+20 -35
View File
@@ -1,39 +1,23 @@
import { NexeCompiler } from '../compiler'
import { readFileAsync, writeFileAsync } from '../util'
import { resolve, relative } from 'path'
import NativeModulePlugin from '../bundling/fuse-native-module-plugin'
import { NexeOptions } from '../options'
import resolveFiles from 'resolve-dependencies'
function createBundle(options: NexeOptions) {
const { FuseBox, JSONPlugin, CSSPlugin, HTMLPlugin, QuantumPlugin } = require('fuse-box')
const plugins: any = [JSONPlugin(), CSSPlugin(), HTMLPlugin(), NativeModulePlugin(options.native)]
if (options.compress) {
plugins.push(
QuantumPlugin({
target: 'server@esnext',
uglify: true,
bakeApiIntoBundle: options.name
})
)
}
const cwd = options.cwd
const fuse = FuseBox.init({
cache: false,
log: Boolean(process.env.NEXE_BUNDLE_LOG) || false,
homeDir: cwd,
sourceMaps: false,
writeBundles: false,
output: '$name.js',
target: 'server@esnext', //try not to transpile
plugins
})
const input = relative(cwd, resolve(cwd, options.input)).replace(/\\/g, '/')
fuse.bundle(options.name).instructions(`> ${input}`)
return fuse.run().then((x: any) => {
let output = ''
x.bundles.forEach((y: any) => (output = y.context.output.lastPrimaryOutput.content.toString()))
return output
function makeRelative(cwd: string, path: string) {
return './' + relative(cwd, path)
}
let producer = async function(compiler: NexeCompiler) {
const { cwd, input } = compiler.options
const { files } = await resolveFiles({ entries: [compiler.options.input], cwd })
Object.keys(files).forEach(x => {
const file = files[x]!
if (file) {
compiler.addResource(makeRelative(cwd, x), Buffer.from(file.contents))
}
})
return Promise.resolve('require(' + JSON.stringify(makeRelative(cwd, input)) + ')')
}
export default async function bundle(compiler: NexeCompiler, next: any) {
@@ -43,20 +27,21 @@ export default async function bundle(compiler: NexeCompiler, next: any) {
return next()
}
if (compiler.options.empty || !compiler.options.input) {
if (!input) {
compiler.input = ''
return next()
}
let producer = createBundle
if (typeof bundle === 'string') {
producer = require(resolve(cwd, bundle)).createBundle
}
compiler.input = await producer(compiler.options)
compiler.input = await producer(compiler)
const debugBundle = compiler.options.debugBundle
if ('string' === typeof compiler.options.debugBundle) {
await writeFileAsync(resolve(cwd, compiler.options.debugBundle), compiler.input)
if (debugBundle) {
let bundleDebugFile = typeof debugBundle === 'string' ? debugBundle : 'nexe-debug.bundle.js'
await writeFileAsync(resolve(cwd, bundleDebugFile), compiler.input)
}
return next()
+19
View File
@@ -0,0 +1,19 @@
import { NexeCompiler } from '../compiler'
import { rimrafAsync } from '../util'
import { NexeTarget } from '../target'
export default async function clean(compiler: NexeCompiler, next: () => Promise<any>) {
const { options } = compiler
if (options.clean) {
let path = compiler.src
if (!options.build) {
path = compiler.getNodeExecutableLocation(compiler.options.targets[0] as NexeTarget)
}
const step = compiler.log.step('Cleaning up nexe build artifacts...')
step.log(`Deleting contents at: ${path}`)
await rimrafAsync(path)
step.log(`Deleted contents at: ${path}`)
return compiler.quit()
}
return next()
}
+3 -2
View File
@@ -3,15 +3,16 @@ import { Buffer } from 'buffer'
import * as globs from 'globby'
import { NexeCompiler } from '../compiler'
export default async function resource(compiler: NexeCompiler, next: () => Promise<void>) {
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()
}
const step = compiler.log.step('Bundling Resources...')
let count = 0
await each(globs(compiler.options.resources), async file => {
await each(globs(compiler.options.resources, { cwd }), async file => {
if (await isDirectoryAsync(file)) {
return
}
+23
View File
@@ -256,6 +256,29 @@ const nfs: any = {
}
}
}
const patches = (process as any).nexe.patches
delete (process as any).nexe
patches.internalModuleReadFile = function(this: any, original: any, ...args: any[]) {
const [filepath] = args
setupManifest()
if (manifest[filepath]) {
return nfs.readFileSync(filepath, 'utf-8')
}
return original.call(this, ...args)
}
patches.internalModuleStat = function(this: any, original: any, ...args: any[]) {
setupManifest()
const [filepath] = args
if (manifest[filepath]) {
return 0
}
if (directories[filepath]) {
return 1
}
return original.call(this, ...args)
}
Object.assign(fs, nfs)
if (typeof fs.exists === 'function') {
nfs.exists = function(filepath: string, cb: Function) {
+12 -15
View File
@@ -1,12 +1,12 @@
import { NexeCompiler } from '../compiler'
function wrap(code: string) {
return '!(function () {' + code + '})();'
}
import { relative } from 'path'
import { wrap } from '../util'
export default function(compiler: NexeCompiler, next: () => Promise<void>) {
compiler.shims.push(wrap(compiler.getHeader()))
compiler.shims.push(
wrap(`process.__nexe=${JSON.stringify({ resources: compiler.resources.index })};`)
)
compiler.shims.push(wrap('{{replace:lib/steps/shim-fs.js}}'))
compiler.shims.push(
wrap(`
if (process.argv[1] && process.env.NODE_UNIQUE_ID) {
@@ -17,19 +17,16 @@ export default function(compiler: NexeCompiler, next: () => Promise<void>) {
`)
)
if (compiler.options.resources.length) {
compiler.shims.push(wrap('{{replace:lib/steps/shim-fs.js}}'))
}
//compiler.shims.push(wrap('{/{replace:lib/steps/shim-require.js}}'))
if (compiler.options.fakeArgv !== false) {
const nty = !process.stdin.isTTY
const input = nty ? '[stdin]' : JSON.stringify(compiler.options.input)
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})`});`)
var r = require('path').resolve;
process.argv.splice(1,0, ${nty ? `'${input}'` : `r(${input})`});`)
)
}
+6 -6
View File
@@ -1,8 +1,8 @@
export type NodePlatform = 'windows' | 'mac' | 'alpine' | 'linux'
export type NodeArch = 'x86' | 'x64' | 'arm71'
export type NodeArch = 'x86' | 'x64' | 'arm7l' | 'arm6'
const platforms: NodePlatform[] = ['windows', 'mac', 'alpine', 'linux'],
architectures: NodeArch[] = ['x86', 'x64', 'arm71']
architectures: NodeArch[] = ['x86', 'x64', 'arm7l', 'arm6']
export { platforms, architectures }
@@ -25,12 +25,12 @@ const prettyPlatform: { [key: string]: NodePlatform } = {
alpine: 'alpine'
}
//TODO arm
const prettyArch: { [key: string]: NodeArch } = {
x86: 'x86',
arm: 'arm71',
arm7: 'arm71',
arm71: 'arm71',
arm6: 'arm6',
arm: 'arm7l',
arm7: 'arm7l',
arm7l: 'arm7l',
amd64: 'x64',
ia32: 'x86',
x32: 'x86',
+2 -2
View File
@@ -3,8 +3,8 @@ declare module 'got' {
(url: string, options?: any): Promise<{ body: string }>
stream(url: string, optoins?: any): any
}
function got(url: string, options?: any): Promise<{ body: string }>
export = got as GotFn
const got: GotFn
export = got
}
declare module 'download' {
import { Duplex } from 'stream'
+11 -5
View File
@@ -10,9 +10,11 @@ export async function each<T>(
action: (item: T, index: number, list: T[]) => Promise<any>
) {
const l = await list
for (let i = 0; i < l.length; i++) {
await action(l[i], i, l)
}
return Promise.all(l.map(action))
}
export function wrap(code: string) {
return '!(function () {' + code + '})();'
}
function falseOnEnoent(e: any) {
@@ -28,7 +30,7 @@ function padRight(str: string, l: number) {
const bound: MethodDecorator = function bound<T>(
target: Object,
propertyKey: string,
propertyKey: string | Symbol,
descriptor: TypedPropertyDescriptor<T>
) {
const configurable = true
@@ -36,7 +38,11 @@ const bound: MethodDecorator = function bound<T>(
configurable,
get(this: T) {
const value = (descriptor.value as any).bind(this)
Object.defineProperty(this, propertyKey, { configurable, value, writable: true })
Object.defineProperty(this, propertyKey as string, {
configurable,
value,
writable: true
})
return value
}
}
+3 -3
View File
@@ -1,7 +1,7 @@
import * as nexe from '../lib/nexe'
import { getUnBuiltReleases, getLatestGitRelease } from '../lib/releases'
import * as ci from './ci'
import { runAlpineBuild } from './docker'
import { runDockerBuild } from './docker'
import { getTarget } from '../lib/target'
import { pathExistsAsync, statAsync, readFileAsync, execFileAsync } from '../lib/util'
import got = require('got')
@@ -62,8 +62,8 @@ async function build() {
}
console.log('Building: ', target)
const stop = keepalive()
if (target.platform === 'alpine') {
await runAlpineBuild(target)
if (['arm71', 'alpine'].indexOf(target.platform)) {
await runDockerBuild(target)
} else {
await nexe.compile(options)
}
+19 -6
View File
@@ -1,4 +1,4 @@
import { NexeTarget } from '../lib/target'
import { NexeTarget, architectures } from '../lib/target'
import { writeFileAsync, readFileAsync } from '../lib/util'
import { spawn } from 'child_process'
import got = require('got')
@@ -26,15 +26,28 @@ RUN rm /nexe_temp/\${NODE_VERSION}/out/Release/node && \
`.trim()
}
export async function runAlpineBuild(target: NexeTarget) {
await writeFileAsync('Dockerfile', alpine(target))
const outFilename = 'nexe-alpine-build-log.txt'
function arm(target: NexeTarget) {
return `
FROM hypriot/rpi-node
ENV NEXE_VERSION=beta
WORKDIR /
RUN yarn global add nexe@\${NEXE_VERSION} && \
nexe --build --empty -o out -t ${target.version}
`.trim()
}
export async function runDockerBuild(target: NexeTarget) {
//todo switch on alpine and arm
const dockerfile = alpine(target)
await writeFileAsync('Dockerfile', dockerfile)
const outFilename = 'nexe-docker-build-log.txt'
await writeFileAsync(outFilename, '')
let output: any = []
try {
output.push(await execa.shell(`docker build -t nexe-alpine .`))
output.push(await execa.shell(`docker run -d --name nexe nexe-alpine sh`))
output.push(await execa.shell(`docker build -t nexe-docker .`))
output.push(await execa.shell(`docker run -d --name nexe nexe-docker sh`))
output.push(await execa.shell(`docker cp nexe:/out out`))
output.push(await execa.shell(`docker rm nexe`))
} catch (e) {
+5 -5
View File
@@ -8,7 +8,7 @@ describe('options', () => {
describe('cwd', () => {
it('should use process.cwd() if nothing is provided', () => {
const options = normalizeOptions()
expect(options.cwd).to.equal(process.cwd())
expect(options.cwd).to.equal(process.cwd())
})
it('should use the main module in a package directory', () => {
const options = normalizeOptions()
@@ -16,11 +16,11 @@ describe('options', () => {
})
it('should resolve pathed options against cwd', () => {
const cwd = '/a/b/c'
const options = normalizeOptions({
cwd,
const options = normalizeOptions({
cwd,
input: '123.js',
output: 'abc',
temp: './d'
temp: './d'
})
expect(options.temp).to.equal(path.resolve(cwd, './d'))
expect(options.input).to.equal(path.resolve(cwd, '123.js'))
@@ -39,7 +39,7 @@ describe('options', () => {
input: 'src/folder/app.js'
})
expect(options.output).to.equal(path.resolve(`./app${ext}`))
})
})
it('should default to the folder/project name if filename is index', () => {
const options = normalizeOptions()
expect(options.output).to.equal(path.resolve(`./nexe${ext}`))
+2 -3
View File
@@ -6,7 +6,7 @@ import { getTarget, NexeTarget } from '../src/target'
const arch = process.arch === 'ia32' ? 'x86' : process.arch
describe('Targets', () => {
[
;[
['win-ia32-6.11.2', 'windows-x86-6.11.2'],
[{ version: '6.11.2', platform: 'win', arch: 'ia32' }, 'windows-x86-6.11.2'],
['win32-x64-6.11.2', 'windows-x64-6.11.2'],
@@ -23,8 +23,7 @@ describe('Targets', () => {
})
})
it ('should stringify and toString', () => {
it('should stringify and toString', () => {
expect(JSON.stringify(getTarget(process))).to.equal(`"${getTarget(process)}"`)
})
})
+9
View File
@@ -0,0 +1,9 @@
{
"rulesDirectory": ["tslint-plugin-prettier", "tslint-config-prettier"],
"linterOptions": {
"exclude": ["**/node_modules/**/*"]
},
"rules": {
"prettier": [true, { "semi": false, "printWidth": 100, "singleQuote": true }]
}
}
-3078
View File
File diff suppressed because it is too large Load Diff