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

Improved %%javascript cell magic. #13376

Open
ellisonbg opened this issue Dec 7, 2021 · 17 comments
Open

Improved %%javascript cell magic. #13376

ellisonbg opened this issue Dec 7, 2021 · 17 comments
Assignees

Comments

@ellisonbg
Copy link
Member

I have been working on am improved %%javascript cell magic and I wanted to run the idea by others to gauge interest. The existing %%javascript magic uses eval on a string of JavaScript code. While this works, it is relatively difficult to load external JavaScript packages and it is awkward to work with the DOM. I have developed a prototype with the following features:

  • Uses the sucrase library to allow a use to write modern JS, JSX or even TypeScript.
  • Run the code by appending a script tag to the page with type=module. This allows users to directly import modules from CDNs that support modules, such as Skypack.
  • Includes a JS implementation of a display function that takes a React element, native DOM element or list of thereof and renders it into the output of that cell.

The result of all this is that a user can write code that looks like the following:

%%typescript

display(<h1>Hello World</h1>);

And it will "just work". I would propose that this improved magic replaces the existing javascript magic. We might also want to have multiple variants that handle plain javascript, typescript, etc. At this point, I mostly want to get feedback on this directly to see if there is interest in this being in IPython. Here are a couple of example of this in action:

Screen Shot 2021-12-07 at 2 17 05 PM

@ellisonbg
Copy link
Member Author

ping @Carreau

@Carreau Carreau added this to the 8.0 milestone Dec 7, 2021
@Carreau
Copy link
Member

Carreau commented Dec 7, 2021

I'm happy to deprecate the current javascript magic before 8.0, but I think that if anything a magic like that should be in a separate package to move at its own speed.

Even in a separate package, we can make IPython depend on it, or auto load it when present.

I also want to be really careful about "just swapping" as it may break a lot of existing code.

@ellisonbg
Copy link
Member Author

Good points, I think it makes sense to be in a separate package, are you open to that package being in the IPython org?

@ellisonbg
Copy link
Member Author

I should note that the entire code base for this is in a single notebook and the core code is 60 lines (Obviously the final version with tests/docs will be more). All that to say I don't have this in an existing repo that could be transferred over and would need a repo to exist that I could submit a PR to.

@Carreau
Copy link
Member

Carreau commented Dec 7, 2021

are you open to that package being in the IPython org

Of course. The main question is wether it is the best place for people to find it. Will it work only with Lab ? Or also nteract/vscode/... ? Is the approach generic enough that pieces of it cold be reused by other kernels ?

I'll trust you with the location, once you've decided I'm happy to add deprecation warnings to %%javascript

@ellisonbg
Copy link
Member Author

The implementation uses the HTML MIME type and should be reasonably portable across frontends that render the HTML output type. It should also be fairly straightforward to port to work with other kernels as the main logic is two string templates.

In terms of location I propose we create an ipython/javascript_magic repository for this.

@Carreau
Copy link
Member

Carreau commented Dec 8, 2021

In terms of location I propose we create an ipython/javascript_magic repository for this.

That sounds great !

@Carreau
Copy link
Member

Carreau commented Dec 8, 2021

BTW, the %%javascript is "just"

    @cell_magic
    def javascript(self, line, cell):
        """Run the cell block of Javascript code"""
        display(Javascript(cell))

Should we also start deprecate the Javascript object ?

@ellisonbg
Copy link
Member Author

ellisonbg commented Dec 8, 2021 via email

Carreau added a commit to Carreau/ipython that referenced this issue Dec 8, 2021
@ellisonbg ellisonbg self-assigned this Dec 8, 2021
@blois
Copy link
Contributor

blois commented Dec 8, 2021

In the scope of this I think it would also be good to think about how to expose an API from the host application to the Javascript module. The goal would be to enable these Javascript outputs to leverage Comms and possibly other APIs with a standardized API.

There's a bit of discussion on this general idea in https://github.com/Quansight-Labs/jupyter-output-spec.

For implementation and end user ease-of-use it should be as simple as the user optionally adding a export function render(args) {} to the module which would be invoked if present.

