Skip to content

nianyi778/unplugin-version-injector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

37 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ unplugin-version-injector - Auto Inject Version & Build Time

πŸ‡¨πŸ‡³ δΈ­ζ–‡ζ–‡ζ‘£ | πŸ‡¬πŸ‡§ English README


πŸ“Œ Introduction

unplugin-version-injector is a lightweight unplugin-based plugin that automatically injects version and build timestamp into all HTML files. It supports Vite, Webpack 4/5, Rspack, Rollup and Rolldown, and works seamlessly with both SPA and MPA projects.


✨ Features

βœ… Injects <meta name="version"> and <meta name="project"> into the <head>
βœ… Injects <script> into the <body> to log version, name, and build time
βœ… Supports Vite, Webpack 4/5, Rspack, Rollup, Rolldown
βœ… Fully compatible with Multi-Page Applications (MPA)
βœ… Customizable version, project name, date format, and theme-based console styling
βœ… Date format supports dayjs-style patterns (YYYY-MM-DD HH:mm:ss) with zero extra dependencies
βœ… Optional: attach a version header (X-Client-Version) to fetch / XMLHttpRequest requests to identify clients in backend logs


πŸ“¦ Installation

# Using npm
npm install -D unplugin-version-injector

# Using yarn
yarn add -D unplugin-version-injector

# Using pnpm
pnpm add -D unplugin-version-injector

πŸš€ Usage

πŸ“Œ Vite

// vite.config.ts
import versionInjector from 'unplugin-version-injector/vite';

export default {
  plugins: [versionInjector()],
};

πŸ“Œ Webpack 4/5

// webpack.config.js
const versionInjector = require('unplugin-version-injector/webpack');

module.exports = {
  plugins: [
    versionInjector({
      version: '1.2.3', // Optional: manually specify version
    }),
  ],
};

πŸ“Œ Rspack

// rspack.config.js
const versionInjector = require('unplugin-version-injector/rspack');

module.exports = {
  plugins: [versionInjector()],
};

πŸ“Œ Rollup

// rollup.config.js
import versionInjector from 'unplugin-version-injector/rollup';

export default {
  plugins: [versionInjector()],
};

πŸ“Œ Rolldown

// rolldown.config.js
import versionInjector from 'unplugin-version-injector/rolldown';

export default {
  plugins: [versionInjector()],
};

πŸ§ͺ Example Output

In your final HTML output:

<head>
  <meta name="version" content="1.2.3">
  <meta name="project" content="my-project">
</head>
<body>
  <script data-injected="unplugin-version-injector">
    // console badges:
    //  my-project@1.2.3
    //  Build Time: 2024-04-01T12:00:00.000Z
  </script>
</body>

πŸ”§ Configuration Options

Option Type Description Default
version string Custom version number Read from package.json
name string Custom project name Read from package.json
log boolean Whether to inject the console log script true
formatDate string | ((date: Date) => string) Custom build time format: a dayjs-style pattern (e.g. 'YYYY-MM-DD HH:mm:ss') or a function ISO 8601 format
requestHeaders boolean | RequestHeadersOptions Attach version/build-time headers to outgoing requests false
nonce string CSP nonce added to the injected inline <script> tags β€”

version and name can be provided independently β€” whichever is missing falls back to the nearest package.json.


πŸ“… Formatting build time (formatDate)

formatDate accepts two forms, and applies to both the console banner and the X-Client-Build-Time header:

// 1) dayjs-style pattern (built-in lightweight impl, no dayjs needed)
versionInjector({ formatDate: 'YYYY-MM-DD HH:mm:ss' }); // 2024-04-01 12:30:45

// 2) custom function
versionInjector({ formatDate: (date) => date.getTime().toString() }); // timestamp

Supported tokens: YYYY YY MMMM MMM MM M DD D dddd ddd dd d HH H hh h mm m ss s SSS SS S A a.


πŸ“‘ Request Headers (identify clients in backend logs)

Enable requestHeaders to patch window.fetch and XMLHttpRequest so requests carry the client version and build time β€” making it trivial to tell which client build produced a request in backend/API logs. Two headers are injected by default:

X-Client-Version: my-app/1.2.3
X-Client-Build-Time: 2024-04-01 12:00:00

