Skip to content

Note

What a PX page actually weighs, and the switch that halves it

Every ux or PX-in-a-browser session loads 718 KB of framework before it draws anything, and a stock station sends all of it uncompressed. Both numbers are readable from the jars, without a station.

  • PX graphics
  • JACE
  • Performance

Written September 2026

The payload is declared in Java, so it can be counted

"Can the controller serve this graphic?" is normally answered with an opinion — it depends, keep it simple, use a Supervisor. It has a measurable form: when an operator opens the view, how many files and how many bytes does the station send, and how much of that is your drawing?

That is answerable without a running station, because the framework declares its own client-side dependency graph in Java. Every module that ships browser code registers a BJsBuild singleton naming exactly one pre-built bundle plus the builds it depends on, and the page writer resolves that set into the nested require() calls it writes into the page. Read the classes and you have the payload the framework will ask for, per view, exactly as the framework computes it. The figures below come from a stock Niagara 4.15 install.

The floor: 718 KB before your graphic exists

Every session loads the same bootstrap, whatever the view contains. The requirejs alias table decides which file each name resolves to, and at stock defaults it resolves to the minified copy of each library:

FileRawGzipped
require.min.js17.2 KB6.4 KB
js.built.min.js (20 AMD modules)50.7 KB23.7 KB
jquery.min.js85.5 KB29.7 KB
bluebird.min.js79.6 KB22.8 KB
handlebars.min.js87.3 KB26.6 KB
underscore.min.js19.2 KB7.4 KB
hbs.built.min.js7.2 KB3.2 KB
lex, log and css plugins8.7 KB3.9 KB
baja.js (the BajaScript plugin)9.0 KB2.8 KB
bs.built.min.js (202 AMD modules)354.0 KB89.8 KB
Total718.4 KB216.3 KB

Twelve files, 718 KB, 222 AMD modules, and not one pixel of anybody's building. BajaScript is the largest single item and it is not loaded by a define([...]) list that a scan would find — the baja! plugin requires it at runtime, which is why it is missing from most estimates of this.

What the view itself adds

Resolving each build's declared closure gives two honest figures rather than one. The certain column is the floor plus every bundle and stylesheet in the resolved graph: those are written into the page's require() blocks and fetched whether or not a particular widget is used. The ceiling adds every loose file a bundle member declares that no loaded bundle provides — the Ace code editor at 446.9 KB, the icon sprite stylesheet at 216.2 KB, moment, the dialogs plugin, jQuery contextMenu. Those are fetched lazily, when something that needs them is instantiated, so a real page lands between the two columns.

ViewCertain (raw / gzip)Ceiling (raw / gzip)
A bare bajaux widget869 / 260 KB876 / 262 KB
PX served to a browser (hx container)1,871 / 507 KB2,816 / 707 KB
Graphics primitives (gx)1,994 / 530 KB2,870 / 713 KB
PX with the standard widget kit2,270 / 597 KB3,146 / 780 KB
A chart on the page2,585 / 682 KB3,735 / 956 KB
An analytics chart3,111 / 793 KB5,006 / 1,280 KB

One bundle dominates all of them: the web editors bundle, 916 KB carrying 417 AMD modules — field editors, property sheet, nav tree, composite editor — pulled in by the graphics module, the standard widget kit, the chart module and the hx container alike. A read-only floorplan on a wall panel gets the whole editing toolkit, because the dependency is declared at build level rather than at view level.

Counted as AMD modules instead of files, a PX page with standard widgets is about 900 modules arriving in 31 requests. That ratio is the bundling doing its job, and it is the reason webdev mode belongs nowhere near a site station: with it on for a module, requirejs fetches that module's members individually and the same view goes from tens of requests to several hundred.

Gzip is off by default, and it is one hidden slot

