Are ES6 modules in browsers going to get loaded level-by-level?

J Decker d3ck0r at gmail.com
Fri Oct 23 02:26:11 UTC 2020


On Thu, Oct 22, 2020 at 2:23 PM #!/JoePea <joe at trusktr.io> wrote:

> >  It's caused me some headaches especially when dealing with
> inheritance/extends and in workers.
>
> Like, extending from a `Module` object?
>
> > Maybe someday we'll have a `modules` collection we can interrogate.
>
> That may be nice, to query which modules have already been imported, etc.
>
> It would also be great if we could unload modules.
>
> ---
>
> Skypack is making news rounds as an ESM server: http://skypack.dev/
>
> It says it supports HTTP/2 and HTTP/3. But it isn't open source.
>
> Seems that there isn't any open source solution (otherwise I'm sure
> people would be using that over bundling if it works out better, at
> least alternatives to skypack would exist, f.e. well-know projects
> like React, Angular, Vue, Svelte, etc, could all have their own ES
> Module servers if it was viable).
>
> Seems that there hasn't been any free/open project to prove viability
> yet, and the existing ones are closed source.
>
> Seems that even http://jspm.dev is closed source.
>
> Looks like at this point in time people are aiming to make money from
> ESM servers, and there's no viable open source ESM server solution.
>
> Seems like it wouldn't be a LOT of work to take Acorn (
https://www.npmjs.com/package/acorn ) and http server (
https://www.npmjs.com/package/http ) and parse the pages loaded if
(*.[cm]+js) (something)

Though my observation is that when the browser gets the first page, async
requests go out for more content even before it's actually interpreted/run
the script; and the requests are streamed over one or more http(s)
connections.  this screenshot https://pasteboard.co/JwUnbAD.png  of this
demo http://d3x0r.github.io/Voxelarium.js/  shows the network load time;
recently updated to imports and non-built scripts...    though I do see a
gap where the html script loading ends and the imports in the scripts
actually go... but that could also be the pause setting up the opengl
surface... it's about 50ms.

since 'import' is itself async I sort of expected a lot of overlap in the
requests; there's only a single network wire, so there's not a LOT to be
gained parallelizing things.

If there was even some sort of manifest could make a background service
worker (which itself doesn't support import
https://bugs.chromium.org/p/chromium/issues/detail?id=680046 ) which can
behave like a offline storage/cache so the server can dump requests to the
client before it knows to ask for them... and then it doesn't have to ask
the server for anything  at all later even; which sort of de-emphasizes all
the work put into the server in the first place :)

J

