UwView v1.2.1 — How the Browser (WASM) Build Went From “It Runs” to “It’s Usable”

Release

We’ve released v1.2.1 of UwView, the free, open-source viewer for huge text files.

Almost everything in this release is a fix to the browser (WASM) build. In our recent native-vs-WASM benchmark we wrote that “the speed differs, but the features all work.” Then we sat down and actually used it — and a string of bugs turned up that broke the display itself. Body text going blank, romaji leaking into Japanese input, the tab freezing when switching to context lines. None of them ever occurred on the desktop build.

v1.2.0 was never published: these fixes landed after its distributables had already been built, so we replaced it with v1.2.1. Everything from v1.2.0 (the all-icon toolbar, the session-restore fix, and so on) is included here.


Why Only the Browser Build Broke

Nearly all of it traces back to one thing: the browser reads files in a fundamentally different way.

The desktop build touches the file directly through the OS’s memory-mapped files. If it wants the first byte of line 1,000,000,000, it just reads it. There is no such thing as “not available yet.”

The browser build has no such option. A local file arrives as a Blob, and the only way to read it is to slice it into 256 KB chunks and fetch them asynchronously. In other words, “the data at the position I want to read hasn’t arrived yet” is a routine state.

And the code we brought over from the desktop build had no concept representing that state at all. That is the epicentre of virtually every bug in this release.


What We Fixed (Browser Build)

Body text not displayed / wrong line numbers

This was the worst of them. Line numbers lined up with blank body text, floods of … (omitted), a search-results list full of empty rows — and it got worse the more you scrolled.

The cause: “not fetched yet” was being mistaken for “end of file.” Once the code decided it had hit the end, whatever it read (nothing) counted as a correct result — and got baked into the cache. When the data did arrive, nothing changed, because the lookup hit the cache.

Two fixes. Detect the not-yet-arrived state explicitly and never cache an incomplete result, then redraw once the data lands. And the search-results list now reads directly from each line’s starting byte offset instead of going through line numbers (going through line numbers meant reading a different line whenever data was missing).

The same fix also resolved line numbers in search results being off (line 5,000 shown as 4,865, for example). Same root cause.

Romaji left behind by Japanese input

A very visible one: typing 東京 into the search box produced toukyou東京.

The browser implementation of our UI framework (Avalonia) does not exclude key input while an IME composition is in progress. Since the problem sits in the framework, we added handling on the browser side, before the event reaches the framework, to suppress key input during composition. Only committed characters go into the box now.

The tab freezes on ±N context lines

Switching the search-results list to “± 1 context line” could freeze the whole browser tab.

Resolving line numbers for every hit would hit unfetched data and spin forever: request the fetch, recompute, still not there, request again. WASM runs on a single thread, so a loop like that takes the UI down with it.

Line-number resolution is now asynchronous and caches its results instead of redoing them. Right after you switch, the hit lines appear immediately; the surrounding lines are added once resolution completes.

Colour labelling targeted the wrong word

You’d select ref, and the colour palette’s header would say nd — the word just before it.

The browser build can’t use a monospace font and falls back to the bundled proportional font. But word selection alone was still computing coordinates as if every character had a fixed width. Both the “which word is under the click” logic and the selection outline drifted. Both now use the actual rendered width, the same as search highlighting, so it stays correct even on lines containing tabs.

Slow loading and searching

When we measured it, passing the data around cost more than the search itself. Bytes were being converted between the browser and the program one at a time — roughly 23 million conversions for a 22 MB file.

It now copies in bulk into a memory region. For reference, here are the pre-fix measurements (22.4 MB, 400,000 lines, 400 hits):

Operation Desktop build Browser build (before fix)
Load (index build) 19–28 ms 473 ms
Search 4–5 ms 531 ms

Post-fix numbers are not measured: browser tab throttling made it impossible to take stable measurements in our environment. It is clearly faster in practice, but we’d rather say so honestly than publish a number we can’t stand behind.


Two Shared Fixes That Also Land in the Browser Build

Not WASM-specific, but they fix the browser build just the same.

Blank screen when dragging the scrollbar to the bottom. The scrollbar’s maximum was set to the total line count, so at the bottom the first visible line went out of range (line 400,001 of a 400,000-line file). The maximum is now capped one screen short. This one affected the desktop build too.

Slow scrolling in the search-results list. The list didn’t meet the UI framework’s requirements for virtualisation, so every hit row was regenerated on each rebuild — a million rows for a million hits. It’s now custom-drawn like the main view, rendering only visible rows (measured: 1,000,000 rows generated before the fix, 0 after). That also restored left-drag on the list’s scrollbar thumb, which the list had been intercepting.

On top of that, the results list now keeps its scroll position and ±N setting when you close and reopen it (previously reset every time).


Limitations That Remain

Two structural limits are still there, and we’d rather state them plainly.

Processing almost stops while the tab is in the background. Browsers throttle hidden tabs, and our framework advances work in step with screen updates, which compounds it. Keep the tab in the foreground while working with large files. The desktop build is unaffected.

The speed gap versus native remains. On a 100-million-line file, indexing is about 35× slower and full-text search about 15–20× slower, as covered in the benchmark article. That gap comes from how file access works, not from anything this release could close.

Which is the point: the browser build’s value isn’t speed, it’s running the whole feature set on the spot with nothing to install. This release is what finally makes “the whole feature set” true.


Summary

  • v1.2.1 is almost entirely a browser (WASM) fix release: blank body text, wrong line numbers, IME romaji, the ±N freeze, and mis-targeted colour labelling
  • Nearly all of it had a single root cause — the code had no concept of “this data hasn’t arrived yet”
  • Byte transfer for loading and searching moved from one-at-a-time conversion to bulk copy
  • The bottom-of-scrollbar blank screen and the slow results list are fixed too (these help the desktop build as well)
  • Still outstanding: background-tab throttling, and the structural speed gap against native

Try the browser build with nothing to install at the WASM demo (Chromium-based browsers recommended). Desktop builds are on GitHub Releases.


Sources

  • amru195704/UwView (GitHub) https://github.com/amru195704/UwView
  • UwView Releases (v1.2.1 release notes) https://github.com/amru195704/UwView/releases
  • Browser build (WASM demo) https://amru195704.github.io/UwView/

Premium edition: UwView Pro (on sale, Windows/macOS/Linux)

The commercial edition: “View and search huge files instantly, any time; save the index so the second time onward it opens instantly with line numbers; searching up to about 9x faster; store logs at about 1/9 the size and open them as-is.” One-time $129 / $9 per month.
→ https://uvp.y42u.net/en/pro-en/


From the developer: a list of my apps, Kindle books and open-source projects is on GitHub: amru195704.


Note
The information in this article is provided for reference only, and its accuracy or completeness is not guaranteed. Features and figures reflect the state at the time of writing and may change in future updates. If you notice any errors or inaccuracies, please let us know in the comments and we will review and correct them.

コメント

Copied title and URL