跪拜 Guibai
← All articles
Frontend · JavaScript · Interview

A Build Plugin That Stamps Every HTTP Request with the Frontend Version

By 七月丶 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Production debugging still depends on asking users to clear their cache or guess which build they have. Stamping every request with the frontend version turns backend logs into a reliable source of truth and eliminates a recurring source of friction between frontend teams and ops.

Summary

Frontend version information rarely makes it into backend logs. When a production bug surfaces, the first question is always "which build is the user on?" and the answer is usually a guess. unplugin-version-injector 2.2 closes that gap by injecting a small script that wraps fetch and XMLHttpRequest, automatically attaching X-Client-Version and X-Client-Build-Time headers to every request.

The plugin works across Vite, Webpack, Rspack, Rollup, and Rolldown with a single line of config. Same-origin requests get headers by default; cross-origin APIs require an explicit include list plus backend CORS opt-in. A monorepo setup can read API origins from environment variables so the same shared config works across dev, sandbox, and production.

Beyond request headers, the plugin also stamps a meta tag into the HTML and prints a styled build banner to the console. The 2.2 release adds Rspack and Rolldown support, a dayjs-style date formatter with zero dependencies, full TypeScript types, and 26 unit tests covering the injection logic.

Takeaways
Enabling requestHeaders patches window.fetch and XMLHttpRequest so every outgoing request carries X-Client-Version and X-Client-Build-Time headers.
Same-origin requests get headers automatically; cross-origin APIs must be added to an include whitelist and the backend must allow the custom headers via Access-Control-Allow-Headers.
In a monorepo, API origins can be read from environment variables so a single shared build config works across dev, sandbox, and production without hardcoded domains.
Cross-origin header injection triggers an OPTIONS preflight; adding CDN or third-party script domains to include will break resource loading.
The plugin also injects a meta tag into the HTML and prints a styled build banner to the console, both showing the project name and version.
Version 2.2 adds Rspack and Rolldown adapters, a dayjs-style formatDate option with zero dependencies, full TypeScript types, and 26 unit tests.
Conclusions

Frontend version observability is a solved problem at the infrastructure level for backend services, but frontend builds remain opaque once deployed. This plugin treats the browser the same way a microservice treats its own health endpoint.

The design choice to default to same-origin-only and require an explicit cross-origin whitelist is the right security posture. It prevents the plugin from silently breaking third-party integrations while still making the common case effortless.

Monorepo support via environment variables is the detail that separates a demo from a tool that survives real multi-environment pipelines. Hardcoding domains in build config is a maintenance trap that most teams hit within weeks.

Concepts & terms
CORS preflight (OPTIONS request)
When a browser sends a cross-origin request with custom headers, it first sends an OPTIONS request to check whether the server permits those headers. The server must respond with the appropriate Access-Control-Allow-Headers or the actual request is blocked.
unplugin
A unified plugin system that lets a single plugin implementation target multiple build tools (Vite, Webpack, Rollup, Rspack, etc.) through adapters, avoiding the need to write and maintain separate plugins for each tool.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