Using NVM installed Nodejs 16 for extensions install on Jupyterlab on Centos 7.6

I tried to install the @jupyterlab/geojson-extension on a Jupyterlab Version 3.5.3 running on Jupyterhub on Centos 7.6. It gives an error message of “Please install nodejs >=12.0.0. nodejs may be installed using conda or directly from the nodejs website”. In looking at $node -v it shows v6.13.1. Ran $ conda install -c conda-forge nodejs to try and upgrade but it only installed node v6.13.1 on Centos 7.6 which seems to be the highest version conda can install on this OS. So next tried to install using NVM as root: $ nvm install lts/gallium . Now it gives $node -v as v16.20.2 . After restarting Jupyterhub it still shows in a Jupyter terminal node version is v6.13.1. Also $ whereis node
/root/.nvm/versions/node/v16.20.2/bin/node /data/opt/anaconda3/bin/node . So apparently the jupyterhub is invoking node from /data/opt/anaconda3/bin/node which has old v6.13.1 instead of from /root/.nvm/versions/node/v16.20.2 since NVM installs under the userid . Jupyterhub is running under root user and how to make it use the node in /root/.nvm/versions/node/v16.20.2 instead of /data/opt/anaconda3/bin/node . Thanks!

Note that jupyterlab-geojson is a prebuilt extension, so either of the following will put it in the correct place without rebuilding lab (or needing nodejs):

  • pip install jupyterlab-geojson
  • conda install -c conda-forge jupyterlab-geojson

This can be verified with:

juyter labextension list

which should show a line something like:

@jupyterlab/geojson-extension    v3.x.y    installed   OK

Mixing nvm with conda is basically recipe for disaster. And, under many circumstances, using anaconda or defaults might be a ToS violation. My general recommendation is:

  • start with Mambaforge from conda-forge
    • never install anything else in the base
    • never install anything from defaults
    • don’t use the shell automation stuff, stick with
      • source /path/to/mambaforge/bin/activate
  • use an environment.yml to manage your jupyter environment, ideally with the kernel, server, and client in the same environment
    • splitting envs creates a bunch of other problems

Thanks @bollwyvl you are right. $ conda install -c conda-forge jupyterlab-geojson successfully installed the pre-built extension and I see now:
$ jupyter labextension list

JupyterLab v3.5.3
jupyterlab-plotly v5.9.0 enabled OK
nbdime-jupyterlab v2.2.0 enabled OK
jupyterlab-jupytext v1.3.8+dev enabled OK (python, jupytext)
@jupyter-widgets/jupyterlab-manager v5.0.5 enabled OK (python, jupyterlab_widgets)
@pyviz/jupyterlab_pyviz v2.0.2 enabled OK (python, pyviz_comms)
@jupyterlab/git v0.41.0 enabled OK (python, jupyterlab-git)
@jupyterlab/geojson-extension v3.4.0 enabled OK (python, jupyterlab-geojson)

Other labextensions (built into JupyterLab)
app dir: /data/opt/anaconda3/share/jupyter/lab

Now this leads to the next question how the normal users who use the JupyterLab GUI can click on the Extensions menu “Install” to install the other extensions since normal users will not be able to run "conda install -c conda-forge jupyterlab-geojson " as root. And they will not have write permissions to /data/opt/anaconda3/share/jupyter/labextensions although the Jupyterhub/JupyterLab is running under root user process. Also if they want to build a non-prebuilt extension that needs nodejs how can we install and point to the latest version of nodejs like v16.20.2 on Centos 7.6 since conda-forge will install max v6.13.1 on Centos 7.x. Thanks!

Yep, there are limitations. The best thing for your user of a locked down system that want non-prebuilt extensions… is to request the upstream distribute them as pre-built extensions.

I’d probably turn off the extension manager, as it is a very poor match for a multi-user setup, and indeed, there is no trivial way to offer per-user custom labextension paths in a single-process server. If users can’t be trusted users to install python packages, then they certainly shouldn’t be messing with npm… and npm (or pip or conda) should never be run as root: there’s basically zero chance a user will be able to remotely debug what any of the above barfed on, and there’s a nonzero chance that user (or all the users) will end up with an entirely broken experience.

If this deployment is doing one-user-per-server-process hub (not clear from the above), then the JUPYTER_PATH environment variable can be set at spawn time which would allow certain things to be specified per-user, but again, very peril-fraught. These users might also be able to use pip install --user, but this is an entire other ball of deadly wax, and seldom works the way one might expect… conda doesn’t even play that game.

Hello @bollwyvl what you said makes sense. Letting end-users install random extensions on a LocalProcessSpawner/jupyterhub-singleuser is not workable with the current Extensions Manager design unless somehow the extensions can be isolated per user in their own workspace. May not even be easy with dockerspawner or others that isolate users. So the better option for now would be to stick to conda command by the root user to install any needed extension requested by end-users using “conda install -c conda-forge extension-xxxxx”. Thanks!