Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

federated extensions, webpack sharing, deploying/configuring docs #58

Merged
merged 25 commits into from
May 4, 2021

Conversation

bollwyvl
Copy link
Collaborator

@bollwyvl bollwyvl commented Apr 20, 2021

References

Code changes

  • Adds build from upstreams
  • better handle setting federated_extensions in the index.html files
  • try with a simple extension that has schemas, for example: https://github.com/jtpio/jupyterlab-cell-flash
    • for now schemas are all bundled into a all.json file on build:
  • be able to just copy the prebuilt extension assets to lab/extensions
    • not have to edit all.json when new federated extensions are installed?
  • settings service will have to be aware of federated extensions
    • dynamically construct the list of all settings in this getAll() method.
  • a @jupyterlite/top (or site or something) that carries and abstracts some of the boilerplate
    • should be able to dedupe the app webpack bundles

User-facing changes

Deployer

  • Someone who wants to deploy a site would be able to
    • at the very leasst on this PR
      • drop some well-formed packages in <app>/extensions (as copied from $share/labextensions)
      • run a .py and/or .js script to update various all.json files

End User

  • n/a (though load times might be.... different, due to multiple packages)

Backwards-incompatible changes

?

@vercel
Copy link

vercel bot commented Apr 20, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/jtpx/jupyterlite/6JKfpTnPYwWaSXeQrpGjdpd8b9Yc
✅ Preview: https://jupyterlite-git-fork-bollwyvl-add-federated-extensions-jtpx.vercel.app

@jtpio
Copy link
Member

jtpio commented Apr 22, 2021

Thanks for getting this started!

@jtpio
Copy link
Member

jtpio commented Apr 30, 2021

Trying this out locally:

image

Also changed the structure and boilerplate code so it follows the upstream example a bit more closely: https://github.com/jupyterlab/jupyterlab/blob/master/examples/federated/core_package/webpack.config.js

@jtpio
Copy link
Member

jtpio commented Apr 30, 2021

Next steps:

  • better handle setting federated_extensions in the index.html files
  • try with a simple extension that has schemas, for example: https://github.com/jtpio/jupyterlab-cell-flash
  • for now schemas are all bundled into a all.json file on build:

https://github.com/jtpio/jupyterlite/blob/534111c7c3b9f1dbe04c7b99c9eb7bff187e63a1/app/webpack.config.js#L37-L59

so the lab settings manager can fetch all settings at once:

https://github.com/jtpio/jupyterlite/blob/534111c7c3b9f1dbe04c7b99c9eb7bff187e63a1/packages/settings/src/settings.ts#L37

It would be nice to be able to just copy the prebuilt extension assets to lab/extensions and not have to edit all.json when new federated extensions are installed. Basically a copy should be enough. But then the jupyterlite settings service will have to be aware of federated extensions, and be able to dynamically construct the list of all settings in this getAll() method.

@bollwyvl
Copy link
Collaborator Author

Thank you so much for looking into this. I'll check it out soon... the delta from my broken stuff should be enough for me to keep moving forward.

settings service will have to be aware of federated extensions

Yeah, sounds like table stakes for getting this in.

Humans should not have to write anything other than the one JSON file that seeds pageinfo, etc. so this is just another part of that, i guess...

@bollwyvl
Copy link
Collaborator Author

Nothing to concretely comment on, but the duplication between classic/lab definitely points to us perhaps wanting a @jupyterlite/top or something that carries and abstracts some of the boilerplate... will have to do some thinking.

@jtpio
Copy link
Member

jtpio commented Apr 30, 2021

but the duplication between classic/lab definitely points to us perhaps wanting a @jupyterlite/top or something that carries and abstracts some of the boilerplate

Yeah that sounds good.

the one JSON file that seeds pageinfo

And for now we could limit the scope to Python driven installs, which sounds the simplest so we could copy straight from $PREFIX/share/jupyter/labextensions to lab/extensions.

@bollwyvl
Copy link
Collaborator Author

could limit the scope to Python driven installs

Oh, yes, indeed. Nobody benefits from us building another package format.

So in another nuts-and-bolts, hopefully-testable diagram, I think we want two paths:

  • Integrate into existing Jupyter-based workflows #41 will be able to fully populate everything, because we can guarantee having a working lab sitting around, but won't need nodejs
  • for the "plumbing" approach (want to run webpack and stuff), we have a separate directory for py-module-0.0.0.tar.gzs (to cleanly separate from pyolite .whls... also they are half the size), and do the dirty in nodejs to figure out where they are put with data_files, copy them out. It seems preferable this is not done during webpack, though it could start webpack. So basically @jupyterlite/builder.

