Note that this section targets contributors. If you're interested in using the standalone app, download the latest release..
- git
- Node.js. We recommend using Node.js v8.x, but all
versions starting from v4 should work. Upgrading and managing node versions
can be easily done using
nvm
or its Windows alternatives. npm
v5.x and up (which ships by default with Node.js v8.x) to ensure that thepackage-lock.json
file is used and updated correctly.
git clone https://github.com/plotly/plotly.js.git
cd plotly.js
npm install
We haven't found a Node.js library that converts PDF files to EPS,
so we use poppler
:
On Debian-flavored Linux:
apt-get poppler-utils
On OS X:
brew install poppler
On Windows:
Can anyone help us out?
npm test
# or more granularly:
# just the standard linter
npm run test:lint
# just the unit tests (TAP tests using Node.js only)
npm run test:unit
# just the integration tests (using spectron)
npm run test:integration
We use electron-builder
to pack up
the plotly-graph-exporter
executable. To do so locally, run:
npm run pack
to do
Electron creates an executable environment. That is, require('electron')
does not do the same when executed as node index.js
and electron index.js
.
So, to write good unit tests, it becomes important to split logic that only
runs in Electron from other things that can be run in Node.js. That's why in
src/app/*
, only index.js
requires Electron modules. The other modules are
pure Node.js and are tested in test/unit/
using
TAP. The Electron logic is itself tested using
Spectron which is much slower.
Along with a name
field, each component has a ping
, an inject
, a parse
,
a render
and a convert
method:
ping
(required, renderer process): method that send healthy signal renderer to main processinject
(optional, main process): returns a string or an array of strings which is injected in the head of the app's HTML index file (e.g<script src="plotly.js"></script>
)parse
(required, main process): takes in a request body and coerces its optionsrender
(required, renderer process): takes options and returns image dataconvert
(required, main process): converts image data to output head and body
Component modules are just plain objects, listing methods. Components aren't
instantiated, their methods shouldn't depend on any this
. We chose to not
turn components into classes as this practice would be difficult to implement in the
main and renderer process at once.
Image exporter is a heavy user of Electron's IPC (inter-process-communication) which in turn is callback heavy. To help us stay out of callback hell, we use the following terms to designates callbacks:
- At the end of the data-parse callback, we call the component module
parse
method asparse(body, componentOpts, sendToRenderer)
wheresendToRenderer
is a callback. sendToRenderer
transfers info from the main to the renderer process assendToRenderer(errorCode, parseInfo)
.- In the renderer process we then call the component module
render
method asrender(info, componentOpts, sendToMain)
wheresendToMain
is a callback. sendToMain
transfers info from the renderer back to main process assendToMain(errorCode, result)
- Back in the main process, the component module
convert
method is then called asconvert(fullInfo, componentOpts, reply)
whenreply
is (you guessed it) a callback. reply
is then called asreply(errorCode, convertInfo)
.
Older plotly devs might remember our old nw.js
image server, but yeah
Electron is way better than nw.js
and a lot more people are using it. Using
it for this project was a no-brainier.
Devs more experienced with nw.js
should note: Electron apps juggle between a
Node.js process (called the main process) and browser scripts (call the
renderer process). Compared to nw.js
, creating Electron apps requires a
little more boiler plate, but Electron makes it much easier to know what
globals you have available.