fonsp / Pluto.jl

🎈 Simple reactive notebooks for Julia
https://plutojl.org/
MIT License
5k stars 296 forks source link

ES6 imports inside cells #992

Open fonsp opened 3 years ago

fonsp commented 3 years ago

Normally, you can import libraries inside JS using the import syntax:

import confetti from 'https://cdn.skypack.dev/canvas-confetti'
import { html, render, useEffect } from "https://cdn.jsdelivr.net/npm/htm@3.0.4/preact/standalone.mjs"

In Pluto, this is currently not supported (because code is not executed at toplevel), and you need to use a different syntax as workaround:

html"""
<script type=module>

const { default: confetti } = await import("https://cdn.skypack.dev/canvas-confetti@1")
const { html, render, useEffect } = await import( "https://cdn.jsdelivr.net/npm/htm@3.0.4/preact/standalone.mjs")

</script>
"""

Can we add support for the toplevel syntax? Should we do some regex tricks to rewrite user code?

fonsp commented 2 years ago

A second reason is because

const { default: confetti } = await import("https://cdn.skypack.dev/canvas-confetti@1")

schedules a microtask (or whatevs), even if the lib is already loaded, whereas the original does not.

In Pluto, this can cause a single-frame flash where the DOM is rendered without the output from a script, causing scroll shifts and all that.

In one case (a big matrix of Scrubbables), this was causing a real problem, and I had to fix it like so: https://github.com/JuliaPluto/PlutoUI.jl/commit/7180494e58b7b6f872322a4843ce56ecfd5954c1

In this notebook, I made this technique "official" by storing past imports in a Map.

fonsp commented 2 years ago

I think I have a good solution! We can make ES6 imports work using a code transformation, detecting import ... from ... and then either:

  1. Placing it outside of the async wrapper function that we put around user code, since we now execute user code in a real <script>
  2. Rewriting to await import( with the Map system from my previous comment.

Now... rewriting code is hard and we are going to make mistakes. So I have an idea!

@dralletje WDYT?

dralletje commented 2 years ago

The microtask thing can be solved way easier, should to that anyway for any microtask stuff...

All I know is that as soon as we are transpiling javascript code, we'll become one of these things always lagging a couple feature behind, not being compatible with this and that unless we actively keep maintaining it with every new thing that comes out...

I first wanna apply the microtask fix and see if that makes it worthwhile, would love to keep type=module clean (you I don't like that we "support" it at all :P)

fonsp commented 2 years ago

Oooh awesome! I can make a notebook that you can fix?

fonsp commented 2 years ago

Fixing the underlying microtask problem instead of writing our own transpiler is a 👌👌👌 idea