| 
									
										
										
										
											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); | 
					
						
							|  |  |  | 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 | 
					
						
							|  |  |  | amalgamation makes integration extremely simple!  It supports `Buffer` natively: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```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"); | 
					
						
							|  |  |  | duk_eval_string_noresult("workbook = XLSX.read(buf, {type:'buffer'});"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* 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
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Goja is a pure Go implementation of ECMAScript 5.  As of this writing, there are | 
					
						
							|  |  |  | some issues with processing Unicode data, but the `xlsx.core.min.js` script can | 
					
						
							|  |  |  | be processed.  `[]byte` should be transformed to a binary string in the engine: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```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
										 |  |  | [](https://github.com/SheetJS/js-xlsx) |