Opened 11 years ago

Closed 11 years ago

#7040 closed enhancement (wontfix)

add dojo._base._stubs for tiny core build appropriate to mobile devices, etc.

Reported by: alex Owned by: anonymous
Priority: high Milestone: 1.2
Component: Core Version: 1.1.1
Keywords: performance, loader, stubs, dojo.js Cc: James Burke, Adam Peller
Blocked By: Blocking:

Description

Today some environment have a problem with the (already small) dojo.js generated by the build system. The time to download and evaluate Dojo for an initial visit may prove too much for these environments. Today, a build that uses the customBase parameter to create a smaller subset of dojo.js is supported by the build tools, but this means that content authors need to know that they should dojo.require("dojo._base.query"); before using !dojo.query, which breaks the "dojo.js always means the same thing" contract.

A better solution for these environments would be a version of the core loader which only includes what's *absolutely* required to bootstrap Dojo and then provides stubs for what isn't directly provided. These stubs should replace themselves at runtime by pulling in the appropriate dojo._base module (if that module isn't already available).

A module to implement this and the profile file used in the build for it are attached.

Attachments (3)

_stubs.js (5.7 KB) - added by alex 11 years ago.
dojo/_base/_stubs.js
stubs.profile.js (208 bytes) - added by alex 11 years ago.
util/buildscripts/profiles/stubs.profile.js
7040.build.patch (8.3 KB) - added by James Burke 11 years ago.
buildscripts patch that injects dojo._base dependencies into files.

Download all attachments as: .zip

Change History (10)

Changed 11 years ago by alex

Attachment: _stubs.js added

dojo/_base/_stubs.js

Changed 11 years ago by alex

Attachment: stubs.profile.js added

util/buildscripts/profiles/stubs.profile.js

comment:1 Changed 11 years ago by alex

a build of Core is available for this configuration:

http://turtle.dojotoolkit.org/~alex/dojo-stubs.tar.gz

This build clocks dojo.js at 17K on disk at ~7k gzipped on the wire, which is less than 1/3 the size of the "stock" dojo.js build. Obviously, the work is only deferred and the overall network and run time will be higher than under a normal build, but for constrained environments or super-high-traffic sites, delaying work like this may be hugely advantageous.

comment:2 Changed 11 years ago by Adam Peller

Cc: Adam Peller added

comment:3 Changed 11 years ago by James Burke

Thinking more about this, I think this would work better as a build step:

  • Have an automated task that builds the base function-to-module mappings like the ones listed in _stubs.js
  • Scan all JS modules in the release directory and insert dojo.require calls for any base function calls found in that file.
  • Do a build with customBase: true and name the layer dojo.js, but do not specify any base dependencies.

This approach ends up with a dojo.js that should be smaller than the stubs-based one, since we just need the normal loader and no _stub.js file in dojo.js. If memory serves, the loader by itself weighs in around 5-6KB gzipped.

This approach also then allows you to specify base modules in the build, or just list your top level modules in the dependencies for dojo.js, and the appropriate base modules will be included automatically in the build: no need to track down the base modules yourself.

This approach also has the benefit of working with xdomain builds (although that is less of a concern).

The downside with this approach means that you have to do a custom build for your application: you cannot do one build that works for all your apps. But it seems likely you will be doing a custom build per application, if you are really trying to squeeze out this much performance.

The trick with this approach is how to autogenerate the function-to-module listings, then also detecting these methods in modules so we inject the proper dojo.require calls for the base modules.

But I think we can work out regexps that should get us close enough.

Changed 11 years ago by James Burke

Attachment: 7040.build.patch added

buildscripts patch that injects dojo._base dependencies into files.

comment:4 Changed 11 years ago by James Burke

I just added 7040.build.patch to the ticket. At build time, it injects dojo._base dependencies into files that reference dojo._base methods.

It is not exact, since regexps are used, but if anything it errs on the side of adding more dojo._base dependencies than less, so errs on the side of safety: dojo._base.event creates a doc variable that is based on a real document. It then calls doc.body on it. This matches the regexp for a method in dojo._base.window, so dojo.require("dojo._base.window") gets added to dojo._base.event.

If a layer has customBase: true set on it, then this dojo._base dependency injection occurs. So, do a build with customBase: true for "dojo.js" layer, and set no dependencies for it. This will generate a dojo.js with just the bootstrap/hostenv/loader.

In this scenario, dojo.js is 10,368 bytes shrinksafed, 5,558 bytes gzipped. dojo.xd.js is 29,480 shrinksafed, 10,368 bytes gzipped. dojo.xd.js includes loader_xd.js, and dojo.i18n. dojo.i18n requires dojo._base.array, which needs dojo._base.lang. We might be able to get the xd version smaller if we break some of those dependencies. It would be nice if dojo.xd.js was under the 25KB ungzipped limit for iphone caching.

Still some more testing to do, but initial testing seems good.

Does this sound like a good enough alternate approach?

comment:5 Changed 11 years ago by James Burke

Looking more closing, the dojo.i18n -> dojo._base.array dependency is a weakness of the regexp approach: dojo.i18n uses an indexOf call on a string. However, dojo._base.array defines an indexOf method, and the regexp finds a match.

We can get around the problem in this case by doing targetLocaleindexOf? in dojo.i18n: that pattern will not match in the build regexp (by design, to get around these kinds or problems).

So, again, another demonstration of the weakness in the regexp approach. However, I feel it is still safer than the stubs approach.

The stubs has a hole with non-function properties, like dojo.doc -- it cannot intercept those calls, so if someone does a dojo.doc call, it could fail if dojo._base.window has not been loaded.

On the doc.body issue in dojo._base.event: I can fix that issue: I can change the base mappings to include specific regexps for function properties vs. non-function properties. That will fix the dojo._base.event case mentioned above.

comment:6 Changed 11 years ago by James Burke

Opened ticket #7119 to track customBase injection of dojo._base dependencies, to avoid further confusing this ticket with two approaches.

comment:7 Changed 11 years ago by James Burke

Resolution: wontfix
Status: newclosed

Closing this out in favor of the customBase injection done as part of #7119.

Note: See TracTickets for help on using tickets.