I did a very primitive exploration of this in JupyterLab at https://github.com/blois/js-module-renderer/.

@blois
Copy link
Contributor

blois commented Dec 20, 2021

Just to follow up on #13376 (comment) in Colab we have these capabilities exposed off of the window object to support rich visualizations without requiring extensions similar to classic notebook (full api). This works well but:

  • It's non-standard- Colab could not just expose a subset of classic notebook APIs off of window because too many visualizations feature detect off of window.jupyter then attempt to access very classic-specific APIs. We were forced to use a separate namespace.
  • Hanging APIs off of window works in Colab's iframed outputs but is a model which will not work for JupyterLab which renders multiple notebooks in the same window.

The goal here is to allow some degree of the customization that was available in Jupyter Notebook in JupyterLab and other clients, in a standardized manner.

I also believe that an implementation must also preserve the simplicity of the module examples #13376 (comment) any top-level function should not be required but it would be used if present.

@Carreau Carreau modified the milestones: 8.0, 8.1 Dec 26, 2021
@Carreau
Copy link
Member

Carreau commented Dec 26, 2021

I'm going to bump that past 8.0, I've marked the current JS magic as pending deprecation (ie not deprecated yet but it will likely be). I don't have particular use of the %%javascript, so I'll trust you all to make a decision and let me know.

@echarles
Copy link
Member

Maybe jumping to the details too soon, and better discussed in the upcoming repository, but I prefer logging my questions here for now:

  1. Would sucrase invocation be different for js, jsx, ts, tsx? I guess tsx would cover everything. Let's say it is different, then we could have the magic being %%js, %%jsx, %%ts, %%tsx allowing keeping the to be deprecated %%javascript, and allowing to no make the pure javascript developer afraid with the typescript naming...
  2. Let's say I run in JupyterLab, will the generated code have access to jupyterlab dependencies and code, so we could simply say import React from "react" without going to Skypack?
  3. Again for JupyterLab, will the generated code have access to the effective runtime, so being able to access some singleton, and from there other live constructs, even some private or more sensible ones?

@Carreau Carreau removed this from the 8.1 milestone Feb 25, 2022
@BrainAnnex
Copy link

I note some talk about React. How about support for Vue?

@movy
Copy link

movy commented Sep 10, 2022

Is there any update on this feature? I'm trying to utilize JS charting libraries inside JupyterLab (which implies exchanging data between python and JS cells), and so far the only working solution I found is https://github.com/jorgehpo/notebookJS. It works fine, but is rather convoluted, and I wonder if there's a more straightforward way available in 2022? Thank you.

@maartenbreddels
Copy link

@ellisonbg Ever since I read this issue and you mentioned sucrase, I thought that it was an excellent idea to do transpilation in the browser.

I've turned a subset of this idea this into an ipywidget library called ipyreact: https://github.com/widgetti/ipyreact/
Which transpiles the tsx/jsx in the browser, and uses all the ESM feature (+shims for future features) to make it easy to write JSX/TSX in the notebook.

Also, this issue motivated me to add a cell magic, so after pip install ipyreact you can do:

%load_ext ipyreact
%%react
import confetti from "canvas-confetti";
import * as React from "react";

export default function({value, on_value, debug}) {
    return <button onClick={() => confetti() && on_value(value + 1)}>
        {value || 0} times confetti
    </button>
};

Due to (preconfigured) import maps, Material UI also works out of the box, so you should be able to copy paste the example from https://mui.com/material-ui/react-rating/ and it will just work.

Hopefully, this is also an inspiration to pick up the full idea of an improved %%javascript cell magic.

@declann
Copy link

declann commented Apr 2, 2024

Hi!

The proposed cell magic sounds great.

I'm considering some JS integration with Jupyter and wonder if the dev notebook be shared/published?

Cheers
Declan

I should note that the entire code base for this is in a single notebook and the core code is 60 lines (Obviously the final version with tests/docs will be more). All that to say I don't have this in an existing repo that could be transferred over and would need a repo to exist that I could submit a PR to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants