Notes on the JupyterLab Notebook HTML DOM Model, Part 9: Building and Distributing a Pre-Built Extension

So finally, finally… we’re at the point we can try to build an installable pre-built extension.

To test the build, it first makes sense to uninstall the version we’ve been developing to date. Running pip uninstall doesn’t necessarily do the job, as described in the previous post, so you may have to scrabble around searching for where the extension was installed so you can delete it yourself.

Building the extension is then relatively straightforward. In the project directory, make sure all the build tools are available:

pip3 install build

And then build the distribution, creating a wheel in dist/ directory:

python3 -m build

Usefully, it’s a platform agnostic wheel which means it should be installable in JupyterLite.

I noticed that changing adding stricter checks to tsconfig.json didn’t seem to get picked up after a successful build using my “let everything through” casual build, but the following command did rebuild the extension with all the re-enabled error checking switched back on:

jlpm clean && jlpm build:lib && jlpm build:labextension

Not surprisingly, my hacky Python flavoured Javascript style of Typescript raised all sorts of errors and suggests I really need to settle down to read a good (and recent) TypeScript book for a vcouple of days, but instead of that, I just switched all the error checking back off again:

  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "composite": true,
    "declaration": true,
    "esModuleInterop": true,
    "incremental": true,
    "jsx": "react",
    "module": "esnext",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitAny": false,
    "noUnusedLocals": false,
    "preserveWatchOutput": true,
    "resolveJsonModule": true,
    "outDir": "lib",
    "rootDir": "src",
    "strict": true,
    "strictNullChecks": false,
    "target": "es2017",
    "types": []
  "include": ["src/*"]

I’m not sure if a (re)start of the JupyterLab server is required to see the updated extension in action, or whether we can get away with just refreshing the JupyterLab browser window.

To distribute the newly built wheel via the project repository, we need to commit it: remove the dist/ path from the .gitgnore file and the wheel should now be visible.

My example repo (and you have been warned in advance about the state of the “TypeScript”) can be found here: innovationOUtside/jupyterlab_empinken_extension

To install the wheel:

pip3 install --upgrade

The extension by default enables four buttons that can be used to toggle cell tags. The tags are parsed and used to class the notebook cells and then coloured accordingly (I really need to do something about the default colours!).

The tag state is saved in the notebook document so should persist. The actual convention used to define the tags is user customisable via extension settings, as are the background colours.

I reckon it’s taken me a couple of years and four and a half days to get this far. The code is not TypeScript, but a hacky version of Javascript, mostly, from somoneone who only ever tends to write casual Python, with odd bits of copy and pasted TypeScript from other extensions. I note that many TypeScript programmes seem to be rather slack in terms of TypeScript formalism too, so it’s not just me… I also note that trying to search for good examples on TypeScript sucks. I’m not sure if this is becuase websearch rankings broke since TypeScript became a thing, or because there aren’t many good TypeScript resources out there.

Even with occasional moments of success, I found the whole process really dispiriting. I am not convinced that I came up with an effective strategy for making sense of or navigating the docs, or the examples. As ever, I get the sense that the most useful resources are other extensions written by people who aren’t developers, because the code tends to be simpler, even though it can also be a bit ropey in terms of code quality. But the overheads of getting started mean that you need to be quite resilient to get as far as even a simple extension that works.

The current extension is limited to just reading state, processing tags and classing DOM elements. I’ll try one more (a port of innovationOUtside/nb_cell_execution_status) which will attempt to react to cell execution status signals: I think I have enough cribs to make a start, although I haven’t (yet?) found any really good resources on the message responses that might be expected or how to parse them. When that’s done, and if I can then get things working in a JupyterLab environment, I may try to get innovationOUtside/nbev3devsim working in a meaningful way in JupyterLab, and then I’ll be able to quit the whole JupyterLab space and hopefully make a start playing with thebe and JupyterLite kernels in Jupyter Book, which I think is a far more interesting space to work in.

Author: Tony Hirst

I'm a Senior Lecturer at The Open University, with an interest in #opendata policy and practice, as well as general web tinkering...

%d bloggers like this: