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
\n
multiline expressions%
symbolAbort
buttonPrint
function- paradigm, where all frontend objects are powerful syntax sugar
Graphics3D
(partial) as a interactive frontendthree.js
object. see repo
Ploty
(partial support) as an interactive 2D plot usingploty.js
, simillar toPlot
orListLinePlot
- exporting notebooks as
.html
interactive page
HTMLForm[String]
embedsString
as 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 ofExport
andHTMLForm
. The created file stores inpublic/trashcan
forever.Popup
means to open a tab with the given object.
SVGForm[anything]
exports the object assvg
to the fronted cell. Try to evalPlot[x,{x,0,1}]//SVGForm
JSRun[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
cd
to the project folder and
git clone https://github.com/JerryI/wolfram-js-frontend
cd wolfram-js-frontend
wolframscript start.wls
Open your browser with http://127.0.0.1:8090
or to define ip address
wolframscript start.wls ip 127.0.0.1 port 8090
There is a Demo
notebook, which covers the most functions.
- Documentation
- Markdown support
- floating menu at cells to change their properties
- export any cell as
.html
interactive page - indicator or a progress bar of the evaluation process
- non-destructive abortion (full evaluation control)
-
TableForm
,MatrixForm
as aFrontendExecutable
-
Dynamic
orManipulate
using websokets; event systemEventBind[]
,DynamicControl[]
and etc - export notebook as a file
- server-side rendering
- asynchronous functions like
await
and event-loop - simple HTML and JS constructors like
CreateDiv[]
,Apply[, style->CSS[]]
or similar - export function (as interactive
.html
doc) -
JSRun
run custom js from Wolfram Kernel - truncate the output, prevent the large data to come to the frontend
-
HTMLForm[]
-
Ploty
as a temporary replacement for 2D plots -
WebExport
acts 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 i
then
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.js
src/misc.js
- everything else, which expandscore.js
functions
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"]')