Both would end up fully realizing in lab/extensions/(<ns?>)/<package>/package.json, and generating whatever metadata slugs we need.

@bollwyvl
Copy link
Collaborator Author

bollwyvl commented Apr 30, 2021 via email

@bollwyvl
Copy link
Collaborator Author

bollwyvl commented May 2, 2021

I am making progress here, but not necessarily in the direction i was expecting:

  • move all jupyter-config-data into a jupyter-lite.json
    • add a schema for jupyter-lite.json (not using it at runtime, yet, because ajv is 🐘)
    • for now, this contains just jupyter-config-data, but I got some ideas...
      • I'm thinking we can abuse OpenAPI to normalize the all.jsons
  • in each index.html, do a hard redirect, if needed, to {pathname}/ so that relative URLs work predictably
  • make a /config-utils.js (could use a more lyrical name, perhaps) with no imports allowed which
    • reads and mangles jupyter-config-data with jupyter-lite.json files up the chain to the jupyter-lite-root
    • adds favicons (based on config)
    • adds the bundle script tag
      • specified with a <script rel="preload" id="jupyter-lite-main" href="./build/bundle.js" as="script"/>)
        • partially offsets the additional requests

This whole yak 💈 is to demonstrate being able to have a single _static/.jupyter-lite deployed in the docs site which adds some federated_extensions... which works locally for some stuff:

Screenshot from 2021-05-02 17-33-18

So I reckon we add tour and a few other goodies to docs, and see how it goes...

@jtpio
Copy link
Member

jtpio commented May 3, 2021

Thanks, this is looking great!

However, we don't need to solve that on this pr! Well already be able to do
lots of good demos with this, modulo the things we've called out (which
I'll hoist to the checklist)

Yeah absolutely, need to give some more thoughts to this. Also in the case where third-party packages want to distribute both a serverlite and a "normal jupyterlab extension" together.

So I reckon we add tour and a few other goodies to docs, and see how it goes...

We could put something lightweight into the current docs, however, without checking stuff in... it's really just a question of what are our top-flight selections. Of course, I'm partial to ipydrawio, but it is pretty heavy...

Sounds good 👍 I think we could also have a list of curated extensions that work well, or just some that we like to use.
Generally speaking, it would be nice to always have a functional demo on main that doesn't break too often. So as long as it doesn't disrupt the rest, adding new federated extensions to the default demo website on RTD should be fine.

/**
* TODO: consider better pattern for invocation.
*/
await main();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this might give a top level await error on some browsers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, i just wanted something that didn't webpack for this stage. as mentioned, we likely want this for "in-app" stuff too, so it probably needs to become a package with an entry point in the top-level webpack.

We also need to do more work on cache-busting, getting that [hash] back into file names, as I've noted on RTD it's pretty easy to get in a bad cache state. there's probably some more stuff we can fiddle with to get more-reproducible chunks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So top level await seems to be supported by Chromium 90 and Firefox 89.0b7 (developer edition). But not in Firefox 88.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually do we need the await here? Or could this be changed to the following (at least for now):

void main();

docs/deploying.md Outdated Show resolved Hide resolved
Co-authored-by: Jeremy Tuloup <jeremy.tuloup@gmail.com>
.eslintrc.js Outdated
@@ -45,7 +45,7 @@ module.exports = {
{ avoidEscape: true, allowTemplateLiterals: false }
],
curly: ['error', 'all'],
eqeqeq: 'error',
eqeqeq: ['error', 'always', { null: 'ignore' }],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need the null: 'ignore' part? Or was is for testing?

It would be nice to stick to === checks in general, but maybe this was added for a specific reason?

Copy link
Collaborator Author

@bollwyvl bollwyvl May 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strict equality of null and undefined is not consistent, whereas if you let the browsers Do Their Casting Thing, it comes out correctly... in my experience. Indeed, I prefer the behavior where it complains if you ever try to strict equal null or undefined.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So do you think we should keep that ignore clause, or leave it like it was before?

It might sound like a cosmetic thing mostly, but I was thinking we could try to follow the JupyterLab TypeScript Style Guide to make it easier for folks to switch between code bases and contribute to these projects. It doesn't explicitly say anything about strict equality, but I guess it would try to follow the JupyterLab eslint / prettier config when that makes sense.

name: STORAGE_NAME,
description: 'Offline Storage for Settings',
storeName: 'settings',
version: 1
});

export async function getAll(): Promise<{ settings: IPlugin[] }> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the settings are not updated on the RTD preview for this PR, for example when switching the theme or moving tabs to the left and right area: https://jupyterlite--58.org.readthedocs.build/en/58/_static/lab/index.html

Although refreshing the page does pick them up. So maybe it's related to the new getAll "merging" logic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, gross. needs test #6 lol

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah absolutely.