#!/JoePea
>
> On Sun, Oct 18, 2020 at 8:50 AM Randy Buchholz <work at randybuchholz.com>
> wrote:
> >
> > Right, it's basically just doing what an import aware server might do
> and the type-tree is a hierarchal version of the scope imports. The rest is
> just extra stuff. Probably the biggest difference though is that it lets me
> isolate prototypes. From what I gather it seems that import stores a live
> "ghosted" version of the prototype that it checks before making additional
> requests for the item. The scope basically gets a reference to this
> prototype. If you do things like add a property with reflect in one scope
> that property shows up everywhere. And since it modified the "ghost" it
> persists after the scope goes away. It's caused me some headaches
> especially when dealing with inheritance/extends and in workers.
> >
> > Yeah, inspecting is in issue. I haven't found a way to inspect modules
> to see what they have in them. They're a strange beast. You can see their
> scope in the debugger and they look like an ES Object or IDL interface, but
> I don't know how to get a reference to them in code. But, they're new, so
> we'll see where they go. Maybe someday we'll have a `modules` collection we
> can interrogate.
> >
> > -----Original Message-----
> > From: #!/JoePea <joe at trusktr.io>
> > Sent: Saturday, October 17, 2020 10:35 PM
> > To: Randy Buchholz <work at randybuchholz.com>
> > Cc: es-discuss at mozilla.org
> > Subject: Re: Are ES6 modules in browsers going to get loaded
> level-by-level?
> >
> > That's neat, but it seems like the same work that a server would have to
> do with actual ES Module imports, right? And the "type tree"
> > equivalent is the modules that the JS engine stores as a map from import
> identifier to module scope instance. It seems that in the end, the `PUSH`
> approach should work with the same efficiency, right?
> >
> > Seems the only thing that makes it difficult is checking the map. In
> your special case, with `inject`, you can physically check the global
> namespaces to see if the module is available. But with ES Modules, we can't
> check if some module has already been lodade by its identifier, can we? So
> we have to make the request, because that's the only way to check.
> >
> > #!/JoePea
> >
> > On Sat, Oct 17, 2020 at 1:28 PM Randy Buchholz <work at randybuchholz.com>
> wrote:
> > >
> > > I think some form of bundling will always be necessary. I use classes
> and took a name-spaced and typed approach to modules and classes, putting
> each class in its own module in a file hierarchy (namespace). This is an
> enterprise level LOB application with dozens of classes. Many classes are
> used cross-domain, limiting static/design-time bundling approaches. Also,
> an issue I encountered with static bundling is that classes aren't hoisted,
> so there are ordering concerns/issues with class bundles.
> > >
> > >
> > >
> > > I have multiple workers as background services that use these. Each
> class usually has a few imports for the classes it uses. Using normal
> imports, I was soon generating 100's of requests for the files. Even with
> caching, there is a lot of overhead. As classes are used more, this can
> become a real issue.
> > >
> > >
> > >
> > > I ended up with an approach where I added dependency metadata to each
> class to support bundling. The metadata helps with the "what to send"
> issue. When I need a class/type do an import for it. The server walks the
> dependencies, and bundles the request class with the full tree of
> dependencies. When the client receives the bundle it adds the new classes
> to a type library. It's designed for enterprise use where you have more
> control of things and can enforce standards.
> > >
> > >
> > >
> > > Class looks like this:
> > >
> > >
> > >
> > > // File Bar.cmjs
> > >
> > > ```
> > >
> > > //::Requires: Foo.Package.Class1 Foo.Package.Class2
> > >
> > > class Bar {
> > >
> > >     const a = new Class1(); // Actually usually the qualified
> > > Foo.Package.Class1
> > >
> > >     ...
> > >
> > > }
> > >
> > > ```
> > >
> > > // File /Foo/Package/Class1.cmjs
> > >
> > > ```
> > >
> > > //::/Requires: Common.Util.Whatever
> > >
> > > class Class1{
> > >
> > >
> > >
> > > }
> > >
> > > ```
> > >
> > >
> > >
> > > The basic idea is that when the server gets a request it reads the
> "Requires" and gets those files, recursively reading requires. I keep a
> list of all files and the depth so I know if I already captured a required,
> and how to order the results. Once I have all of the files I write them to
> a single bundle. I don't need to parse the files (Requires is just a
> comment), but can if I want more control. The bundled file looks like:
> > >
> > >
> > >
> > > ```
> > >
> > > class Whatever {...}
> > >
> > >
> > >
> > > class Class1 {...}
> > >
> > >
> > >
> > > class Class2 {...}
> > >
> > >
> > >
> > > class Bar {...}
> > >
> > > ```
> > >
> > >
> > >
> > > It's more complex, because of name collisions and import scoping. What
> I do is process the bundle and promote the classes out of the scope.
> > >
> > > ```
> > >
> > > globalThis
> > >
> > >    .Foo
> > >
> > >       .Package
> > >
> > >          .Class1 = Class1; // (The "newable" class)
> > >
> > >          .Class2 = Class2;
> > >
> > >    .Common
> > >
> > >       .Util
> > >
> > >          .Whatever = Whatever;
> > >
> > > ```
> > >
> > >
> > >
> > > Now I can just do `new Foo.Package.Class1()` anywhere in the context,
> not just in the import scope. On the client I use `inject` in many places
> instead of `import` - inject('A.B.Class'); const x = new A.B.Class();`.
> This checks for the type, and if it doesn't exist on the client it requests
> it from the server.  The server creates a bundle for it and its
> dependencies. I add these to the type-tree. My server isn't really
> import-aware, I just use middleware to intercept the request. This is why I
> could use a way to identify "import requests". I know when I’m doing an
> ”import” through injection, but with a regular import I have to do some
> inspection of the fetch to know to initiate the process.
> > >
> > > _______________________________________________
> > > es-discuss mailing list
> > > es-discuss at mozilla.org
> > > https://mail.mozilla.org/listinfo/es-discuss
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20201022/c610e449/attachment-0001.html>


More information about the es-discuss mailing list