2017-08-10 23:46:34 +00:00
|
|
|
# Other JS Engines and Deployments
|
|
|
|
|
|
|
|
There are many JS engines and deployments outside of web browsers. NodeJS is the
|
|
|
|
most popular deployment, but there are many others for special use cases. Some
|
|
|
|
optimize for low overhead and others optimize for ease of embedding within other
|
|
|
|
applications. Since it was designed for ES3 engines, the library can be used in
|
|
|
|
those settings! This demo tries to demonstrate a few alternative deployments.
|
|
|
|
|
2017-09-05 05:26:50 +00:00
|
|
|
Some engines provide no default global object. To create a global reference:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var global = (function(){ return this; }).call(null);
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Swift + JavaScriptCore
|
|
|
|
|
2019-11-15 01:46:49 +00:00
|
|
|
iOS and OSX ship with the JavaScriptCore framework for running JS scripts from
|
2017-09-05 05:26:50 +00:00
|
|
|
Swift and Objective-C. Hybrid function invocation is tricky, but explicit data
|
2017-09-24 23:40:09 +00:00
|
|
|
passing is straightforward. The demo shows a standalone example for OSX. For
|
|
|
|
playgrounds, the library should be copied to shared playground data directory
|
|
|
|
(usually `~/Documents/Shared Playground Data`):
|
|
|
|
|
|
|
|
```swift
|
|
|
|
/* This only works in a playground, see SheetJSCore.swift for standalone use */
|
|
|
|
import JavaScriptCore;
|
|
|
|
import PlaygroundSupport;
|
|
|
|
|
|
|
|
/* build path variable for the library */
|
|
|
|
let shared_dir = PlaygroundSupport.playgroundSharedDataDirectory;
|
|
|
|
let lib_path = shared_dir.appendingPathComponent("xlsx.full.min.js");
|
|
|
|
|
|
|
|
/* prepare JS context */
|
2018-02-14 20:06:35 +00:00
|
|
|
var context: JSContext! = JSContext();
|
2017-09-24 23:40:09 +00:00
|
|
|
var src = "var global = (function(){ return this; }).call(null);";
|
|
|
|
context.evaluateScript(src);
|
|
|
|
|
|
|
|
/* load library */
|
|
|
|
var lib = try? String(contentsOf: lib_path);
|
|
|
|
context.evaluateScript(lib);
|
|
|
|
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
|
|
|
|
|
|
|
|
/* to verify the library was loaded, get the version string */
|
|
|
|
let XLSXversion: JSValue! = XLSX.objectForKeyedSubscript("version")
|
|
|
|
var version = XLSXversion.toString();
|
|
|
|
```
|
2017-09-05 05:26:50 +00:00
|
|
|
|
2017-09-24 23:40:09 +00:00
|
|
|
Binary strings can be passed back and forth using `String.Encoding.isoLatin1`:
|
|
|
|
|
|
|
|
```swift
|
|
|
|
/* parse sheetjs.xls */
|
|
|
|
let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
|
2018-02-14 20:06:35 +00:00
|
|
|
let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1);
|
2021-10-03 01:41:36 +00:00
|
|
|
context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol));
|
2017-09-24 23:40:09 +00:00
|
|
|
src = "var wb = XLSX.read(payload, {type:'binary'});";
|
|
|
|
context.evaluateScript(src);
|
|
|
|
|
2018-02-14 20:06:35 +00:00
|
|
|
/* write to sheetjsw.xlsx */
|
|
|
|
let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx");
|
2017-09-24 23:40:09 +00:00
|
|
|
src = "var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})";
|
|
|
|
context.evaluateScript(src);
|
|
|
|
let outvalue: JSValue! = context.objectForKeyedSubscript("out");
|
2018-02-14 20:06:35 +00:00
|
|
|
var out: String! = outvalue.toString();
|
2017-09-24 23:40:09 +00:00
|
|
|
try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);
|
|
|
|
```
|
2017-09-05 05:26:50 +00:00
|
|
|
|
2017-08-10 23:46:34 +00:00
|
|
|
|
|
|
|
## Nashorn
|
|
|
|
|
|
|
|
Nashorn ships with Java 8. It includes a command-line tool `jjs` for running JS
|
|
|
|
scripts. It is somewhat limited but does offer access to the full Java runtime.
|
|
|
|
|
2018-02-14 20:06:35 +00:00
|
|
|
The `load` function in `jjs` can load the minified source directly:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var global = (function(){ return this; }).call(null);
|
|
|
|
load('xlsx.full.min.js');
|
|
|
|
```
|
2017-08-10 23:46:34 +00:00
|
|
|
|
|
|
|
The Java `nio` API provides the `Files.readAllBytes` method to read a file into
|
|
|
|
a byte array. To use in `XLSX.read`, the demo copies the bytes into a plain JS
|
|
|
|
array and calls `XLSX.read` with type `"array"`.
|
|
|
|
|
|
|
|
|
2017-09-05 05:26:50 +00:00
|
|
|
## Rhino
|
|
|
|
|
|
|
|
[Rhino](http://www.mozilla.org/rhino) is an ES3+ engine written in Java. The
|
|
|
|
`SheetJSRhino` class and `com.sheetjs` package show a complete JAR deployment,
|
|
|
|
including the full XLSX source.
|
|
|
|
|
2017-09-24 23:40:09 +00:00
|
|
|
Due to code generation errors, optimization must be turned off:
|
2017-09-05 05:26:50 +00:00
|
|
|
|
|
|
|
```java
|
|
|
|
Context context = Context.enter();
|
|
|
|
context.setOptimizationLevel(-1);
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2017-09-12 20:02:06 +00:00
|
|
|
## ChakraCore
|
|
|
|
|
|
|
|
ChakraCore is an embeddable JS engine written in C++. The library and binary
|
|
|
|
distributions include a command-line tool `chakra` for running JS scripts.
|
|
|
|
|
2017-09-24 23:40:09 +00:00
|
|
|
The simplest way to interact with the engine is to pass Base64 strings. The make
|
2017-09-12 20:02:06 +00:00
|
|
|
target builds a very simple payload with the data.
|
2017-08-10 23:46:34 +00:00
|
|
|
|
|
|
|
|
2017-09-12 20:02:06 +00:00
|
|
|
## Duktape
|
2017-08-10 23:46:34 +00:00
|
|
|
|
2017-09-12 20:02:06 +00:00
|
|
|
[Duktape](http://duktape.org/) is an embeddable JS engine written in C. The
|
2021-10-03 01:41:36 +00:00
|
|
|
amalgamation makes integration extremely simple! It supports `Buffer` natively
|
|
|
|
but should be sliced before processing:
|
2017-09-12 20:02:06 +00:00
|
|
|
|
|
|
|
```C
|
|
|
|
/* parse a C char array as a workbook object */
|
|
|
|
duk_push_external_buffer(ctx);
|
|
|
|
duk_config_buffer(ctx, -1, buf, len);
|
|
|
|
duk_put_global_string(ctx, "buf");
|
2021-10-03 01:41:36 +00:00
|
|
|
duk_eval_string_noresult("workbook = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});");
|
2017-09-12 20:02:06 +00:00
|
|
|
|
|
|
|
/* write a workbook object to a C char array */
|
2018-02-14 20:06:35 +00:00
|
|
|
duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})");
|
2017-09-12 20:02:06 +00:00
|
|
|
duk_size_t sz;
|
|
|
|
char *buf = (char *)duk_get_buffer_data(ctx, -1, sz);
|
|
|
|
duk_pop(ctx);
|
|
|
|
```
|
2017-09-24 23:40:09 +00:00
|
|
|
|
2018-03-29 04:31:36 +00:00
|
|
|
|
2019-07-21 03:32:02 +00:00
|
|
|
## QuickJS
|
|
|
|
|
|
|
|
QuickJS is an embeddable JS engine written in C. It provides a separate set of
|
|
|
|
functions for interacting with the filesystem and the global object. It can run
|
|
|
|
the browser dist build.
|
|
|
|
|
|
|
|
The `global` object is available as `std.global`. To make it visible to the
|
|
|
|
loader, create a reference to itself:
|
|
|
|
|
|
|
|
```js
|
|
|
|
std.global.global = std.global;
|
|
|
|
std.loadScript("xlsx.full.min.js");
|
|
|
|
```
|
|
|
|
|
|
|
|
The filesystem interaction mirrors POSIX, including separate allocations:
|
|
|
|
|
|
|
|
```js
|
|
|
|
/* read file */
|
|
|
|
var rh = std.open(filename, "rb"); rh.seek(0, std.SEEK_END);
|
|
|
|
var sz = rh.tell(); rh.seek();
|
|
|
|
var ab = new ArrayBuffer(sz); rh.read(ab, 0, sz); rh.close();
|
|
|
|
var wb = XLSX.read(ab, {type: 'array'});
|
|
|
|
|
|
|
|
/* write file */
|
|
|
|
var ab = XLSX.write(wb, {type: 'array'});
|
|
|
|
var wh = std.open("sheetjs.qjs.xlsx", "wb");
|
|
|
|
wh.write(out, 0, ab.byteLength); wh.close();
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2018-03-29 04:31:36 +00:00
|
|
|
## Goja
|
|
|
|
|
2021-10-03 01:41:36 +00:00
|
|
|
Goja is a pure Go implementation of ECMAScript 5. `[]byte` should be converted
|
|
|
|
to a binary string in the engine:
|
2018-03-29 04:31:36 +00:00
|
|
|
|
|
|
|
```go
|
|
|
|
/* read file */
|
|
|
|
data, _ := ioutil.ReadFile("sheetjs.xlsx")
|
|
|
|
|
|
|
|
/* load into engine */
|
|
|
|
vm.Set("buf", data)
|
|
|
|
|
|
|
|
/* convert to binary string */
|
|
|
|
_, _ = vm.RunString("var bstr = ''; for(var i = 0; i < buf.length; ++i) bstr += String.fromCharCode(buf[i]);")
|
|
|
|
|
|
|
|
/* parse */
|
|
|
|
wb, _ = vm.RunString("wb = XLSX.read(bstr, {type:'binary', cellNF:true});")
|
|
|
|
```
|
|
|
|
|
|
|
|
On the write side, `"base64"` strings can be decoded in Go:
|
|
|
|
|
|
|
|
```go
|
|
|
|
b64str, _ := vm.RunString("XLSX.write(wb, {type:'base64', bookType:'xlsx'})")
|
|
|
|
buf, _ := base64.StdEncoding.DecodeString(b64str.String())
|
|
|
|
_ = ioutil.WriteFile("sheetjs.xlsx", buf, 0644)
|
|
|
|
```
|
|
|
|
|
2017-09-24 23:40:09 +00:00
|
|
|
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|