nitfixer
v0.4.0
Published
Tags React, Vue and Svelte components with stable ids and emits a source manifest so nitfixer can trace feedback back to source on production builds.
Downloads
459
Maintainers
Readme
nitfixer
Vite plugin for nitfixer. It tags your React components with stable ids at build time and emits a source manifest, so feedback pinned on a production build can be traced back to the exact file and line.
Install
pnpm add -D nitfixerUse
// vite.config.ts
import react from '@vitejs/plugin-react';
import { nitfixer } from 'nitfixer/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react(), nitfixer()],
});A build writes .nitfixer/build/nitfixer-manifest.json, and vite dev keeps .nitfixer/manifest.json up to date. Add .nitfixer/ to your .gitignore.
Both paths sit outside your build output on purpose. The manifest lists your component names and source file paths, so anything inside dist/ would be served publicly by your host. CI reads it straight from the checkout after vite build — the nitfixer Action finds .nitfixer/build/nitfixer-manifest.json with no manifest: input to set — and authenticates with GitHub OIDC, so there is no secret to store either.
If your app also runs an SSR build, that environment writes nitfixer-manifest.ssr.json next to the client manifest rather than overwriting it. Only the client manifest has components in it, and that is the one CI uploads.
Vue and Svelte
The same plugin handles Vue 3 and Svelte 5 single-file components. Their
components compile away at runtime, so instead of a property on a component
function every element in a component's template is stamped with
data-nitfixer="<component id>", and the browser extension rebuilds the
component chain by walking DOM ancestors. Child components, <template>
wrappers, <slot> outlets and <svelte:element> are left alone, so each
component contributes exactly one id.
Install vue or svelte next to the plugin (they are optional peer
dependencies, loaded only when a .vue or .svelte file is transformed)
and register nitfixer() before the framework plugin:
// vite.config.ts
import vue from '@vitejs/plugin-vue';
import { nitfixer } from 'nitfixer/vite';
export default defineConfig({
plugins: [nitfixer(), vue()],
});// vite.config.ts
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { nitfixer } from 'nitfixer/vite';
export default defineConfig({
plugins: [nitfixer(), svelte()],
});The manifest lists one entry per component, named after the file
(pricing-card.svelte becomes PricingCard), with the line of the first
element in its template. The build id import lands inside the component's
script block (one is added when the file has none).
Caching
Vite's output is content-hashed, which is what makes it safe to serve with Cache-Control: public, max-age=31536000, immutable. This plugin writes window.__NITFIXER_BUILD_ID__ into that output, so it owes you the same guarantee, and from 0.3.0 it keeps it:
Two builds with different build ids never produce byte-identical assets under the same file names. The build id is substituted before the bundler computes each chunk's content hash, not after, so a chunk carrying a build id is renamed whenever that id changes.
Expect that rename to spread. A chunk's hash covers the names of the chunks it imports, so everything that (transitively) imports the chunk holding the build id is renamed too. With the default inject: 'modules' the id lands in a chunk shared by your tagged components, which in a typical app means most of the JavaScript graph gets new names on every new build id — the cost of an id you can actually trust. If you would rather confine it, inject: 'entry' puts the assignment in the entry chunks, which nothing imports, so only those are renamed.
It follows that you must not serve the build id from a path whose name doesn't change with it:
index.html(and anyinject: 'html'script tag inside it) is not content-hash-named, so it must not be cached immutably. Standard Vite guidance already says this; scope your immutable rule to the hashed assets directory, e.g./build/assets/*.emitToBundle: truewritesnitfixer-manifest.jsonto a fixed, unhashed file name, and its contents change every build. Another reason to leave that option off; if you do use it, serve that file with a short cache lifetime.
If you deployed 0.1.0 or 0.2.0 behind a CDN, assets already pinned under an old name still carry that build's id. Purge the CDN cache for your assets directory once after upgrading — after that, renames do the work.
Options
| Option | Default | What it does |
| --------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| inject | 'modules' | How window.__NITFIXER_BUILD_ID__ reaches the page: 'modules', 'html', 'entry' or 'none'. |
| manifestPath | '.nitfixer/build/nitfixer-manifest.json' | Where a build writes the manifest — absolute, or relative to the Vite root. Keep it out of your build output. |
| emitToBundle | false | Also emit the manifest as a build asset. This publicly exposes your component names and source paths. |
| devManifest | '.nitfixer/manifest.json' | Where the dev server writes its manifest, relative to the Vite root. false turns it off. |
| manifestFileName (deprecated) | 'nitfixer-manifest.json' | File name of the build manifest inside the default .nitfixer/build/ directory. Use manifestPath instead. |
0.4.0
Adds Vue 3 and Svelte 5 support (see above). Nothing changes for React
projects; vue and svelte are optional peer dependencies, only loaded when
a .vue or .svelte file is transformed.
Upgrading from 0.2.0
0.2.0 and earlier substituted the real build id in Rollup's generateBundle hook — after content hashes had been computed. A chunk whose other content was unchanged between two builds therefore kept the same file name while carrying a different build id, so a CDN or a warm browser cache went on serving the first build's copy. Pages reported a stale build id, and feedback captured on them matched no source mapping (or the wrong one) and never resolved to a file and line. 0.3.0 substitutes the id before hashing instead — see Caching. To upgrade:
- Bump the dependency. There are no API or option changes.
- Purge your CDN cache for the assets directory once, so clients stop being served assets pinned under a name from an older build id.
- If you pin
NITFIXER_BUILD_IDin CI (recommended — it makes the id identical wherever the assets are built), nothing else changes: that id is now baked straight into the module graph rather than patched in afterwards.
Upgrading from 0.1.0
0.1.0 emitted the manifest as a build asset, so it shipped inside dist/ and was served publicly. 0.2.0 writes it to .nitfixer/build/nitfixer-manifest.json instead. To upgrade:
- Add
.nitfixer/to.gitignoreif it isn't there already. - Drop the
manifest:input from the nitfixer Action (v1.1.0 or newer resolves the new path itself), or point it at.nitfixer/build/nitfixer-manifest.json. - Delete any
nitfixer-manifest.jsonalready deployed with an older build — 0.2.0 stops producing it but does not remove what is already on your host.
With inject: 'none', wire the build id up yourself:
import 'virtual:nitfixer-build-id/global';License
MIT
