An alternative way of operating in REPL mode of the freeware Wolfram Engine bringing similar experience as Mathematica Notebook.
This is one of the possible implementations of the frontend, the built JS/Wolfram framework and general concept behind it doest limit the environment (let say wrapper application), where it will be embedded. All frontend parts for the developers are located in src folder.
The project is in alpha stage (or may be even lower), some features might be changed.
PS: please, do not use master kernel for the evaluation, it exposes all internal scope of the webserver to the user. Spawn a separate process from the menu
- syntax check
\nmultiline expressions%symbolAbortbuttonPrintfunction- paradigm, where all frontend objects are powerful syntax sugar
Graphics3D(partial) as a interactive frontendthree.jsobject. see repo
Ploty(partial support) as an interactive 2D plot usingploty.js, simillar toPlotorListLinePlot
- exporting notebooks as
.htmlinteractive page
HTMLForm[String]embedsStringas a dom innerHTML at the given output cell
- iconize the output if it is too large. There is no actual data transfer to the frontend, everything works if it was a memory pointer
WebExport[name, expr, Popup->False]export your data by a link. Works as a combination ofExportandHTMLForm. The created file stores inpublic/trashcanforever.Popupmeans to open a tab with the given object.
SVGForm[anything]exports the object assvgto the fronted cell. Try to evalPlot[x,{x,0,1}]//SVGFormJSRun[String]executes JS script inside the cellWebOpen[url]popup a window at the given url (no output to the cell)FrontendXXX[]a family of functions allow to control the frontend (used by the kernel), seesrc/frontend.js.- spawn a separate process for the cell executions (the frontend will never fail)
- automatic backups every 30 mins
- easily expandable functionality
This is quite simple. All that you need is
- Freeware WolframEngine
the rest will be downloaded via the internet. Then
cdto the project folder and
git clone https://github.com/JerryI/wolfram-js-frontend
cd wolfram-js-frontend
wolframscript start.wlsOpen your browser with http://127.0.0.1:8090
or to define ip address
wolframscript start.wls ip 127.0.0.1 port 8090There is a Demo notebook, which covers the most functions.
- Documentation
- Markdown support
- floating menu at cells to change their properties
- export any cell as
.htmlinteractive page - indicator or a progress bar of the evaluation process
- non-destructive abortion (full evaluation control)
-
TableForm,MatrixFormas aFrontendExecutable -
DynamicorManipulateusing websokets; event systemEventBind[],DynamicControl[]and etc - export notebook as a file
- server-side rendering
- asynchronous functions like
awaitand event-loop - simple HTML and JS constructors like
CreateDiv[],Apply[, style->CSS[]]or similar - export function (as interactive
.htmldoc) -
JSRunrun custom js from Wolfram Kernel - truncate the output, prevent the large data to come to the frontend
-
HTMLForm[] -
Plotyas a temporary replacement for 2D plots -
WebExportacts asExport, but provide the link to download the exported file -
FrontEndExecutable[]as a reference to the programs to be executed on the frontend side
A web server and the half of logic runs on freeware Wolfram Engine as a backend
- serves the static page via library TinyWeb & WSP (hypertext preprocessor)
- stores the whole structure of the notebook
- communicates with a JS frontend via websockets
CodeMirror 6 library was used to operate notebook cells inside the page, when you press Shift-Enter it sends the content and a command to Wolfram Engine via websockets.
On the backend, it evaluates the result and sends it back via websockets. However, if there is a Graphics3D object (in future can be extended to many) it replaces it with a special symbol FrontEndExecutable["uid"], which tells to frontend, that the content can be executed in a browser. Also, web server sends a JSON representation of the content behind FrontEndExecutable to be parsed by JS.
Once it arrived CodeMirror uses Decorations structure to detect these objects inside the code and executes the content of it via a written very primitive JS Mathematica interpreter. CodeMirror treats it as an AtomicRange, i.e. a single symbol containing a complex DOM element. Of course, once it was sent back to the backend the FrontEndExecutable will be replaced by the original function.
Originally it was done for the utility to convert Graphics3D objects to ThreeJS, because one needs to parse the internal structure, which includes almost all features of a Wolfram Language.
By default JS script interprets everything that arrives via websockets using interpretate(json, env), therefore for the creation of notebook cells it uses the Wolfram-like function FrontEndCreateCell[]. To define your own function, you can write it as
core.List = function(args, env) {
var copy, e, i, len, list;
copy = Object.assign({}, env);
list = [];
for (i = 0, len = args.length; i < len; i++) {
e = args[i];
list.push(interpretate(e, copy));
}
return list;
};The set of Graphics3D objects is loaded from this repository and extends core functions.
In general, it is possible to insert inside FrontEndExecutable anything you want to execute at a frontend side.
type
git clone https://github.com/JerryI/wolfram-js-frontend
cd wolfram-js-frontend
npm ithen
wolframscript start.wls dev
The filewatcher will rebuild the js bundle every time you change something in src folder and copy the rest to the modules (reimporting the lib into Wolfram Engine).
Apart from the frontend parts located in src, the rest can be threated as a "wrapping application", which starts child processes (usually 1, since Wolfram Licensing limitations), stores notebooks, provides api and etc etc boring stuff, which is necessary to support the core of the frontend.
The building procedure is stored in config.prior.wls file, as well as in rollup.config.mjs. Using just one rollup is a pain, since the building procedure is quite complicated.
To add a new feature, check the following files
src/converter.wls- converts registered types of functions to the objects, which can be executed using frontend's JS interpretersrc/webobjects.wls- defines supporting functions for the graphics and other thingssr/core.js- simplified JS interpreter, can be called from anywhere asinterpretate(json object, environment)src/frontend.js- the cells creating functions of the frontend, expandscore.jssrc/misc.js- everything else, which expandscore.jsfunctions
To define your own function, define anywhere you want (inside <script> or in .js files)
core.MyFunction = function(args, env) {
console.log(interpretate(args[0]));
}To call it from the Wolfram kernel, use (more about it one can find there)
WebSocketBroadcast[server, MyFunction["Hey!"]];for all connected clients. As simple as it was shown.
To communicate with Wolfram Engine directly use
socket.send('Print["Hi from the frontend"]')




