ES6 module loader issues: preloading, and CSS imports

Ian Hickson ian at hixie.ch
Tue Aug 19 16:38:53 PDT 2014


On Tue, 19 Aug 2014, caridy wrote:
> 
> IMO, it is a bad idea to use the loader for preloading things.

The problem is that you need to, otherwise if someone suddenly invokes the 
things in question you won't be able to relate the preloading that is 
already on the fly with the actual loading that gets triggered, because 
they'll be independent.


> If you really care about performance, you will probably put in place a 
> build process to understand the dependency graph, and find a way to 
> allocate those scripts in the browser's cache somehow.

It has to be more than the cache -- the idea is to even preparse the 
script. But yes, being able to do exactly this is what I'm looking at 
doing. The idea is to use the ES6 module loader to do this.


> Using the loader for that is abusing it

I don't see why. The alternative is to have to have all this code twice, 
once for loading and once for preloading, which seems like a non-starter.


> you just need the dependency graph and a way to generate those urls, and 
> in theory you can do that offline to produce some sort of meta to 
> preload (in any way you want).

The idea is to do away with the need for such redundant information in the 
HTML file, where possible.


> You could even rely on SPDY and the knowledge about the dep graph to 
> hint files to be prefetch by the browser during the initial render of 
> the page.

Unfortunately many authors don't have sufficient control over their 
servers for this kind of thing.


> > This would also allow for ES6 import syntax to be used inline to declare 
> > some dependencies, as in the case of an inline script marked as being 
> > on-demand containing something like:
> > 
> >     import "jquery";
> >     import "jquery/animations";
> >     import "myapp/logic";
> > 
> > If the browser could notice that this was an inline script and have 
> > the ES6 module system pre-parse it to discover the imports, it could 
> > preload them and then when the script element's execute() or load() 
> > method (whatever we end up calling it) is invoked it could just 
> > unblock the execution and immediately have the scripts run.
> 
> are you talking about `<script type="module">` proposal? if yes, those 
> are going to be async, non-blocking, etc. due to the nature of the 
> import syntax.

Not sure how that relates to the above. The download would of course be 
non-blocking. Execution itself would be done as part of a task (ES job), 
which is on the main event loop. But that seems orthogonal to the issue.


> > Assuming we use the ES6 module loader to handle all the loads in an 
> > HTML document, in the Web context, there are also some interesting 
> > questions to resolve around the issue of de-duping.
> > 
> > Suppose you had an inline style element markup containing:
> > 
> >    @import "http://example.com/foo.x";
> > 
> > ...followed by an external script element src="" pointing to:
> > 
> >    http://example.com/foo.x
> > 
> > This causes foo.x to be evaluated once as a style sheet, and once as a 
> > script. In the new world, though, if every load goes through the ES6 
> > module system, how do we distinguish them in the module registry?
> 
> URI of the resource, that's unique, no matter how you invoke the 
> fetching and execution of the module, the URI is going to be the same.

Yes, but the context matters for how it's interpreted.

The same URL used in an @import and in a <script src=""> will get treated 
differently, even assuming it returns the same data.

 
> Even if you have `import foo from "foo"`, where foo is resolved thru 
> some loader extensions, it resolves to a URI, therefore Loader will be 
> able to reuse the instance, very similar to nodejs internal registry for 
> modules.

Right. The point is that the @import _can't_ reuse the same module 
instance if it was interpreted as JS, because of the semantics of @import. 
Sometimes, the same URL is going to need to be loaded again with a 
different context. So we need to be able to associate that context in or 
before the "normalize" hook, so that when the result of "normalize" is 
looked up in the registry, we don't get the same result for those 
different contexts.


> > It would be great if it was possible to attach metadata to the key 
> > that is used in the registry that would be part of the registry key 
> > but not exposed in the module API. For example, @import could tag all 
> > its modules as "CSS", so that the above would be keyed as 
> > {"http://example.com/foo.x", CSS}. Regular imports wouldn't key 
> > anything, so that in the case of an inline CSS block followed by an 
> > inline ES6 module both importing the same file, the second import 
> > would find the pre-existing CSS import rather than try to introduce a 
> > new one.
> 
> create a custom extension that uses the loader hooks to do whatever you 
> need.

Can you elaborate on this?


> At this point, we don't know how the internal registry will work, how it 
> will be exposed, and how you will interact with it, we are still working 
> on that. But one thing is sure, you should be able to keep your own 
> registry (a la System.JS) to do your own thing if needed.

The registry I'm talking about is the Web browser's built-in registry. If 
that's not the same as the ES6 module registry, then we've presumably 
failed somewhere since that means you can't get to the ES6 one. :-)

-- 
Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'


More information about the es-discuss mailing list