n-riesco / ijavascript

IJavascript is a javascript kernel for the Jupyter notebook
Other
2.18k stars 187 forks source link

Document how to import npm libraries #118

Open designium opened 7 years ago

designium commented 7 years ago

Hi,

I installed the following libraries:

 $ npm install -g web3
 $ npm install -g ethereum.js

Everything is installed and then I try to load the libraries in Jupyter Notebook:

var web3 = require('web3');
Error: Cannot find module 'web3'
at Function.Module._resolveFilename (module.js:527:15)
at Function.Module._load (module.js:476:23)
at Module.require (module.js:568:17)
at require (internal/module.js:11:18)
at repl:1:12
at ContextifyScript.Script.runInThisContext (vm.js:50:33)
at REPLServer.defaultEval (repl.js:239:29)
at bound (domain.js:301:14)
at REPLServer.runBound [as eval] (domain.js:314:12)
at REPLServer.onLine (repl.js:440:10)

Jupyter is not picking up the library. Is it something wrong?

Thanks.

n-riesco commented 7 years ago

This is a common misunderstanding in Node.js and npm. Installing a package globally doesn't ensure that the package can be required. A global install is meant to be used to install executable files. For example, if you want to install the latest version of npm, then you could run the command: npm install -g npm. This command would install the npm package in {prefix}/lib/node_modules and the executable file in {prefix}/bin (that usually is in your PATH).

In your case, I'd suggest the following:

$ mkdir my-project

$ cd my-project

$ npm init -y
[...]

$ npm install web3
[...]

$ npm install ethereum.js

$ jupyter notebook
[so that your notebook is created in the folder where the npm packages have been installed]
designium commented 7 years ago

Oh my god, your explanation is really clear and good. I wish I could have found instructions on that. I came from Ruby world and things are a bit more organized and clear. Thanks for the response!

n-riesco commented 7 years ago

I'm going to re-open the issue to remind me to include this info in the README.md.

sigurdurb commented 6 years ago

To require global modules/packages in an IJavascript session in notebook with JupyterHub you have to have the environment variable NODE_PATH set. Run "npm root -g" to find out where your global modules are. Mine were in /usr/lib/node_modules

You can run process.env in the notebook to see which variables are loaded.


There are 2 ways depending how you want to set it.

1. Simple way, everything in the Jupyterhub config file

in /etc/jupyterhub/jupyterhub_config.py c.Spawner.environment.update({'NODE_PATH':'/usr/lib/node_modules'})

2. Running Juputerhub with supervisor

In supervisor config:

[supervisord]
environment=NODE_PATH=/usr/lib/node_modules

and then in jupyterhub_config.py set c.Spawner.env_keep.append('NODE_PATH') env_keep is a list of variables that are to be inherited to the notebook.


There are probably other ways you can hardcode the environment variable by modifying the get_env function in spawner.py for example: /opt/conda/lib/python3.5/site-packages/jupyterhub/spawner.py But I recommend you rather take the approaches where you are just modifying the config files.

ps. simply adding it in the notebook with process.env.VARNAME = VARVALUE and requiring did not work.

n-riesco commented 6 years ago

@sigurdurb Thanks a lot for writing this up. I really appreciate it.

One comment about using process.env. There is a hacky way to get node acknowledge the change in process.env.NODE_PATH after the IJavascript session has started (this may be useful for anyone using IJavascript with other frontends):

process.env.NODE_PATH = "/usr/lib/node_modules";
require("module").Module._initPaths();

This code could also be injected into the IJavascript session by means of the flag --startup-script=path.

sigurdurb commented 6 years ago

That's also a cool way if you have it in --startup-script Otherwise you would have to write it in every notebook. I also wanted to mention about the order in which a notebook searches for node_modules: Correct me if I am wrong but from a little testing this is how it seems to work.

Lets say this is your folder structure:

/home/user ├── folder1 │   └── node_modules │   └── P1.ipynb ├── node_modules ├── P0.ipynb

If I have a require('d3') in folder1/P1.ipynb then that will first look in the node_modules in folder1, then in the user folder and if it does not find it there it will search in the NODE_PATH folder.

Lets say you are a student and want to try a newer or older version then is in the global directory you can install that in your current directory and require it again to get that version, while still requiring your other packages from the global NODE_PATH directory.

n-riesco commented 6 years ago

Lets say you are a student and want to try a newer or older version then is in the global directory you can install that in your current directory and require it again to get that version, while still requiring your other packages from the global NODE_PATH directory.

Yes, that's my understanding. The official documentation is here and here.

n-riesco commented 6 years ago

@sigurdurb This comment may be useful in your case.

vherasme commented 4 years ago

ps. simply adding it in the notebook with process.env.VARNAME = VARVALUE and requiring did not work.

Hello @sigurdurb. I am trying to use some node modules in Jupyter, I have Windows 10. How could I do it in my case?

n-riesco commented 4 years ago

@vherasme Do the instructions in this comment work for you?

Are you using the Jupyter notebook? nteract? hydrogen? or Jupyter hub?

vherasme commented 4 years ago

@n-riesco I am using Jupyter Notebook. I have set the NODE_PATH variable and then run npm install axios and now I am able to run axios from the notebook. Still I am unable to run:

let httpRequest = new XMLHttpRequest();
1:23 - Cannot find name 'XMLHttpRequest'.
n-riesco commented 4 years ago

I've had a quick look at the documentation for axios here and it doesn't seem to define XMLHttpRequest.

Here's an untested example of use, that should work with the ijavascript kernel:

const axios = require('axios');

axios.get('https://github.com/n-riesco/ijavascript/raw/master/AUTHORS');