Skip to content

Keep the gzip copy of dotnet.native.wasm - #19

Merged
gmurray81 merged 2 commits into
vnextfrom
btraykov/keep-runtime-gzip
Nov 11, 2026
Merged

gmurray81 merged 2 commits into
vnextfrom
btraykov/keep-runtime-gzip

Conversation

@turbobobbytraykov

@turbobobbytraykov turbobobbytraykov commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

#14 dropped every gzip (.gz) copy from the published site to shrink the artifact that each deployment downloads. This PR brings back one of them: _framework/dotnet.native.*.wasm.gz, the 108 MB runtime as a 27.9 MB download. It was the middle option discussed for #14: gzip-only clients keep a compressed runtime, which is the one file that matters, and the artifact keeps most of the saving.

Changes

  • DropGzipCopies target: after publish, deletes wwwroot/**/*.gz except _framework/dotnet.native.*.wasm.gz.
  • web.config: brings back the gzip rules Ship only Brotli copies of the WebAssembly site #14 removed, only as far as this one copy needs: the .gz MIME type, the Gzip copy rewrite (it serves a .gz only where one exists), the Gzip encoding rule, and .gz in the wasm type and Vary patterns. Gzip encoding applies only to 200, 206 and 304 responses, so an IIS error page for a .gz path gets no Content-Encoding (the same check Set explicit Cache-Control headers for the WebAssembly site #16 adds for .br).
  • CI (Validate deployable site): fails unless the only published .gz is _framework/dotnet.native.*.wasm.gz.

Effect

The sizes are from the .NET 9 build. With #18 (.NET 10), dotnet.native.wasm is about 4% larger, and so is its gzip copy.

  • Artifact: about 79.6 → 107.5 MB zipped (+27.9 MB), still 18.7 MB smaller than before Ship only Brotli copies of the WebAssembly site #14. That's about 1.5 minutes more per IIS node at the 0.3 MB/s measured during US hours, and seconds at night.
  • Browsers: no change. Every browser that can run the app accepts Brotli and gets the .br copies.
  • Clients without Brotli: they get dotnet.native.wasm as gzip again. The other files come as they are, or compressed on the fly by nginx where it does that.

Why keep this one copy

No browser that can run the app is gzip-only. The .NET runtime refuses to start without WebAssembly SIMD and exception handling, which means Chrome/Edge 95+, Firefox 100+ or Safari 16.4+. All of them send br on HTTPS, and page scripts can't change Accept-Encoding.

Who is gzip-only:

  • Visitors behind a TLS-inspecting proxy that removes br. Cisco Secure Access, Check Point gateways with HTTPS inspection and Symantec ProxySG document this.
  • Tools such as link checkers.

What that means for this app's visitors: they are .NET developers evaluating the controls, many of them through the documentation, which embeds the samples. Many will be on company networks, which is where such gateways are deployed. So a group that is rare across the web is likely more common here. We have no data on its size.

What a gzip-only client downloads on a first visit (estimated from the measured file sizes):

All .gz copies (before #14) No .gz copies (vnext now) This PR
Staging ~44 MB ~51 MB ~47 MB
Staging, behind a proxy that adds Via (Squid does by default) or uses HTTP/1.0 ~44 MB ~162 MB ~82 MB
Production, through CloudFront ~44 MB ~127 MB ~47 MB
  • Staging: without a copy, nginx compresses on the fly at level 1, and leaves .ttf, .dat, .svg, .ico and .webmanifest uncompressed. For dotnet.native.wasm that was 31.7 MB, against 27.9 MB for the stored copy.
  • Via or HTTP/1.0: staging nginx compresses nothing for these requests (gzip_proxied and gzip_http_version defaults).
  • Production: every request reaches nginx through CloudFront, which adds Via. CloudFront itself compresses only objects up to 10 MB, so without the copy the 108 MB runtime would go out uncompressed, unless production nginx sets gzip_proxied.
  • Before the production deploy, confirm that the CloudFront cache policy for this path enables both Gzip and Brotli. A policy that caches gzip only forwards Accept-Encoding: gzip for every viewer, and then every visitor would get the gzip path (~47 MB instead of ~28 MB with Brotli).

Merge order

Verified

  • Publish: an interpreter-mode publish of this branch (vnext 7c3993e plus this change) leaves exactly one .gz, _framework/dotnet.native.*.wasm.gz. It passes this branch's Validate deployable site step, including the checks from Turn off the PWA service worker #12, Preload only the six Open Sans faces the samples use #13 and Ship only Brotli copies of the WebAssembly site #14.
  • IIS Express, on that output:
    • dotnet.native.wasm: a Brotli client gets Content-Encoding: br, a gzip-only client gets gzip, and a client that accepts neither gets the plain file.
    • Every other file: a gzip-only client gets the plain file.
    • Every response keeps its own Content-Type and Vary: Accept-Encoding.
  • CI check: passes for that layout and fails for an extra .gz, a missing runtime copy, and a runtime copy outside _framework. It checks the published files, not web.config; the serving behaviour above was checked by hand on IIS Express, including that a 404 for a .gz path gets no Content-Encoding.

🤖 Generated with Claude Code

Gzip-only clients (TLS-inspecting proxies that remove br) would otherwise get the
108 MB runtime uncompressed wherever nginx does not compress on the fly: requests
with a Via header, such as everything through CloudFront, and HTTP/1.0. Keeping
that one copy costs 27.9 MB of the artifact; the other 520 copies (18.7 MB) still
go. web.config keeps its gzip rules, which serve a .gz only where one exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-up: as #16 does for Brotli, the Gzip encoding rule now applies only to 200, 206 and 304 responses, so an IIS error page for a .gz path gets no Content-Encoding header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gmurray81
gmurray81 merged commit 579fe02 into vnext Nov 11, 2026
gmurray81 added a commit that referenced this pull request Nov 11, 2026
global.json takes vnext's version, which names only the Uno.Sdk. Both
workflows install the newest .NET 10 SDK (setup-dotnet 10.0.x) instead of
reading an SDK from global.json, and the deploy's step that pinned 9.0.315
for CI runs is gone. Visual Studio 2022 17.14 uses the newest SDK it can
load, so it builds the net10.0 targets when a 10.0.1xx SDK is installed;
the README says so.

DropGzipCopies takes vnext's version from #19 (keep the dotnet.native.wasm
gzip copy) and runs for net10.0-browserwasm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants