Feature Proposal: Lazy Load Javascript and Css

Motivation

As I use javascript popup dialogs more, I find myself needing to get javascript loaded dynamically - some dialogs need charting that isn't present in the loaded topic, or (the currently obvious one - strikeone.js for popup task creation)

it would give us a more dynamic js REQUIRE implementation than we currently have - where the js knows its loaded, so doesn't need to re-load, can load implied dependencies, obey ordering, and generally walk and chew gum at the same time.

additionally, there seems to be a meme about the speed / non-blocking download aspects of doing things this way (the html5 async attr may address this, but not the other possible advantages)

I wold also like to have the ability to trigger an even when the async things are ready smile

Description and Documentation

there are a few blogs about the development of solutions:

implementations :

Examples

I really would like to just add

REQUIRE{strikeone} to something and know that it'll happen irrespective of normal topic view, or delayed load.

or if using a jqDialog css param - to not require anything at all - it'll just know... (yeah, that might be dreaming but meh.)

so presumably there will need to be a REQUIRE_MANIFEST that lists the js, html, css, dependencies, whatever that should be loaded - like JQREQUIRE, but generalised.

Impact

%WHATDOESITAFFECT%
edit

Implementation

-- Contributors: SvenDowideit - 18 Apr 2012

Discussion

Yes we need this for javascript. Not sure about css. At least optimizing css is easier.

Just for clarification: the main difference will be that instead crafting script tags into the html header on the server side, we will add them on the client side after the DOM has been loaded. The browser will then have to decide which scripts to load and in which order.

Question: shall we

  • (a) write our own lazy async loader or
  • (b) use an existing one like RequireJS?

Things to watch out for:

FUBC (flash of unbehaviored content): there might be some js that manipulates the DOM massively as soon as it gets loaded. this might result in flickering or more rerendering than what we have now, or at least easier perceived by the user. Best examples are twisties and tinymce.

With regards to tinymce: there is a rather delicate javascript init process in the way tinymce is loaded into the page right now, i.e. it massively blocks page loading times by executing even before the complete DOM is loaded. Not sure it is compatible with things like RequireJS.

We still generate inline scripts and styles per page. Makes things a bit tricky wrt execution order. From what I see now, only LabJS can deal with this. Please prove me wrong studying the other loaders.

What about users adding javascript to the topic text? Which provisions will they have to follow to play nicely with the code loaded by Foswiki? It might need some macros to interact with the javascript loader.

RequireJS comes with a "module" concept of its own. This doesn't match well the way we plug things into foswiki atm.

HeadJS comes with lots of html5 "cruft" that is better done using Modernizr, imho.

LabJS seems to be equivalent to HeadJS w/o the html5 stuff.

LabJS seems to demand the least overhead organizing javascript files on the backend. It just does what it should do: load the js files.

There's a clear migration path towards making use of LabJS.

Before:

<script src="framework.js"></script>
<script src="plugin.framework.js"></script>
<script src="myplugin.framework.js"></script>
<script>
   myplugin.init();
</script>
<script>
   framework.init();
   framework.doSomething();
</script>

After:

<script>
   $LAB
   .script("framework.js").wait()
   .script("plugin.framework.js")
   .script("myplugin.framework.js")
   .wait(function(){
      myplugin.init();
      framework.init();
      framework.doSomething();
   });
</script>

-- MichaelDaum - 18 Apr 2012

yeah - that was my impression about LabJS and the others :/

-- SvenDowideit - 18 Apr 2012

Another twist to the problem is that content might be loaded async'ly, e.g. using JQueryLoader or using InfiniteScrollContrib. This markup then adds js and css requirements incrementally. For now the only way to deal with this is either to load all js and css before any async markup, or to inline css and js. The latter approach is not available when generating markup client side using JQueryTmpl while reading json from the backend, as is the case in SolrPlugin.

-- MichaelDaum - 15 Jan 2013

In the past I've just used jQuery.getScript() - I realize this comment is perhaps unhelpful smile

-- PaulHarvey - 29 Jan 2013

This here looks like it was made for us: https://github.com/ded/script.js

I ask myself: in how far does lazy loading javascript and css harm SPDY Push?

Loading times on mobile devices are an issue to consider as well, as network round trips on mobile connections are very expensive.

-- MichaelDaum - 25 Feb 2014

A year later we now see ECMAScript 6 modules becoming part of the language. Here are a couple of polyfills that allow us to make use of these standards now:

Some read-up:

-- MichaelDaum - 05 May 2015

We focus on reducing the http requests related to the Wiki Chrome. So we concat all CSS and JS (at least this is our goal) and serve them minified. A wiki wide set of Javascript and CSS get served along all topics. Disabling certain plugins in a topic must be possible by means of Javascript or by declaring/removing a HTML Class.

Adding an additional plugin would still work the old way. Whether a plugin has to add its CSS and JS or can expect them to be part of the skin should be configurable plugin by plugin.

This would be nice!

-- AndreLichtsteiner - 05 May 2015

Concatenating and spriting is not best practice anymore with HTTP/2. Note that this only plays a role on the initial page request. A long-living (single page) app will require further css and js during its live time depending on the topics being requested and the libraries requried for it to render. JS and css is then injected later on demand ... presumably using the ES6 Module Loader. This is going to be a dynamic process as you wouldn't be able to know in advance which pages of a Foswiki site the user clicks on and which libraries are required for it. So configuring it per plugin is not required or even possible.

-- MichaelDaum - 05 May 2015

A bird in the hand is worth two in the bush.

-- AndreLichtsteiner - 05 May 2015

Modern browsers can load css and scripts async or defer attributes.

-- MichaelDaum - 20 Jul 2021
 
Topic revision: r12 - 20 Jul 2021, MichaelDaum
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy