manzt / anywidget

reusable widgets made easy
https://anywidget.dev
MIT License
503 stars 39 forks source link

Problems with CORS due to URL.createObjectURL #106

Closed rmorshea closed 1 year ago

rmorshea commented 1 year ago

I'm fairly confident I'm encountering CORS problems due to the fact that the URL created by by URL.createObjectURL and executed by import() returned has a different host. Specifically, it is of the form blob:https://example.com/.... If you make a request for a resource from the Jupyter server in my widget I get a CORS error. Presumably because the host of my widget code has a blob: prefixed host name.

It's hard to be 100% sure of this since window.location does not show the blob: prefix. However, I've convinced myself by observing that the CORS error does not show up if I run the same query in the developer console.

manzt commented 1 year ago

Hmm interesting. I'm not sure when this would occur and seems like a bug if it is. We only should use URL.createObjectURL if the provided ESM isn't already a URL:

https://github.com/manzt/anywidget/blob/c74e0518ded7f9a6f4a45d9c57390370da0d5e40/packages/anywidget/src/widget.js#L85-L95

so:

import anywidget

class Foo(anywidget.AnyWidget):
  _esm = "http://example/.com/foo.js"

should cause the front end to use import("http://example/.com/foo.js"), rather than creating a blob: url.

rmorshea commented 1 year ago

I'll try and provide a simple way to reproduce. In short, my admittedly niche use case is one in which I have a Jupyter server extension that serves some other static JS resources where I import(myURL) inside the ESM blob any widget executes. myURL is something like /path/to/my/module.js. In this situation:

  1. This import() works just fine in the dev console, but fails to resolve when executed under anywidgets.
  2. If I explicitly declare the host in myURL (e.g. http://127.0.0.1:8000/path/to/my/module.js) I got a CORS error.
rmorshea commented 1 year ago

I had a bit if time to play around with this today and I was surprised to find that fetch didn't seem to have this same problem. I'd like to dig into that more to be sure though.

rmorshea commented 1 year ago

This seems less like a problem with anywidgets and more like an issue with the implementation of import().

If instead of doing import('/path/to/module.js') I do the following:

const rsp = await fetch('/path/to/module.js');
return await import(URL.createObjectURL(await rsp.blob()));

I have no problems.