Just pushed c0bff5f in the meantime which should fix it.

It adds the network requests back to fetch all.json and the federated extension schemas too. But it would fine to take a look at it again in a separate PR if we want to optimize this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also handle editing settings for a federated extension via the settings editor.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, settings editing works now that the isFederated check is accurate

@bollwyvl
Copy link
Collaborator Author

bollwyvl commented May 3, 2021

list of curated extensions

That's a whacking good idea. quick sketch:

  • as we don't yet know what we want it to look like "for real", add a dumb file of:
    • map of npm-package-name to
      • full .whl URLs
      • whether we want them in the demo site
      • notes about their deployment
      • maybe a link to any open issues about supporting lite
  • during the docs build, use that file to
    • download and unpack
    • write jupyter-lite.json
    • build up the docs page
      • read whl metadata to get homepage etc
      • look at the on-disk size to see how much heft we're talking

As for that dumb file:

  • I don't see this becoming part of the end user tooling, per se
    • probably best to stick to stdlib dependencies when possible, which means .json or .ini 😿
  • but for docs purposes, maybe TOML for pr-ability?
    • we already have flit around, which depends on toml
      • even though we won't be able to ship all the packages with it, because data_files 🙀

always have a functional demo on main

No complaints there! Indeed, #6 should be testing that (probably deployed locally with e.g. tornado), not just the empty-and-light-as-possible contents of app which might not be minified, etc.

distribute both a serverlite and a "normal jupyterlab extension" together.

Well... on Jyve, i paid the 🐒 price to make stuff work in both full lab and the offline thing, and it was a huge hassle... but i'd definitely want to be able to use things like jupyterlab/pull-requests with Notebooks for kernelites.

What we can't do is introduce a new package build chain: it's gotta build with labextension build, and end up as another plugin.

I'd see hoisting serverlite-extensions up to jupyter-lite.json and making that something that the tooling can either detect at build time by introspecting a jupyterlite key in package.json, or that a deployer can manually specify.

@jtpio
Copy link
Member

jtpio commented May 3, 2021

we already have flit around, which depends on toml

Using flit was quite arbitrary mostly to get the pyolite kernel up and running quickly (and it's simple to use), but we could switch to something else if needed.

What we can't do is introduce a new package build chain: it's gotta build with labextension build, and end up as another plugin.

That would be ideal yes. Just need to check whether we can keep that workflow given that the jupyterlite server app is (for now at least) a separate Lumino application.

@bollwyvl
Copy link
Collaborator Author

bollwyvl commented May 3, 2021

Using flit was quite arbitrary

I strongly desire being able to ship jupyter tools with flit, if only for the reproducible wheels but we'll be stuck with setup.cfg and setuptools for actually shipping the built applications for the foreseeable... once we're worrying about cache busting and being able to confidently update jupyterlite deploys, this gets pretty clutch...

*/
export async function getFederated(id: string): Promise<IPlugin | undefined> {
const [ext, plugin] = id.split(':');
let federated: string[];
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, i think this comes back as a {name, load, extension, style}... will update...

}

/**
* Get all the settings
*/
async getAll(): Promise<{ settings: IPlugin[] }> {
return Private.getAll();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so... these will definitely not pick up federated stuff at present...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looked into this a bit... the problem is there is no enumeration of ["@org/pkg:plugin", ...] anywhere in the metadata. When we get to the "for real" automation tools, we may wish to hoist that information as well, as we would have the contents of the canonical schemas directory available, and could make that available to jupyter-config-data.

it could also be that the convention of the directory structure isn't actually enforced... but i think we'll just have to found out once we have the automation to start trying out a bunch of a extensions.

@bollwyvl
Copy link
Collaborator Author

bollwyvl commented May 4, 2021 via email

@jtpio
Copy link
Member

jtpio commented May 4, 2021

@bollwyvl I just pushed a couple of minor tweaks to:

  • remove the top level await so it works in the latest stable Firefox. And we can probably add it back later once FF 88 is the new stable
  • switch back to the previous eslint rule regarding the null checks (just to keep things consistent but could be added later again if needed)

Otherwise I think it looks really good for a first iteration on federated extensions! We can merge it as is and iterate in follow-up PRs and issues.

@bollwyvl
Copy link
Collaborator Author

bollwyvl commented May 4, 2021 via email

@jtpio jtpio merged commit 373b8aa into jupyterlite:main May 4, 2021
@jtpio
Copy link
Member

jtpio commented May 4, 2021

This is really great stuff, thanks again Nick!

@jtpio jtpio added this to the 0.1.0 milestone May 4, 2021
@jtpio jtpio added the enhancement New feature or request label Jun 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants