Measuring code size

The size dialog measures what your code adds up to: the source document, every exported file, the worker bundle and the imports the worker loads. It measures locally, with no deployment needed, or one deployed route, or any saved version of it, and it tells you which files are served as you wrote them. This guide shows how to open it, what each measurement does, how to read the report, and how to get the same numbers from a script.

Opening the dialog

CommandKeysOpens
Code: Size…Alt+Shift+S / ⌥+⇧+SLocal.
Code: Size (Deployed)…None. It is in the F1 palette.Deployed, for the first route. It falls back to Local when there are no routes.
File menu (Alt+F) ▸ Code ▸ SizeNoneLocal. Shift + click or Shift+Enter opens Deployed.

The tooltip of the menu item reads "Local code size, with deployment measurements when routes are available." and "Deployed route: Shift click". The menu item is hidden in embedded playgrounds; the palette item and the shortcut remain. From a script, edge.size.open() opens it. A failure while opening shows as a toast.

What the dialog shows

The URL sizes are the complete UTF-8 bytes of the playground URL, in its plain form (v1) and in its compressed form (v2, #v=2&c=…). Local marks the encoding in use as Active: v2 once the raw state reaches 8,192 characters and v2 is shorter. Deployed measures the saved URL of the version and marks the encoding that was Stored. See Linking and embedding.

Local measurement

Local needs no routes, no history and no deployed files. It measures:

The local composition is the source document plus the separately generated worker bundle. The dialog says so: "Export sizes are already included in the source document. Included adds the separately generated worker bundle." The second sentence appears only when the code has a <script type=worker>. The status line reads "Local source", "Local source + bundled worker", "Estimated · bundling local worker" or "Estimated · local worker bundle unavailable", and adds "Some import sizes unavailable" when that applies.

Deployed measurement

Deployed, for the current deployment, measures one route: the one chosen in the Route select.

Status glyphs

In Deployed mode, each file has a glyph:

GlyphMeaning
✓Verbatim: the SHA-256 of the served bytes equals the local export.
≠Differs from the local source.
~Not byte-comparable, because it is re-serialized on deploy. That covers every export that is not raw script or style text or a data-URL image, and the root document.
✗Not deployed, or the request failed. It shows "HTTP n" or "failed".
…Pending.

Local rows have no glyph. See Deploying.

Saved versions

In Deployed mode, the Version select lists "Current deployment" and the newest 100 saved versions, each as "date · sha7 · deleted · note". A script can also pick a version by its index, 0 for the newest, or by a unique prefix of its SHA. See Versions and undo.

Reading the report

Composition

The Composition panel has one toggle button for each content type, plus markup and worker, each with its share in percent and its size. A stacked bar shows the shares, and an Included total, or "Known" for a partial archive, sums them.

  • Clicking a type excludes or includes it. The file table hides the rows of that type, worker hides the worker section, and markup hides the root row. The exclusions are remembered separately for Local and Deployed until you reload.
  • Deployed composition uses the deployed root, scales the exports down when they exceed it, and adds the worker.
  • The status line says how firm the numbers are: "Measured deployment", "Approximate · exports scaled to root size", "Estimated · measuring deployment", "Estimated · deployed root unavailable", "Estimated · some deployed files unavailable" or "Estimated · worker bundle unavailable". For an archive, it says "Archived payloads" or "Archived deployment attempt", followed by · failed, · deleted version, · partial and · known bytes only where they apply.

Units

By default, sizes are split into decimal units in aligned columns: 1,166,713 bytes show as 1MB 166kB 713B, with 1 kB being 1000 bytes. Press b to toggle exact grouped bytes, 1,166,713 B. The JSON report always has raw bytes.

The table and its keys

Click a sortable header, which are file, bytes or source, deployed and wire, to sort, and click again to reverse. The root row stays first. These single-letter keys work while the focus is not in a text field and no Alt, Ctrl or ⌘ is held:

KeyWhat it does
/Focuses the filter, which matches a substring of the path. The sum rows then show n/total.
rMeasures again, and reads the history again.
bToggles the units.

Enter on a sortable header, or Space, sorts it. Enter on a file row, or a click on a row without a text selection, closes the dialog and selects the o:=<name> attributes of that file in the editor. The root goes to line 1. If the attribute is missing, a toast reads "Not found in the source: o:=<name>". Archives cannot be revealed. Clicking the worker heading or its rows reveals the <script type=worker> tag or the import specifier. Copy as text copies the aligned text report with the current units, filter and exclusions, and shows "Size table copied as text".

While it measures

Switching the mode, the route or the version, or closing the dialog, stops the running measurement. Closing focuses the editor. The previous table stays dimmed until the new rows arrive. The status line reads "Measuring…", "Loading archived payload…", "Loading versions…", "Measurement unavailable: <msg>", "Versions unavailable: <msg>", "No saved versions" or "Newest 100 saved versions".

From a script

The dialog is a front end for edge.size(). Run these from io.eval.js or the playground tab's DevTools console. See edge.size() for the full reference.

edge.size(options)

Returns a promise of the JSON report. It measures the first route of Code.D by default, or Local when there are no routes.

edge.size.text(options)

Returns the aligned text report, as Copy as text does. Besides the options below, it takes units ('human' or 'bytes'), order ('size' or 'doc'), cols (132 by default), q, a path substring filter, and off, a Set of content types to leave out.

edge.size.local()

Returns a snapshot of what the source would deploy, with no network use: no deployed fetches, no import resolution and no bundle.

edge.size.open(options)

Opens the dialog, on Local by default and on Deployed when you pass a version. It works without routes.

The options of edge.size() are mode, where 'local' forces Local and any other value means Deployed when a route is available, route, one of Code.D, version, refresh and signal. A version is 'current' for the live deployment, a non-negative integer for the n-th newest of the newest 100 saved versions, or a hexadecimal SHA prefix of 1 to 40 characters that must match exactly one version. A string of digits such as '2' is a SHA prefix, not an index. The promise rejects for a bad combination: "A saved version requires Deployed mode.", "A saved version requires a deployment route.", "Unknown deployment route: <route>", "Unknown deployment version: <ref>" and "Ambiguous deployment version: <ref>".

The local size as JSON, and as text

js
const { total, exports, worker, complete } = await edge.size({ mode: 'local' });
({ total, exports, worker, complete })

Keep the semicolon before a line that starts with (. Without it, the parenthesized object is parsed as a call on the previous line.

js
await edge.size.text({ mode: 'local', units: 'bytes', order: 'doc', cols: 100, off: new Set(['markup']) })

The live deployment against a saved version

js
const live = await edge.size(), saved = await edge.size({ version: 0 });
({ live: live.total, saved: saved.total, issues: saved.issues })

'current' measures the live deployment and 0 the newest archive. This needs Code.D, and sign-in for the archive. Check complete, issues and total.partial before you trust the totals of an archive.

js
await edge.size.open({ mode: 'deployed', route: Code.D[0], version: 1 })   // the dialog on the second-newest saved version

Browser requirements

Code Size uses CompressionStream with gzip, Resource Timing, Intl.NumberFormat unit formatting and URL.parse(), which it needs to resolve export paths and worker imports. The v2 URL size also needs Uint8Array base64 support. Without it, only the URL sizes show "URL sizes unavailable: …". See Browser support.

See also