How to Manage Static Asset Versioning in Vue Projects Without Hashes
This guide explains how to replace hash‑based static asset versioning with timestamps or package version numbers in Vue projects, adjust webpack configuration to keep hashes only on chunk files, handle preload/prefetch hints, and coordinate backend updates for reliable cache busting.
Background
In single‑page applications the backend serves a static index.html while all JavaScript and CSS assets are hosted on a CDN (e.g., s.autoimg.cn). Vue CLI adds a content hash to every output filename ( app.3f2a1c.js, chunk-vendor.9b8e7d.js, …). When any chunk changes, the hash of the entry file app.js also changes, forcing the backend to modify the HTML template on each release. To avoid frequent HTML updates the team switched to a dynamic timestamp query parameter (e.g., app.js?v=20240101) that can be regenerated hourly or daily.
Disabling filename hashing
Vue CLI enables filenameHashing by default. Setting filenameHashing: false in vue.config.js removes the hash from all output files, but the generated index.html still references the entry file with a hash‑less name, so the backend must still update the HTML when the entry changes.
Keep hashes for chunks while removing them from the entry file
To retain cache‑busting hashes for lazy‑loaded chunks but keep a stable name for the entry script, customize the webpack configuration:
module.exports = {
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// CSS filenames – keep hash only for chunk CSS
config.plugin('extract-css').tap(options => {
options[0].filename = 'css/[name].css';
options[0].chunkFilename = 'css/[name].[contenthash:8].css';
return options;
});
}
},
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// JavaScript filenames – entry without hash, chunks with hash
config.output.filename = 'js/[name].js';
config.output.chunkFilename = 'js/[name].[contenthash:8].js';
}
}
};After this change the entry app.js is always emitted as js/app.js, while dynamically imported chunks keep a content hash (e.g., js/chunk-vendor.9b8e7d.js), reducing unnecessary CDN invalidations.
Removing resource hints (preload & prefetch)
Vue CLI injects many <link rel="preload"> and <link rel="prefetch"> tags into the HTML head. When the entry hash changes, these hints may still point to the old assets, causing stale downloads. If aggressive preloading is not required, the plugins can be removed:
module.exports = {
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// Remove the prefetch plugin
config.plugins.delete('prefetch');
// Remove the preload plugin
config.plugins.delete('preload');
}
}
};Disabling these hints simplifies version coordination at the cost of a potentially longer initial load.
Using a version string instead of a hash
Instead of a content hash, a stable version identifier (e.g., the version field from package.json) can be embedded in filenames. This makes the URLs predictable across builds and allows the backend to generate matching query parameters.
// vue.config.js (partial)
const pkg = require('./package.json');
const version = pkg.version; // e.g., "0.1.2"
module.exports = {
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.plugin('extract-css').tap(options => {
options[0].filename = `css/[name].${version}.css`;
options[0].chunkFilename = `css/[name].[contenthash:8].${version}.css`;
return options;
});
}
},
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.output.filename = `js/[name].${version}.js`;
config.output.chunkFilename = `js/[name].[contenthash:8].${version}.js`;
}
}
};The version can be bumped with npm version (e.g., npm version patch), which updates package.json and creates a Git tag. The backend should append the same version as a query parameter, e.g., app.js?v=0.1.2, to keep preload/prefetch links in sync.
Important notes on preload/prefetch with versioning
Even when using a version string, the HTML template must embed the identical version in the rel="preload" and rel="prefetch" links; otherwise those hints become ineffective. A common approach is to expose a helper function (e.g., addVersion()) in the entry script that injects the correct version at runtime, or to let the backend render the version directly into the HTML.
References
For advanced webpack-chain configuration see the repository: https://github.com/neutrinojs/webpack-chain
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