This is the finding worth acting on. The station's web server does have a gzip handler, and its MIME list covers JavaScript, CSS, HTML, plain text, JSON and the XML types — everything in the tables above. But the handler is only added to the handler collection when the web service's gzipEnabled property is true, and that property is declared HIDDEN with a default of false. You will not see it on the property sheet until you show hidden slots.

Nothing downstream compensates. Module resources are served from /module/* by a file servlet whose only content-encoding path requires the file on disk to already be a gzip file, which no bundle is. The heap-memory file cache that does compress is mapped to /vfile/* only.

Out of the box, a PX page ships about 2,270 KB of uncompressed JavaScript and CSS to every operator whose browser cache is cold. With the switch on, about 597 KB. As arithmetic rather than measurement: on a 10 Mbit/s link that is 1.9 s of transfer against 0.5 s; on a 2 Mbit/s site uplink, 9.3 s against 2.4 s, per cold operator.

Two caveats, both checkable. The gzip handler is present in the compact3 build of the web server that ships in the controller's own distribution file, so this is not a Supervisor-only switch. And the trade is controller CPU: this path is not cached, so it compresses per response. Turn it on deliberately, having tested it on your own hardware, before doing it at a site where many operators log in cold at once.

The second load is nearly free, and every upgrade makes it cold

Module files are long-term cacheable by construction: because they live in a module's space, the servlet sends Cache-Control: private, must-revalidate, max-age=2592000 — thirty days. The second graphic an operator opens costs almost nothing, which is the right design.

It has a consequence people meet without recognising it. The page's requirejs config carries a urlArgs cache-buster derived from the last build time, so after a station upgrade or a module install every operator's first graphic is a full cold load again. If that is 2.3 MB uncompressed per operator, the morning after a Tuesday-night upgrade is when the site link gets measured for you.

Caching also switches off in two places that are easy to confuse with webdev: the servlet stops sending those headers if niagara.web.addExpires is set to false, or if its own file-servlet webdev flag is enabled. That is a different switch from the per-module one that makes requirejs fetch loose files.

The controller has no image pipeline at all

The other half of a graphics budget is the artwork, and here the platform decides for you. The controller platform's distribution files name their VM as a compact3 ARM build, and that JVM's rt.jar can be counted: it carries zero classes under java/awt, javax/swing, javax/imageio and java/beans. The 64-bit JRE shipped in the same install carries 599, 1,951 and 89 respectively.

So nothing in a station on that platform can decode, scale, crop or recompress an image. There is no server-side thumbnail and no second chance: the render you engineer is the file every browser downloads, at the pixel dimensions and in the format you saved it. On a floorplan job that single fact usually outweighs every JavaScript figure above, because a render exported at 3000 px wide is a multi-megabyte PNG and the controller will not help you.

What to do with these numbers

  • Budget the framework, not just the drawing. The drawing is usually the small half.
  • Turn the gzip switch on deliberately, tested on the controller, and check it again after an upgrade.
  • Size the image once, correctly, in whatever rendered it.
  • A chart is not free. Putting one on a landing view adds the chart and history bundles to every operator's first load of that page.
  • Reuse view types. Payload is per view type and the browser cache is per file, so five graphics built from the same widget kit pay for the kit once.
  • If a view genuinely has to be light — a wall panel, a phone over 4G, a guard's kiosk — the framework floor is the argument for serving a static page from the station's file space and keeping the station as the data source.

For contrast, the three live demos on this site are one self-contained file each, between 9.9 KB and 19.3 KB, one request, no framework floor — which is not a replacement for PX or bajaux, because they are not editable in Workbench and have no component binding. It is the measurement of what the alternative weighs. The artwork side of the same question is in the note on 3D floorplan graphics, what else the controller is carrying is in what actually runs on a JACE, and the sheets themselves are PX graphics work or a bajaux widget when no stock widget will do.

Related

Where this comes up in the work

More notes

Other things worth writing down

Next step

Tell us the version, the hardware, and what it has to do.

You will get a written scope and a fixed price against it. If the honest answer is that you do not need us, you will get that instead.