Hi there
a probably dumb question from a npm/ts newbie:
I am trying to use in extension jlab_ext2
some code (say, function foo
) from another extension jlab_ext1
(knowing that jlab_ext1
is packaged with pip)
exporting
in jlab_ext1
, I think I found how to re-export foo
, which is not defined in index.ts
but in a separate file foo.ts
by doing
export { foo } from './foo'
importing
the other way around though, when writing src/index.ts
in jlab_ext2
, I would like to mimic the imports like this one
import { Cell } from '@jupyterlab/cells'
but I do not know how to refer to jlab_ext1
because when writing this (with or without a @
)
import { foo } from 'jlab_ext1'
I’m getting
src/index.ts:31:8 - error TS2307: Cannot find module 'jlab_ext1' or its corresponding type declarations.
I also tried
- with
from 'jlab-ext1'
as it is the name displayed by jupyter labextension list
- and also with a
@
just in case, but none seemed to work
it feels like the naming is npm-dictated, but since I am packaging through pip I am a little confused
thanks for pointing me in the right direction
Webpack (and therefore jupyter labextension
) only speaks npm
-compatible package names, as declared in package.json#/name
.
To import code from another, pip
-installed prebuilt extension, the consumer must declare the provider in package.json#/jupyterlab/sharedPackages
, which will ensure it is found at runtime, and not duplicated: this is extremely important for libraries which use, e.g. instanceof
or otherwise have hidden singleton behavior, like react
. Indeed, some packages like react
, @lumino/*
, @jupyterlab/*
are already forced as singletons, due to how terrible the failure modes are.
Another option is to have a third package, which is not an extension, that provides the common functionality, in which case both extensions would add the common package name to sharedPackages
.
As for pypi.org
vs npmjs.org
: publishing “real” packages on npmjs.org
allows for other extension developers to depend on the features of an extension, even though users will (hopefully) not have to muck about with it. This is the pattern that enables, for example, Jupyter Widgets, which separates the lab-specific code which declares plugins (@jupyter-widgets/jupyterlab-manager
) from the underlying models (@jupyter-widgets/base
) and the UI implementations (@jupyter-widgets/controls
). This already allows complete reuse of all UI in Lab and Classic, and would allow someone to entirely customize the relatively stock HTML5 widgets, but still be compatible with things like Box
subclasses, which rely on their children
being actual WidgetView
instances.
2 Likes
thanks for the detailed explanation
I’m still confused though; in my use case, the provider extension is this one
So in the consumer extension, I tried this in package.json
"jupyterlab": {
"extension": true,
"outputDir": "jupyterlab_courselevels/labextension",
"sharedPackages": [
"jupyterlab-celltagsclasses"
]
}
and in my index.ts
I wrote this
import { md_get } from 'jupyterlab-celltagsclasses'
but I still see this
pip install -e .
<snip>
INFO:hatch_jupyter_builder.utils:> /private/var/folders/9n/sxs31qhj1gnd6gk2v0ns8848000fn2/T/pip-build-env-zirlx0n7/overlay/bin/jlpm run install:extension
src/index.ts(31,8): error TS2307: Cannot find module 'jupyterlab-celltagsclasses' or its corresponding type declarations.
<snip>
also, I can’t seem to find any ts or js file in the site-packages
area, which may or may be expected… I guess I’m still wondering how the js code is supposed to get installed in the node-modules
area ?
So I guess there’s some additional step I should make at some point ?
PS.
in the consumer extension I have this
$ pip show jupyterlab-celltagsclasses
Name: jupyterlab_celltagsclasses
Version: 0.2.0
Summary: JLAB extension to add classes to cells based on their tags
This is rather unrelated to the sharedPackages
story (and if you are just importing utility functions which are stateless you are not required to use sharedPackages
). To build extensions with TypeScript you need to have types. To have types you either publish the provider package to npm and declare it in the (dev)dependencies of consumer extension, or if publication of types to npm is not an option (rarely the case) manually declare types for the package in declaration files.
Of note this is only required for development build, your users will not need to download anything from npm.
Thanks, that was helpful
So to summarize, what I had to do was to
- run
npm publish
in the provider extension
- add the provider extension in the
dependencies
area in the consumer extension’s package.json
- and then run
npm install
in the provider extension
and this way I indeed have the code pulled in my node-modules
folder
It’s good to know that the provider extension code will come with a pip install
of the consumer extension
thank you !
2 Likes