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

Async createObjectURL #84

Closed
bmeck opened this issue Oct 16, 2017 · 22 comments
Closed

Async createObjectURL #84

bmeck opened this issue Oct 16, 2017 · 22 comments

Comments

@bmeck
Copy link

bmeck commented Oct 16, 2017

createObjectURL is unable to generate circular dependencies for ECMAScript Modules due to URLs requiring their content be given at time of creation. This leads to a problem when trying to recreate this file using createObjectURL:

// a.mjs
import './a.mjs';

It seems that there is no way to generate the URL for the import statement since it is returned from createObjectURL.

I would propose there be an async form or controller for this. I am not tied to any given API but can imagine something like:

// bikeshed method name, doesn't matter to me
const url = URL.createAsyncURL((async () => {
  await; // make sure `url` exists by waiting a tick
  return new Blob([`import ${url};`], {type: 'text/javascript'});
})());
@mkruisselbrink
Copy link
Collaborator

I'm not sure I understand why it would be useful to be able to create a URL that references content that contains that same URL?

@bmeck
Copy link
Author

bmeck commented Oct 16, 2017

@mkruisselbrink for situations where modules have circular dependencies. This can be used for situations where you are instrumenting a source text with code coverage for example.

@bmeck
Copy link
Author

bmeck commented Oct 16, 2017

I should clarify,

// ./a.mjs
import './b.mjs'
// ./b.mjs
import './a.mjs'

Has the same problem of being unable to generate the URLs in a circular manner.

@annevk
Copy link
Member

annevk commented Oct 17, 2017

The problem isn't clear enough to me to be able to recommend any particular solution here.

@bmeck
Copy link
Author

bmeck commented Oct 17, 2017

@annevk I have a working example of the problem in https://github.com/bmeck/browser-hooking/blob/adc8e6767fd6147b662258c765f7923b28105aed/entry.mjs#L3 , I have a Web Worker rewriting ES Modules, which may have circular dependencies. I am not using service worker due to some problems with first load not being able to be integrated against. In particular the worker cannot resolve circular dependencies since the URL generated by URL.createObjectURL cannot be reserved ahead of populating the body.

@annevk
Copy link
Member

annevk commented Oct 23, 2017

It seems service workers would be the natural solution here. Creating blob URL strings which are not immediately backed by a Blob object has all sorts of problems. E.g., the URL parser cannot immediately serialize the associated Blob in that case.

@bmeck
Copy link
Author

bmeck commented Oct 23, 2017

@annevk 2 points:

  1. ServiceWorkers do not work on initial loading of pages, making them appear to be a poor choice for hooking data.

the URL parser cannot immediately serialize the associated Blob in that case.

When does the Blob content access happen? I don't see it in https://w3c.github.io/FileAPI/#unicodeBlobURL

@annevk
Copy link
Member

annevk commented Oct 24, 2017

See https://url.spec.whatwg.org/#url-parsing.

(Given that we might be able to get origin policies before loading something from a domain I suspect that if that's successful we might also pursue loading a service worker before the resource too.)

@bmeck
Copy link
Author

bmeck commented Oct 24, 2017

@annevk that seems it just needs a flag for pending blob body rather than assuming the existence of a URL implies a body.

@annevk
Copy link
Member

annevk commented Oct 24, 2017

How would that work with synchronous XMLHttpRequest? I don't think it would be as simple a change as you assert.

@bmeck
Copy link
Author

bmeck commented Oct 24, 2017

@annevk

  1. does it need to / isn't that deprecated?
  2. Why not an InvalidAccessError like the conditions in https://xhr.spec.whatwg.org/#the-open()-method

@annevk
Copy link
Member

annevk commented Oct 25, 2017

What I'm saying is that you need to go through all the cases that expect URL's object to carry a Blob object and update them with language that they now need to wait for it or throw. And also do so while avoiding race conditions, ensure it's all tested, etc. It's a rather non-trivial addition.

@bmeck
Copy link
Author

bmeck commented Oct 25, 2017

@annevk do you think races could be avoided with a service worker that does work on initial page load?

@annevk
Copy link
Member

annevk commented Oct 26, 2017

I don't really see similar issues there and it's also not further enshrining this extremely awkward setup where a string keeps an object alive.

@bmeck
Copy link
Author

bmeck commented Oct 27, 2017

@annevk can't we already make a string keep objects alive in more simple ways?

const ns = await import('data:text/javascript,export default {}');
assert(typeof ns.default === 'object');

I don't find the argument compelling when we have another way to do exactly that.

@annevk
Copy link
Member

annevk commented Oct 29, 2017

I don't think I'm familiar enough with modules to see the similarity.

@bmeck
Copy link
Author

bmeck commented Oct 30, 2017

@annevk Module Map in HTML / ECMA262 is Idempotent. If you import a Data URL like the one above, it lives for the life of the Realm of JS. In the example above it is a simple {} that gets allocated and can never be GC'd. Unlike URL.createObjectURL there is no way to revoke an entry from the Module Map. A user could allocate more complex things or even just make variable storage that can never be GC'd in a similar way that is matched up to a string.

@annevk
Copy link
Member

annevk commented Oct 31, 2017

Lifetime of the realm is less long than blob URLs I'm pretty sure (although that's still not defined in detail unfortunately).

@bmeck
Copy link
Author

bmeck commented Oct 31, 2017

@annevk correct, blob stores appear to be per tab in browsers rather than per realm. They even cross workers.

@bmeck
Copy link
Author

bmeck commented Oct 31, 2017

Ah, I should note that I am using the feature of crossing realms on purpose in my example above.

@bmeck
Copy link
Author

bmeck commented Nov 8, 2017

@annevk made #89 while looking into lifetime of URLs

@bmeck
Copy link
Author

bmeck commented Feb 12, 2018

Closing in favor of #97

@bmeck bmeck closed this as completed Feb 12, 2018
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

3 participants