Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 85 additions & 22 deletions bin/tmc
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,42 @@ const { compile, archive, unpack, load } = require('../')
const { version } = require('../package.json')
const prettyBytes = require('pretty-bytes')
const minimist = require('minimist')
const mirror = require('mirror-folder')
const mkdirp = require('mkdirp')
const Batch = require('batch')
const debug = require('debug')('tiny-module-compiler')
const path = require('path')
const copy = require('cp-file')
const glob = require('glob')
const fs = require('fs')
const os = require('os')

const PACKAGE_JSON = 'package.json'
const NODE_MODULES = 'node_modules'

const usage = `usage: tmc [-hV] [-acu] [-vCDMOS] [options] ...input
where options can be:

-a, --archive If present, will archive input into "tinybox" format
-c, --compile If present, will compile input into header prefixed v8 cached data
, --concurrency <jobs> An alias for '--jobs'
-C, --copy-assets If present, will copy assets to directory of output
-D, --debug If present, will enable debug output (DEBUG=tiny-module-compiler)
-e, --external <module> Specifies an external dependency that will be linked at runtime
-h, --help If present, will print this message
-l, --load If present, will load inputs
-j, --jobs <jobs> Specifies the number of concurrent jobs for batch tasks (--load, --archive, --copy-assets)
-M, --source-map If present, a source map will be generated
-o, --output <path> If present, will change the output path. Assumes directory if multiple inputs given
-O, --optimize If present, will optimize output by minifying JavaScript source prior to compilation
-u, --unpack If present, will treat input as an archive and will unpack files to path specified by '--output'
-v, --verbose If present, will emit verbose output to stdout/stderr
-V, --version If present, will print the version number
-x An alias for '--external'
`.trim()

