Skip to content
This repository has been archived by the owner on Oct 19, 2019. It is now read-only.

Commit

Permalink
add CommonJS module example
Browse files Browse the repository at this point in the history
  • Loading branch information
Austin Moran authored and ry committed Mar 8, 2016
1 parent 69b64f0 commit 0cc0c15
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -6,3 +6,4 @@ v8
*.swp
.svn
v8worker.test
out/
11 changes: 11 additions & 0 deletions examples/commonjs/README.md
@@ -0,0 +1,11 @@
CommonJS
--------

Rudimentary CommonJS module example:

```
$ go build -o out/commonjs commonjs.go
$ out/commonjs
```

See the actual spec [here](http://www.commonjs.org/specs/modules/1.0/).
162 changes: 162 additions & 0 deletions examples/commonjs/commonjs.go
@@ -0,0 +1,162 @@
package main

import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path"
"regexp"

"github.com/ry/v8worker"
)

type module struct {
Err error `json:"err"`
Source string `json:"source"`
Id string `json:"id"`
Filename string `json:"filename"`
Dirname string `json:"dirname"`
main bool
}

func (m *module) load() {
filename := jsExtensionRe.ReplaceAllString(m.Id, "") + ".js"
if wd, err := os.Getwd(); err == nil {
m.Filename = path.Join(wd, filename)
} else {
m.Err = err
return
}
file, err := ioutil.ReadFile(filename)
if err != nil {
m.Err = err
return
}
m.Dirname = path.Dir(m.Filename)
var b bytes.Buffer
if m.main {
b.WriteString(fmt.Sprintf(
"var main = new NativeModule({ id: '%s', filename: '%s', dirname: '%s' });\n",
m.Id, m.Filename, m.Dirname))
}
b.WriteString("(function (exports, require, module, __filename, __dirname) { ")
if m.main {
b.WriteString("\nrequire.main = module;")
}
b.Write(file)
if m.main {
b.WriteString("\n}")
b.WriteString("(main.exports, NativeModule.require, main, main.filename, main.dirname));")
b.WriteString("\n$send('exit');") // exit when main returns
} else {
b.WriteString("\n});")
}
m.Source = b.String()
}

// Adapted from node.js source:
// see https://github.com/nodejs/node/blob/master/src/node.js#L871
const nativeModule = `
'use strict';
function NativeModule(rawModule) {
this.filename = rawModule.filename;
this.dirname = rawModule.dirname;
this.id = rawModule.id;
this.exports = {};
this.loaded = false;
this._source = rawModule.source;
}
NativeModule.require = function(id) {
var rawModule = JSON.parse($sendSync(id));
if (rawModule.err) {
throw new RangeError(JSON.stringify(rawModule.err));
}
var nativeModule = new NativeModule(rawModule);
nativeModule.compile();
return nativeModule.exports;
};
NativeModule.prototype.compile = function() {
var fn = eval(this._source);
fn(this.exports, NativeModule.require, this, this.filename, this.dirname);
this.loaded = true;
};
`

var (
jsExtensionRe = regexp.MustCompile(`\.js$`)
jsFile = flag.String("f", "module-1.js", "js file to run")
)

func loadMainModule(w *v8worker.Worker, id string) error {
m := module{Id: id, main: true}
m.load()
if m.Err != nil {
return m.Err
}
return w.Load(m.Filename, m.Source)
}

func runWorker(done <-chan struct{}, scriptFile string) <-chan string {
out := make(chan string)

go func() {
worker := v8worker.New(func(msg string) {
out <- msg
}, func(msg string) string {
m := module{Id: msg, main: false}
m.load()
bytes, _ := json.Marshal(m)
return string(bytes)
})

defer func() {
close(out)
worker.TerminateExecution()
}()

if err := worker.Load("native-module.js", nativeModule); err != nil {
log.Println(err)
return
}
if err := loadMainModule(worker, scriptFile); err != nil {
log.Println(err)
return
}

for {
select {
case <-done:
log.Println("killing worker...")
return
default:
}
}
}()

return out
}

func main() {
flag.Parse()
done := make(chan struct{})
in := runWorker(done, *jsFile)

for msg := range in {
if msg == "exit" {
log.Println("got exit message from js...")
close(done)
} else {
log.Printf("message from js: %q\n", msg)
}
}
}
20 changes: 20 additions & 0 deletions examples/commonjs/module-1.js
@@ -0,0 +1,20 @@
/*global $send*/

'use strict';

$send('module1 __dirname = ' + __dirname);
$send('module1 __filename = ' + __filename);

var module2 = require('module-2');

for (var i = 0; i < 10; i++) {
$send(module2.saySomething(i));
}

if (require.main === module) {
$send("module1 is main");
}

module2.longRunning(function(msg) {
$send(msg);
});
23 changes: 23 additions & 0 deletions examples/commonjs/module-2.js
@@ -0,0 +1,23 @@
/*global $send*/

'use strict';

$send('module2 __dirname = ' + __dirname);
$send('module2 __filename = ' + __filename);

var words = ['every', 'good', 'bird', 'does', 'fly',
'alligators', 'can', 'eat', 'grape', 'burgers'
];

exports.saySomething = function(index) {
return 'module2 says ' + words[index % 10] + '!';
};

exports.longRunning = function(callback) {
for (var i = 0; i < Number.MAX_SAFE_INTEGER; i++) {
if (i === Math.floor(Number.MAX_SAFE_INTEGER / 10000000)) {
callback('long running job has finished (' + i + ')');
return;
}
}
};
Binary file removed examples/handle-json/handle-json
Binary file not shown.

0 comments on commit 0cc0c15

Please sign in to comment.