Because it patches fetch / XMLHttpRequest, axios and most HTTP clients work automatically. navigator.sendBeacon and WebSocket connections cannot carry custom headers and are not covered.

RequestHeadersOptions

Option Type Description Default
versionHeaderName string Version header name; value is ${name}/${version} 'X-Client-Version'
buildTimeHeaderName string Build-time header name; value is the formatDate output 'X-Client-Build-Time'
include (string | RegExp)[] Extra cross-origin allowlist: string = URL prefix, RegExp = full-URL test. Same-origin requests are always injected []

Scenario 1: same-origin (simplest)

Page and API share an origin, or you use a dev-server proxy (requests hit /api, which the browser treats as same-origin):

versionInjector({ requestHeaders: true }); // true = defaults, same-origin only

Scenario 2: custom header names

versionInjector({
  requestHeaders: {
    versionHeaderName: 'X-App-Version',
    buildTimeHeaderName: 'X-App-Build',
  },
});

Scenario 3: a single cross-origin API (most common in prod)

Front end and API are on different origins β€” add the API origin to include (string = URL prefix):

versionInjector({
  requestHeaders: { include: ['https://api.example.com'] },
});

Scenario 4: multiple cross-origin APIs / RegExp

versionInjector({
  requestHeaders: {
    include: [
      'https://api.example.com',
      'https://auth.example.com',
      /^https:\/\/[^/]*\.example\.com\//, // any *.example.com subdomain
    ],
  },
});

Scenario 5: Monorepo + all cross-origin (the trickiest) ⭐

Many packages share one build config, and each app talks to cross-origin APIs that differ per environment (dev / sandbox / prod). Two keys:

1. Write include once in the shared root config β€” every package inherits it (put the plugin in the shared configureWebpack / vite config).

2. Don't hardcode origins β€” build them from env vars. Each app's .env.* usually already defines its API origins:

// shared root build config (webpack example)
const versionInjector = require('unplugin-version-injector/webpack');

// provided by each app / each environment's .env
const apiOrigins = [
  process.env.VUE_APP_API_ORIGIN,
  process.env.VUE_APP_SDK_API_ORIGIN,
  process.env.VUE_APP_USER_API_ORIGIN,
].filter(Boolean);

module.exports = {
  configureWebpack: {
    plugins: [
      versionInjector({ requestHeaders: { include: apiOrigins } }),
    ],
  },
};

dev / sandbox / prod each get the right origins automatically β€” no giant hardcoded list.

If all APIs live under a few fixed base domains, a single RegExp also works (new subdomains match automatically):

versionInjector({
  requestHeaders: {
    include: [/^https:\/\/[^/]*\.(example\.io|example\.dev|sandbox-example\.com)\//],
  },
});

Only include API origins you actually fetch/XHR and whose CORS you control. Don't add CDNs or third-party SDK script hosts β€” that only triggers preflights and can break asset loading.

⚠️ Cross-origin requires backend cooperation (CORS preflight)

Custom headers on cross-origin requests trigger an OPTIONS preflight. Every API service matched by include must allow the two headers, or the browser blocks the request:

Access-Control-Allow-Headers: X-Client-Version, X-Client-Build-Time

This is exactly why cross-origin injection is opt-in via include rather than on by default.

πŸ” Same-origin or cross-origin?

Open the browser Network tab and look at the request's real URL:

  • http://localhost:9040/api/... (via dev proxy) β†’ same-origin, requestHeaders: true is enough, no include.
  • https://api.xxx.com/... (direct) β†’ cross-origin, must be in include + backend must allow the headers.

🌍 Why Use This Plugin?

  • πŸ›  Plug and play
  • πŸš€ Helps identify deployed versions
  • πŸ“… Track build timestamps
  • 🎯 Works across major bundlers
  • 🧩 Easily configurable

πŸ“œ License

MIT License Β© 2024 Nian YI


πŸ”₯ unplugin-version-injector – the simplest way to track version and build info!

About

unplugin-version-injector is a powerful and lightweight plugin that automatically injects the version number and build timestamp into all HTML files. It supports Webpack 4/5, Vite, and Rollup, making it ideal for both Single Page Applications (SPA) and Multi-Page Applications (MPA).

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages