Vize

Performance Tuning

Performance tuning in a frontend toolchain is not one trick.

It is not "rewrite it in Rust" and then wait for graphs to go up. It is a long series of small, concrete decisions about where the time goes, how often memory moves, how much work is duplicated, and whether the architecture lets improvements compound.

This note is a knowledge-share of the things Vize keeps optimizing for.

Feedback loop diagram showing source files, native analysis, snapshots, actions, and shipping confidence

Measure the Whole Loop

Compiler benchmarks are useful, but they are not the whole developer experience.

A Vue toolchain has several feedback loops:

  • one-file compile in a dev server

  • full production build

  • linting many files

  • formatting many files

  • type checking generated virtual files

  • editor diagnostics while the user types

  • CI checks across real applications

  • AI-generated patches being validated repeatedly

The slowest loop is not always the most obvious one.

A function that looks fast in isolation can still be harmful if it runs in every stage. A small allocation can still matter if it happens for every token, every AST node, every diagnostic, and every generated segment.

That is why Vize treats performance as a toolchain property, not only a compiler property.

Avoid Duplicate Work

The most reliable optimization is to not do the work twice.

In a fragmented setup, the same .vue file can be parsed separately by:

  • the compiler

  • the linter

  • the formatter

  • the type checker

  • the editor integration

  • the component documentation pipeline

That is expensive, but the deeper problem is architectural. If every tool builds its own understanding of the file, performance tuning becomes local and limited.

Vize is designed around shared structure:

  • parse once where possible

  • keep SFC block boundaries stable

  • reuse template structure across compiler and diagnostics

  • let semantic analysis feed multiple consumers

  • avoid regenerating virtual TypeScript unless inputs changed

The best optimization is often a better ownership boundary.

Allocation Is a Feature, Not a Detail

Frontend tooling processes many small objects: tokens, nodes, spans, strings, scopes, diagnostics, generated code fragments.

If those objects are allocated casually, the toolchain pays for it everywhere.

Vize puts a lot of pressure on allocation behavior:

  • arena-style storage for short-lived compiler data

  • string interning where repeated identifiers or names matter

  • compact spans instead of copied substrings

  • borrowed slices where ownership is unnecessary

  • stable internal IDs instead of large cloned structures

The goal is not to make the code clever for its own sake.

The goal is to make the hot path boring: fewer allocations, fewer copies, fewer cache misses, fewer reasons for the allocator to become part of the profile.

Parallelism Needs Shape

Parallelism is not "turn on threads."

It works best when the problem has clear boundaries:

  • many independent files

  • deterministic aggregation

  • predictable output ordering

  • no shared global mutation

  • bounded caches and sessions

Vue compilation, linting, and fixture sweeps often have a natural file-level parallel shape. But type checking and editor workflows are more subtle because they depend on project state.

So Vize separates the questions:

  • Can this file-level work run independently?

  • Does this step need a resident project session?

  • Is the output order user-visible?

  • Are diagnostics stable across thread counts?

  • Does parallelism increase memory pressure enough to erase the win?

Fast but unstable output is not good enough. Performance work has to preserve trust.

Source Mapping Can Become a Hot Path

Vue tooling often generates intermediate code.

That means every good diagnostic needs a path back:

  • generated TypeScript to original template

  • generated render code to SFC source

  • transformed style or script output to original block

  • virtual module IDs back to real files

If source mapping is slow or imprecise, the whole toolchain suffers. The user sees diagnostics in the wrong place. AI repair loops get poor coordinates. Tests become fragile.

So source mapping deserves the same performance attention as parsing:

  • store spans compactly

  • avoid repeated path normalization

  • keep generated segment metadata small

  • test edge cases with snapshots

  • profile diagnostic-heavy workloads, not only successful compile paths

Diagnostics are product surface. Their performance matters.

Real Projects Beat Synthetic Comfort

Microbenchmarks are useful when answering a focused question.

But a toolchain becomes honest when it is run against real projects.

Real projects contain:

  • odd dependency layouts

  • large SFCs

  • legacy patterns

  • auto-generated code

  • uncommon directives

  • plugin conventions

  • path aliases

  • platform-specific edge cases

That is why Vize keeps investing in real-world fixture sweeps and build snapshots. The goal is not to collect impressive test counts. The goal is to expose the performance cliffs that only appear when the code is messy in the same way production code is messy.

Performance Is a Product Feature

Speed changes behavior.

If checks are slow, people run them less often. If formatting is slow, save-on-format becomes annoying. If type-aware linting is slow, teams disable the rules. If CI is slow, maintainers batch changes and review less carefully. If AI validation is slow, agents take bigger, riskier leaps.

Fast tools make stricter workflows practical.

That is the real performance argument for Vize. The goal is not only a better benchmark number. The goal is to make the strict path feel like the default path.

When compile, lint, format, type-check, and diagnostics become fast enough to run without ceremony, quality stops being a special event.

It becomes the normal way to work.