const argv = minimist(process.argv.slice(2), {
'--': true,
boolean: [
'archive',
'compile',
Expand All @@ -22,12 +49,14 @@ const argv = minimist(process.argv.slice(2), {
'load',
'optimize',
'source-map',
'strict',
'unpack',
'verbose',
'version',
],

string: [
'cwd',
'output'
],

Expand All @@ -52,34 +81,20 @@ const argv = minimist(process.argv.slice(2), {
M: 'source-map',
O: 'optimize',
o: 'output',
S: 'strict',
u: 'unpack',
v: 'verbose',
V: 'version',
x: 'external',
},

unknown(arg) {
console.error('error: unknown option: %s', arg)
process.nextTick(() => process.exit(1))
return false
}
})

const usage = `usage: tmc [-hV] [-acu] [-vCDMO] [options] ...input
where options can be:

-a, --archive If present, will archive input into "tinybox" format
-c, --compile If present, will compile input into header prefixed v8 cached data
, --concurrency <jobs> An alias for '--jobs'
-C, --copy-assets If present, will copy assets to directory of output
-D, --debug If present, will enable debug output (DEBUG=tiny-module-compiler)
-e, --external <module> Specifies an external dependency that will be linked at runtime
-h, --help If present, will print this message
-l, --load If present, will load inputs
-j, --jobs <jobs> Specifies the number of concurrent jobs for batch tasks (--load, --archive, --copy-assets)
-M, --source-map If present, a source map will be generated
-o, --output <path> If present, will change the output path. Assumes directory if multiple inputs given
-O, --optimize If present, will optimize output by minifying JavaScript source prior to compilation
-u, --unpack If present, will treat input as an archive and will unpack files to path specified by '--output'
-v, --verbose If present, will emit verbose output to stdout/stderr
-V, --version If present, will print the version number
-x An alias for '--external'
`.trim()

if (argv.version) {
console.log(version)
process.exit(0)
Expand Down Expand Up @@ -129,7 +144,7 @@ if (argv.compile || (!argv.archive && !argv.unpack && !argv.load)) { // default
}
}

compile(argv._, opts, (err, objects, assets) => {
compile(argv._, opts, (err, _, assets) => {
if (err) {
console.error('error:', err.message)
debug(err)
Expand All @@ -151,6 +166,54 @@ if (argv.compile || (!argv.archive && !argv.unpack && !argv.load)) { // default
})
}

for (const external of opts.externals) {
writes.push((next) => {
try {
const modulePackagePathName = external + path.sep + PACKAGE_JSON
const modulePackagePath = require.resolve(modulePackagePathName)
const modulePath = path.dirname(modulePackagePath)

const cwd = argv.cwd || process.cwd()
const src = modulePath
const dst = cwd + path.sep + NODE_MODULES + path.sep + external

mkdirp.sync(path.dirname(dst))
mirror(src, dst, { ensureParents: true }, next)

} catch (err) {
try {
const cwd = argv.cwd || process.cwd()
const stats = fs.statSync(external)
if (stats && stats.isFile()) {
return copy(external, path.resolve(cwd, path.basename(external)))
.then(() => next(), (err) => next(err))
} else if (stats && stats.isDirectory()) {
mkdirp.sync(path.join(cwd, path.basename(external)))
return mirror(
external,
path.join(cwd, path.basename(external)),
{ ensureParents: true },
next)
}
} catch (err) {
debug(err)
if (argv.strict) {
return next(err)
}
}

debug(err)
if (argv.strict) {
return next(err)
}

console.warn(' warn: failed to copy external dependency asset:%s', external)
next(null)
}
})

}

writes.end((err) => {
if (err) {
console.error('error:', err.message)
Expand Down
5 changes: 2 additions & 3 deletions compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const magic = require('./magic')
const ready = require('nanoresource-ready')
const path = require('path')
const raf = require('random-access-file')
const ncc = require('@zeit/ncc')
const ncc = require('@vercel/ncc')
const vm = require('vm')

// quick util
Expand Down Expand Up @@ -134,7 +134,7 @@ class Compiler extends Pool {
opts = {}
}

const { targets } = this
const { targets, cwd } = this
const objects = new Map()
const assets = new Map()
const writes = new Batch()
Expand All @@ -143,7 +143,6 @@ class Compiler extends Pool {
try {
for (const target of targets) {
const { filename } = target
const extname = path.extname(filename)
const basename = path.basename(filename)
const targetName = path.resolve(target.output)
.replace(path.join(path.resolve(this.cwd), path.sep), '')
Expand Down
39 changes: 37 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,44 @@ const { load } = require('./load')
/**
* Module exports.
*/
module.exports = {
module.exports = Object.create({
archive,
compile,
unpack,
load,
}

/**
* Imports a module at path returning its exports object.
* @param {String} pathspec
* @param {?(Object)} opts
* @param {?(Map)} opts.cache
* @param {?(String)} opts.cwd
* @param {?(Object)} opts.storage
* @param {Function} callback
* @return {Object}
*/
async import(pathspec, opts) {
return await new Promise((resolve, reject) => {
try {
const target = load(pathspec, opts, (err, exports) => {
// istanbul ignore next
if (err) {
// istanbul ignore next
return reject(err)
}

// istanbul ignore next
Object.defineProperty(exports, '__target__', {
enumerable: false,
get: () => target
})

resolve(exports)
})
} catch (err) {
// istanbul ignore next
return reject(err)
}
})
}
})
1 change: 1 addition & 0 deletions loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class Loader extends Pool {

// istanbul ignore next
const createRequireFromPath = Module.createRequire || Module.createRequireFromPath
// istanbul ignore next
const contextRequire = 'function' === typeof createRequireFromPath
? createRequireFromPath(filename)
: makeRequireFunction(contextModule)
Expand Down
21 changes: 12 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tiny-module-compiler",
"version": "1.2.2",
"version": "1.3.1",
"description": "Compile, archive, unpack, and load compiled modules leveraging v8 cached data.",
"main": "index.js",
"scripts": {
Expand All @@ -27,13 +27,15 @@
"author": "Joseph Werle <[email protected]>",
"license": "MIT",
"dependencies": {
"@zeit/ncc": "^0.20.5",
"@vercel/ncc": "^0.31.1",
"batch": "^0.6.1",
"cp-file": "^9.1.0",
"debug": "^4.1.1",
"glob": "^7.1.5",
"isutf8": "^2.1.0",
"isutf8": "^4.0.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"mirror-folder": "^3.1.0",
"mkdirp": "^1.0.4",
"nanoassert": "^2.0.0",
"nanoresource": "^1.2.0",
"nanoresource-pool": "^0.3.1",
Expand All @@ -42,18 +44,19 @@
"protocol-buffers": "^4.1.0",
"random-access-file": "^2.1.3",
"rimraf": "^3.0.0",
"semver": "^6.3.0",
"semver": "^7.3.5",
"tinybox": "0.0.0",
"uint64be": "^2.0.2",
"varint": "^5.0.0"
"uint64be": "^3.0.0",
"varint": "^6.0.0"
},
"directories": {
"test": "test"
},
"devDependencies": {
"nyc": "^14.1.1",
"nyc": "^15.1.0",
"random-access-memory": "^3.1.1",
"tape": "^4.11.0"
"sodium-universal": "^3.0.4",
"tape": "^5.3.1"
},
"repository": {
"type": "git",
Expand Down
26 changes: 26 additions & 0 deletions test/import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const path = require('path')
const test = require('tape')

const { compile, import: _import } = require('../')

test('load(target, callback) - source module', async (t) => {
const filename = path.resolve(__dirname, 'fixtures', 'simple.js')
const { hello } = await _import(filename)
t.equal('function', typeof hello, 'hello')
t.equal('hello', hello(), 'hello()')
})

test('load(target, callback) - compiled module', async (t) => {
const filename = path.resolve(__dirname, 'fixtures', 'simple.js')
const destname = filename.replace(process.cwd() + path.sep, '') + '.out'

await new Promise((resolve, reject) => compile(filename, (err) => {
if (err) { return reject(err) }
resolve()
}))

const { hello } = await _import(destname)

t.equal('function', typeof hello, 'hello')
t.equal('hello', hello(), 'hello()')
})
4 changes: 4 additions & 0 deletions test/unpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ test('unpack(target, callback)', (t) => {
const target = filename + '.a'
const cwd = process.cwd()
compile(filename, (err, objects) => {
t.error(err)
archive(target, objects, (err) => {
t.error(err)
unpack(target, (err, entries) => {
t.error(err)
t.ok(Array.isArray(entries), 'entries')
Expand All @@ -28,7 +30,9 @@ test('unpack(target, callback) - from storage', (t) => {
const target = filename + '.a'
const cwd = process.cwd()
compile(filename, { storag: ram }, (err, objects) => {
t.error(err)
archive(target, objects, { storage }, (err) => {
t.error(err)
unpack(storage, { storage: ram }, (err, entries) => {
t.error(err)
t.ok(Array.isArray(entries), 'entries')
Expand Down
6 changes: 3 additions & 3 deletions unpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ function unpack(target, opts, callback) {

if (!hasCustomStorage) {
const dirname = path.dirname(filename)
return mkdirp(dirname, (err) => {
// istanbul ignore next
if (err) { return next(err) }
const promise = mkdirp(dirname)
promise.catch((err) => next(err))
return promise.then(() => {
write(raf(filename), buffer, (err) => {
// istanbul ignore next
if (err) { return next(err) }
Expand Down