Skip to content

Commit

Permalink
many fixes and examples
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdesl committed Jan 19, 2016
1 parent 50365f6 commit 2db47d4
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 36 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
*.log
.DS_Store
bundle.js
example/streetview.png
115 changes: 103 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,57 @@

[![experimental](http://badges.github.io/stability-badges/dist/experimental.svg)](http://github.com/badges/stability-badges)

### WORK IN PROGRESS
Runs Node.js inside Chromium DevTools (using [Electron](https://github.com/atom/electron/)).

Documentation is currently being written for this module. Check back soon!
This allows you to profile, debug and develop typical Node.js programs with some of the features of Chrome DevTools.

---
The recording below shows setting breakpoints within an HTTP server.

Runs Node.js source code through Chromium DevTools (using Electron).
![movie](http://i.imgur.com/V4RQSZ2.gif)

This allows you to profile, debug and develop typical Node.js programs with some of the features of Chrome DevTools.
## Usage

```sh
Usage:
devtool [entry] [opts]

Options:
--watch, -w enable file watching (for development)
--quit, -q quit application on fatal errors
--console, -c redirect console logs to terminal
--index, -i specify a different index.html file
--poll, -p enable polling when --watch is given
--show, -s show the browser window (default false)
--headless, -h do not open the DevTools window
```

Examples:

```sh
# watch/dev a JS file, with a custom index.html
devtool src/index.js --index index.html --watch

# redirect console and pipe results to a file
devtool main.js -q -c > foo.txt

# open a REPL window
devtool
```

## Example
## Use Cases

For example, we can use this to profile and debug [browserify](https://github.com/substack/node-browserify), a node program that would not typically work within the browser's DevTools.
### Debugging / Profiling

For example, we can use this to profile and debug [browserify](https://github.com/substack/node-browserify), a node program that would not typically run inside Chrome DevTools. Here we use [`console.profile()`](https://developer.chrome.com/devtools/docs/console-api), a feature of Chrome.

```js
// build.js
var browserify = require('browserify');

// Start DevTools profiling...
console.profile('build');

// Bundle some browser application
browserify('client.js').bundle(function (err, src) {
if (err) throw err;

Expand All @@ -30,22 +61,82 @@ browserify('client.js').bundle(function (err, src) {
});
```

Here are some screenshots after the profile has run, and also during debugging of a hot code path.
Now we can run `devtool` on our file:

```sh
devtool build.js
```

Some screenshots of the profiling and debugging experience:

![profile](http://i.imgur.com/vSu7Lcz.png)

![debug](http://i.imgur.com/O4DZHyv.png)

### REPL

We can also use the DevTools Console as a basic Node REPL with some nice additional features. The require statements will be relative to your current working directory. You can run the command without any entry file, like this:

```sh
devtool
```

![console](http://i.imgur.com/bnInBHA.png)

### Browser APIs

You can also mix Node modules with browser APIs, such as Canvas and WebGL. See [example/streetview.js](./example/streetview.js) and the respective script in [package.json](./package.json), which grabs a StreetView panorama with some [Google Client APIs](https://developers.google.com/discovery/libraries?hl=en) and writes the PNG image to `process.stdout`.

Example:

```sh
devtool street.js --index street.html --quit > street.png
```

Result:

![street](http://i.imgur.com/GzqrTK2.png)

### Other Examples

See the [examples/](./examples/) folder for more ideas, and the [package.json](./package.json) scripts which run them.

## Features

This builds on Electron, providing some additional features:
This is built on [Electron](https://github.com/atom/electron/), so it includes the Console, Profile, Debugger, etc. It also includes some additional features on top of Electron:

- Improved error handling (more detailed syntax errors in console)
- Improved source map support for required files
- Makes various Node features behave as expected, like `require.main` and `process.argv`
- Console redirection back to terminal (optional)
- File watching for development and quit-on-error flags for unit testing (e.g. continuous integration)
- Exit error codes
- Handles `process.exit` and error codes

## Usage
## Gotchas

Since this is running in Electron and Chromium, instead of Node, you might run into some oddities and gotchas. For example, `window` is present, which some modules may use to detect Node/Browser environments.

Some modules that use native addons may not work within Electron.

## Roadmap / Contributing

This project is experimental and has not been tested on a wide range of applications. If you want to help, please open an issue or submit a PR. Some outstanding areas to explore:

- Adding a `--timeout` option to auto-close after X seconds
- Supporting `"browser"` field in `package.json`
- Supporting `process.stdin` and piping
- Improving syntax error handling, e.g. adding it to Sources panel
- Exposing an API for programmatic usage
- Adding unit tests

You can `git clone` and `npm install` this repo to start working from source.

## See Also
#### `hihat`

If you like this, you might also like [hihat](https://github.com/Jam3/hihat). It is very similar, but more focused on running and testing *browser* applications. Hihat uses [browserify](https://www.npmjs.com/package/browserify) to bundle everything into a single source file.

[![NPM](https://nodei.co/npm/devtool.png)](https://www.npmjs.com/package/devtool)
In some ways, `devtool` might be seen as a spiritual successor to `hihat`. The architecture is cleaner and better suited for writing large Node/Electron applications.

## License

Expand Down
File renamed without changes.
18 changes: 18 additions & 0 deletions example/http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// debugging an http server in DevTools!
var http = require('http');

var server = http.createServer(function (req, res) {
console.log('Requesting', req.url);
if (req.url === '/') {
res.end('Hello, world!');
} else {
res.statusCode = 404;
res.end('404 not found =(');
}
}).listen(8080, function () {
console.log('Listening on http://localhost:8080/');
});

window.onbeforeunload = function () {
server.close();
};
11 changes: 11 additions & 0 deletions example/simple-get.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
var get = require('simple-get');
var concat = require('concat-stream');

console.log('Requesting google.com');
get('http://google.com/', function (err, res) {
if (err) throw err;
res.pipe(concat(function (body) {
console.log('Total bytes:', body.toString().length);
if (process.env.NODE_ENV !== 'development') window.close();
}));
});
11 changes: 11 additions & 0 deletions example/streetview.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- A custom HTML index for the street view demo. -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>streetview</title>
<script src="https://maps.googleapis.com/maps/api/js?v=3.21"></script>
</head>
<body>
</body>
</html>
17 changes: 17 additions & 0 deletions example/streetview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
var awesome = require('awesome-streetview');
var render = require('google-panorama-equirectangular');
var toBuffer = require('electron-canvas-to-buffer');
var googlePano = require('google-panorama-by-location/browser');

googlePano(awesome(), function (err, result) {
if (err) throw err;
render(result.id, {
tiles: result.tiles,
crossOrigin: 'Anonymous',
zoom: 1
}).on('complete', function (canvas) {
var buffer = toBuffer(canvas, 'image/png');
process.stdout.write(buffer);
window.close();
});
});
2 changes: 1 addition & 1 deletion lib/file-watch.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// a thin wrapper around chokidar file watching HTML / CSS
// a thin wrapper around chokidar file watching files
var chokidar = require('chokidar');
var assign = require('object-assign');
var EventEmitter = require('events').EventEmitter;
Expand Down
10 changes: 7 additions & 3 deletions lib/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@

// get an absolute path to our entry point
var entry = remote.getGlobal('__electronEntryFile');
entry = path.isAbsolute(entry) ? entry : path.resolve(cwd, entry);
if (entry) {
entry = path.isAbsolute(entry) ? entry : path.resolve(cwd, entry);
}

// hook into the internal require for a few features:
// - better error reporting on syntax errors and missing modules
Expand All @@ -52,8 +54,10 @@
}
});

// boot up entry application
require(entry);
// boot up entry application when DOM is ready
ipc.on('dom-ready', function () {
if (entry) require(entry);
});

function fatalError (err) {
ipc.send('error', JSON.stringify(serialize(err)));
Expand Down
12 changes: 6 additions & 6 deletions lib/require-hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = function requireHook (opts, cb) {
var stripBOM = require('strip-bom');
var combineSourceMap = require('combine-source-map');
var entry = opts.entry;
// var basedir = opts.basedir || remote.process.cwd();
var basedir = opts.basedir || remote.process.cwd();

var hasSetMain = false;
var currentWrapFile = null;
Expand All @@ -36,9 +36,9 @@ module.exports = function requireHook (opts, cb) {
} catch (err) {
// improve Electron's error handling (i.e. SyntaxError)
var realErr = syntaxError(code, file) || err;
var msg = 'Error compiling module: ' + file + '\n' + (realErr.annotated || realErr.message);
console.error(msg);
cb(new Error(msg));
console.warn('Error compiling module: ' + file + '\n' + (realErr.annotated || realErr.message));
console.error(err.stack);
cb(err);
}
};

Expand All @@ -47,9 +47,9 @@ module.exports = function requireHook (opts, cb) {
Module.wrap = function (script) {
var wrapScript = wrap.call(wrap, script);
if (!currentWrapFile) return wrapScript;
var baseFileDir = path.dirname(entry);
// var baseFileDir = path.dirname(entry);
// TODO: Use path.dirname(entry) or opts.basedir ?
var sourceFile = path.relative(baseFileDir, currentWrapFile)
var sourceFile = path.relative(basedir, currentWrapFile)
.replace(/\\/g, '/');
var sourceMap = combineSourceMap.create().addFile(
{ sourceFile: sourceFile, source: script },
Expand Down
19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "devtool",
"version": "0.0.0",
"version": "1.0.0",
"description": "runs Node.js programs through Chromium DevTools",
"main": "index.js",
"license": "MIT",
Expand All @@ -18,14 +18,27 @@
"minimist": "^1.2.0",
"object-assign": "^4.0.1",
"serializerr": "^1.0.2",
"simple-get": "^1.4.3",
"strip-bom": "^2.0.0",
"syntax-error": "^1.1.4"
},
"devDependencies": {
"browserify": "^13.0.0"
"awesome-streetview": "^1.4.2",
"browserify": "^13.0.0",
"concat-stream": "^1.5.1",
"domready": "^1.0.8",
"electron-canvas-to-buffer": "^1.0.3",
"faucet": "0.0.1",
"google-panorama-by-location": "^4.1.1",
"google-panorama-equirectangular": "^1.2.0",
"simple-get": "^1.4.3",
"tape": "^4.4.0"
},
"scripts": {
"test": "electron server.js"
"test": "node test/index.js | faucet",
"http": "./bin/index.js example/http -w",
"simple-get": "./bin/index.js example/simple-get.js -qch",
"streetview": "./bin/index.js example/streetview.js -i example/streetview.html -q > example/streetview.png"
},
"keywords": [],
"repository": {
Expand Down
Loading

0 comments on commit 2db47d4

Please sign in to comment.