I developed a Dash plugin for my company and a custom components library. The plugin is a normal python package that brings some features like auth, multi-page routing, etc. while the components library is a normal dash components library built from the cookiecutter template.
Said so, all works great, but I’d like to distribute only 1 python lib: the main plugin + the components inside it as a package, so users can install it once pip install company-dash and later they can import both the components and plugin stuffs:
from company_dash import auth, feature_a, feature_b
from company_dash import components
layout = components.Card("Hey there")
But I’m not able to do it, as if I just place the generated components .py files in a directory inside the main package, the JS and CSS resources are not loaded in the browser as the python components package has to be installed (pip install .).
I went into the inners of dash, as I think that my situation is exactly what you have in the core dash and html/dcc packages, but I couldn’t see any difference between those packages and mine, finally I saw something in the JS/CSS resources registration, it seems that you hardcoded the registration of the html, dcc and table (if I remember well) packages. How can I do that in a nice way?
I will assume that you are using the component boilerplate to create the components part and it is correctly built and etc. Please correct if I am wrong…
One potential cause of not loading the JS/CSS from components is that it is not added to the package files. For instance, in a “normal” component library, you would have these files added in MANIFEST.in (located on project root), but I am not sure it would work if it is in a subfolder…
As far as I remember, the dash components use an external source for the JS/CSS files, while the component boilerplate will do so just in case the library is published in npm, so that is a difference. I also think that all the references to JS/CSS files in __init__.py are relative to the module, so it should not be a problem if your components are in a submodule. That’s why I would look at the manifest to see if these files are added to the package.
Maybe @Emil can give a better input to your question, as dash-extensions has a mix of “normal python package” with components on it.
Indeed I see there’s a Manifest.in correctly populated, so you think if I merge the components manifest with the main lib manifest if may work?
Yes. So MANIFEST.in under /company_dash should include the js files that are on components/MANIFEST.in (which comes with the boilerplate), like include company_dash_components/company_dash_components/company_dash_components.js. One way to figure out if this is working is to inspect the installed package (site-packages folder for the interpreter) and see if the js files are there.
I see that _dash_renderer , dcc , html and dash_table packages are hardcoded while the rest are auto-discovered but can’t understand how.
This is done in self._collect_and_register_resources. I think that if you import your component library, Dash will add the js dependency to the list automatically. Here’s where the resources are defined in dcc:
You should have something similar for your library under company_dash/company_dash_components/company_dash_components/__init__.py
It might be a matter of personal taste, but another thing you could consider is to have two distinct libraries for the plugins and the components. IMO it would easier to maintain the two packages separately…
If the plugins somehow depend on the component (say, you have a custom navbar as compoent), you can simply make the component library a dependency of the plugin library.
I think it depends on the library content. If the Python code is e.g. utility funktions related to the Dash components, I prefer to bundle it all as one library. But if they are completely unrelated, I think separating them is fine (or maybe even better)