Configuring¶
Runtime Configuration Files¶
The behavior JupyterLite in the browser can be controlled by creating specially-named files at any level of the file tree. It is expected each file conforms to the schema. For an example, see the demo configuration.
File |
Config Location |
|
Note |
|---|---|---|---|
|
|
✔️ |
integrates into existing Jupyter workflows |
|
whole file |
✔️ |
good for simple/automated configuration |
|
|
✔️ |
configuration of last resort, not recommended |
Each can be omitted from the file tree, and will result in a harmless (though noisy)
404 response.
Hint
Configuration cascades down, such that the closest, most-user-editable file
to the index.html being served takes highest precedence. Like-named keys will
be replaced by higher-priority files, with the notable exceptions of:
the
federated_extensionsanddisabledExtensionslists are appended and deduplicatedthe
settingsOverridesdictionary will be merged at the top level of each plugin
Schema¶
Warning
The current schema version is 0, and as such is subject to change. Once it has
stabilized, we hope to provide similar backwards-compatibility guarantees as the
Jupyter Notebook Format.
As the schema provides many options, please see the dedicated pages below.
Adding Content¶
Content with the CLI¶
With the CLI installed, run:
jupyter lite build
Any contents found in:
{lite-dir}/files/any content roots added via:
the CLI flag
--contentsthe
#/LiteBuildConfig/contentsinjupyter_lite_config.json
Will be:
copied to the built site under
{output-dir}/files/may have timestamps changed if
--source-date-epochis provided.
indexed to provide
{output-dir}/api/contents/{subdir?}/all.json
Server Contents and Local Contents¶
When a user changes a server-hosted file, a copy will be made to the browser’s storage,
usually in IndexedDB. A user’s locally-modified copy will take precedence over any
server contents, even if the server contents are newer.
Customizing Content Storage¶
By default, all of a user’s contents on the same domain will be available to all
JupyterLite instances hosted there. To create separate content stores, change the
jupyter-lite.json#jupyter-config-data/contentsStorageName from the default of
JupyterLite Storage.
By default, the best available, persistent storage driver will be used. One may force a
particular set of drivers to try with
jupyter-lite.json#jupyter-config-data/contentsStorageDrivers. See more about
local storage drivers.
Adding Extensions¶
JupyterLab 3 pre-built extensions allow for adding new capabilities to JupyterLite without rebuilding the entire web application. A good starting point for extensions that might work is the JupyterLab issue Extension Compatibility with 3.0 (#9461). Additionally, this site demonstrates a few extensions.
Extensions with the CLI¶
Environment Extensions¶
When you run jupyter lite build, all pre-built extensions in your JupyterLab
environment, e.g. {sys.prefix}/share/jupyter/labextensions will be:
copied to
{output-dir}/extensionshave its theme information copied to
{output-dir}/{app/?}theme/
This discovery behavior can be disabled with the CLI flag --ignore-sys-prefix or
LiteBuildConfig/ignore_sys_prefix.
Extensions for a Specific App¶
Similar to the above, by updating $YOUR_JUPYTERLITE/{app}/jupyter-lite.json, the
pre-built extensions will only be available for pages within that file tree.
Custom Extensions¶
By placing extensions under {lite-dir}/extensions/{org/?}{package}/, these will also
be copied into the output-dir after any environment extensions, and all will be
added to {output-dir}/jupyter-lite.json#jupyter-config-data/federated_extensions.
Hint
For example, after building a lab extension, you can copy the contents of
packages.json#/jupyterlab/outputDir right into the lite-dir to preview your
extension.
Finally, the --federated-extensions CLI flag and the
LiteBuildConfig/federated_extensions config entry allow for adding additional
federated extensions, as packaged in Python .whl or conda .tar.bz2 packages.
Applications¶
Removing Applications¶
Provide the --apps CLI argument once or multiple times, or configure
LiteBuildConfig/apps to only copy select applications to the output folder: by
default, all of the default applications will be copied to the
output folder.
Removing Source Maps¶
Provide --no-sourcemaps, or configure no_sourcemaps in a config file to prevent any
.map files from being copied to the output folder. This creates a drastically
smaller overall build.
Warning
Removing sourcemaps, in addition to making errors harder to debug, will also
cause many 404 errors when a user does open the browser console, which
can be even more confusing.
For better baseline performance, the core JupyterLite distribution, and some federated extensions, only ship optimized JavaScript code, which is hard to debug. To improve this, source maps, are also provided to provide pointers to the original source code, and while much larger, are only loaded when debugging in browser consoles.
Customizing Settings¶
With the CLI, if you create an overrides.json in either the root, or a
specific app directory, these will be:
merged into
{output-dir}/{app?}/jupyter-lite.json#/jupyter-config-data/settingsOverrides
Settings Storage¶
By default, all of a user’s settings on the same domain will be available to all
JupyterLite instances hosted there. To create separate settings stores, change the
jupyter-lite.json#jupyter-config-data/settingsStorageName from the default of
JupyterLite Storage.
By default, the best available, persistent storage driver will be used. One may force a
particular set of drivers to try with
jupyter-lite.json#jupyter-config-data/settingsStorageDrivers. See more about
local storage drivers.
Local Storage Drivers¶
By default, the “best” localForage driver will be selected from the technologies available in the user’s browser.
To force choosing from a particular set of technologies, settingsStorageDrivers and
contentsStorageDrivers can be specified, with the first browser-compatible driver
being chosen.
configuration value |
technology |
persistent? |
note |
|---|---|---|---|
|
IndexedDB |
yes |
usually the one selected |
|
WebSQL |
yes |
|
|
localStorage |
yes |
|
|
in-memory |
NO |
requires |
other |
unknown |
unknown |
may be added by third-party extensions |
Volatile Memory Storage¶
Many extensions and features require the ability to at least think they are saving and loading contents and settings. If a user’s data cannot be stored due to browser security settings, a JupyterLite app will generally fail to fully initialize: while this might be frustrating, losing a user’s unique data creation is even more frustating.
Warning
If persistence is entirely handled outside of JupyterLite, e.g. in an embedded
repl it is possible to disable all persistence, assuring
total user data loss after every page/iframe reload:
set
enableMemoryStoragetotrueset
contentsStorageDriversandsettingsStorageDriversto["memoryStorageDriver"]
Adding pyolite wheels¶
The pyolite kernel itself consists of a bit of JavaScript and customized python wheels, which in turn require other wheels and pre-built WASM modules and other JavaScript.
Extra wheels that can be installed via piplite in a running kernel can be added via
the --piplite-wheels CLI flag or LiteBuildConfig/piplite_urls config value, or
simply left in-place in lite_dir/pypi.
These will be:
downloaded to the local cache
copied into
{output-dir}/pypiindexed into an
all.jsonwith data similar to the [PyPI Warehouse API]added to
pipliteUrlsinjupyter-lite.json
If a package is not found in one of these URLs, it will be sought on the main Python
Package Index (PyPI). This behavior can be disabled via jupyter-lite.json:
"jupyter-config-data": {
"litePluginSettings": {
"@jupyterlite/pyolite-kernel-extension:kernel": {
"disablePyPIFallback": true
}
}
}
pyodide¶
Beneath custom wheels are the raw JS and WebAssembly parts of pyolite provided by
pyodide. As the full distribution is very large, and self-hosting
of all its assets brings their own challenges, this use of CDN is the default for
JupyterLite.
A custom pyodide.js, along with its packages.json and the rest of its assets, such
as might be downloaded via the --pyodide CLI option, can also
be configured. This can be either relative to the lite_dir, or as a full URL.
"jupyter-config-data": {
"litePluginSettings": {
"@jupyterlite/pyolite-kernel-extension:kernel": {
"pyodideUrl": "./path/to/custom/pyodide/pyodide.js"
}
}
}
LaTeX¶
Rendering \(\LaTeX\) is generally handled in a special way when compared with most other renderers in JupyterLab. For this reason, it is not presently covered by a pre-built extension, but rather by adding MathJax 2 directly to the page. As it changes very slowly, and is relatively benign if missing for most use cases, this use of a CDN is the default for JupyterLite.
Configuring fullMathjaxUrl and mathjaxConfig in jupyter-lite.json allows you to
specify a relative or remote location, replacing (or avoiding) the CDN. If
jupyter-server-mathjax is
installed, the default configuration TeX-AMS-MML_HTMLorMML-full,Safe will be copied
into the output folder.
About the Demo¶
This documentation site contains the JupyterLite Demo (the Try buttons on the top of the screen) and uses a number of techniques described on this page.
Demo Configuration¶
The following generated configuration powers the Demo, and is generated prior to
building the docs site, copied in during the build, and fetched by browsers from
/_static/jupyter-lite.json.
{ “jupyter-config-data”: { “appName”: “JupyterLite Examples”, “appUrl”: “./lab”, “appVersion”: “0.1.0-beta.4”, “baseUrl”: “./”, “collaborative”: true, “disabledExtensions”: [ “@jupyterlab/server-proxy”, “jupyterlab-server-proxy”, “nbdime-jupyterlab” ], “exposeAppInBrowser”: true, “faviconUrl”: “./lab/favicon.ico”, “federated_extensions”: [ { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.17b005fe12a237b5ee9f.js”, “name”: “@agoose77/jupyterlab-markup” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.3421943a0ce73f10909d.js”, “name”: “@jupyter-widgets/jupyterlab-manager” }, { “liteExtension”: false, “load”: “static/remoteEntry.cdf08c015a8192358158.js”, “mimeExtension”: “./mimeExtension”, “name”: “@jupyterlab/fasta-extension”, “style”: “./style” }, { “liteExtension”: false, “load”: “static/remoteEntry.b75c764d727b50009261.js”, “mimeExtension”: “./mimeExtension”, “name”: “@jupyterlab/geojson-extension”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: true, “load”: “static/remoteEntry.4ba93726087006d2f61b.js”, “name”: “@jupyterlite/p5-kernel-extension”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.09511d7e294e827882b9.js”, “name”: “@marketsquare/jupyterlab_robotmode” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.c7d5ca84bbdfef35f278.js”, “name”: “@telamonian/theme-darcula” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.145e469029155b53b350.js”, “name”: “@timkpaine/jupyterlab_miami_nights” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.af71ba374fc8128e6506.js”, “name”: “bqplot” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.d3f93277b65928cb96a9.js”, “name”: “ipycanvas” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.879e49bd594a2adba895.js”, “name”: “jupyter-cytoscape” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.8f5cefaa26fbae099326.js”, “name”: “jupyter-leaflet” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.123b0b0e76ad7bd9092e.js”, “name”: “jupyter-matplotlib” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.a111cc73e550f743ab57.js”, “name”: “jupyter-vue” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.39dda9717d4e39a08c5a.js”, “name”: “jupyter-vuetify” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.8f896d6ad92823566c46.js”, “name”: “jupyterlab-drawio”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.c6e727a2dea5913e60d7.js”, “name”: “jupyterlab-kernelspy”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.b65dd4fef9fa6e2779f9.js”, “name”: “jupyterlab-myst”, “style”: “./style” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.f372bf1de02fb50ae6e0.js”, “mimeExtension”: “./mimeExtension”, “name”: “jupyterlab-plotly” }, { “extension”: “./extension”, “liteExtension”: false, “load”: “static/remoteEntry.5a1869d4304cb9223cfc.js”, “name”: “jupyterlab-tour”, “style”: “./style” } ], “fullLabextensionsUrl”: “./extensions”, “fullMathjaxUrl”: “./static/jupyter_server_mathjax/MathJax.js”, “fullStaticUrl”: “./build”, “licensesUrl”: “./lab/api/licenses”, “litePluginSettings”: { “@jupyterlite/pyolite-kernel-extension:kernel”: { “pipliteUrls”: [ “./pypi/all.json?sha256=a437a558f8d51f5e670ba554f50382540ca2ea55131301903302920a66d87555” ] }, “@jupyterlite/robolite-kernel-extension:kernel”: { “pipliteUrls”: [ “./pypi/all.json?sha256=a437a558f8d51f5e670ba554f50382540ca2ea55131301903302920a66d87555” ] } }, “mathjaxConfig”: “TeX-AMS-MML_HTMLorMML-full,Safe”, “settingsOverrides”: { “jupyterlab-tour:user-tours”: { “tours”: [ { “id”: “jupyter-lite”, “label”: “Welcome to JupyterLite”, “options”: {}, “steps”: [ { “content”: “This is JupyterLite”, “target”: “#jp-MainLogo” } ] } ] } } }, “jupyter-lite-schema-version”: 0 }
Demo Extension Notes¶
The federated_extensions above are copied from the documentation environment prior to
building this site with Sphinx, and are meant to exercise
different kinds of extensions, including themes, MIME renderers, and Widgets. Some
transient dependencies also include labextensions, but don’t work entirely correctly.
extension |
notes |
working issue |
|---|---|---|
|
needs Jupyter Kernel Comms |
|
|
needs server extension |
|
|
needs server extension |
The Hard Way¶
Content, The Hard Way¶
Assuming:
you have a running JupyterLab 3
you want to add all of the files in the root folder of the current JupyterLab to your JupyterLite.
Open a browser:
view the Contents API, e.g.
http://localhost:8888/api/contents, which should look something like:
{
"name": "",
"path": "",
"last_modified": "2021-05-15T20:16:17.753908Z",
"created": "2021-05-15T20:16:17.753908Z",
"format": "json",
"mimetype": null,
"size": null,
"writable": true,
"type": "directory",
"content": [
{
"name": "README.md",
"path": "README.md",
"last_modified": "2021-05-15T20:12:22.261076Z",
"created": "2021-05-15T20:12:22.261076Z",
"content": null,
"format": null,
"mimetype": "text/markdown",
"size": 3735,
"writable": true,
"type": "file"
}
]
}
Paste this JSON in
$YOUR_JUPYTERLITE/api/contents/all.jsonCopy your files in
$YOUR_JUPYTERLITE/filesRepeat this for every subfolder
:(
Now, when the app reloads, these files will appear in the File Browser if there isn’t an existing file of that name in browser storage. If a user has created such a file, and is deleted, the original server-backed file will become visible.
Extensions, The Hard Way¶
Warning
This is a heavily work-in-progress procedure, and will hopefully soon be improved with convenience tools in (at least) python and JavaScript.
Get the extension assets¶
Assuming you have a working JupyterLab 3 installation, look in your
{sys.prefix}/share/jupyter/labextensions. Each folder contains either:
if it begins with
@, a collection of packagesotherwise, a single pre-built extension
cd $YOUR_JUPYTERLITE
mkdir -p extensions
cd extensions
cp -r $PREFIX/share/jupyter/labextensions/@jupyter-widgets/jupyterlab-manager .
Warning
Some extensions will require other extensions to be available. This can be
determined by looking in package.json for the extension, specifically
#/jupyterlab/sharedPackages.
Handle theme assets¶
The Theme Manager expects to be able to load theme CSS/font assets from
{:app}/build/themes/({:org}/){:package}, where app is usually lab.
Continuing the example above:
cd $YOUR_JUPYTERLITE/extensions
mkdir -p ../build/themes
cp -r @*/*/themes/* ../build/themes/
cp -r @*/themes/* ../build/themes/
Fill Out federated_extensions¶
Again, assuming you have a working JupyterLab, click Inspect Element in your Lab and
inspect the <script id="jupyter-config-data"> in the <head>. The entry you need will
be contained there.
Update your /app/jupyter-lite.json like so:
{
"federated_extensions": [
{
"extension": "./extension",
"load": "static/remoteEntry.ca1efc27dc965162ca86.js",
"name": "@jupyter-widgets/jupyterlab-manager"
}
]
}
Hint
Some extensions also include a style key, and may look off if omitted.