Not all web site files get chunk hashed
We have a website at work which is built by Vue CLI (Webpack) and uses chunk hashes so that deployed artifact names change if the code has changed. That means you dodge the local and cloud caches, and the latest files are always delivered to the user when you deploy an update. Great!
Recently we had a change where it looked like this wasn’t happening, causing a live defect. After a few hours looking into it, we figured out that chunk hashing was working fine.
The real culprit? We were making an HTTPS call using Axios to get some reference data JSON files that we keep in a public
dir on the site. Not a call to an API - just grabbing some files which are part of the frontend project, over the wire.
These files had changed in a critical way, but the old versions were being cached by the local browser and Cloudflare.
As they were just public assets, not import
ed by Webpack anywhere, it didn’t include them in the JS build, so they didn’t get bundled or chunked. Worse - we had set a really long TTL on the public dir using an IIS directive! 🤦
Lesson learned: If you are loading web front end files in some exotic way, remember they may not be delivered the same as the rest of your code! Watch out for these stragglers.
First we deployed a quick fix, which was to change the name of the public subdirectory slightly and remove the TTL rule 😎 no regrets.
The longer term fix was to create a static webpack mapping of each of the required files, so that they can be properly import
ed, and changed how our loader works to get them from the mapper, not via network. Naturally this will also have a performance benefit. The mapper looks a bit like this:
import {
PRODUCT_A,
PRODUCT_B,
} from "@/constants/product.constants";
export const productMapping = {
[PRODUCT_A]: {
type1: {
questions: () => import("@/data/product_a/type1/questions.json"),
application: () => import("@/data/product_a/type1/application.json"),
},
type2: {
questions: () => import("@/data/product_a/type2/questions.json"),
application: () => import("@/data/product_a/type2/application.json"),
},
},
[PRODUCT_B]: {
type1: {
questions: () => import("@/data/product_b/type1/questions.json"),
application: () => import("@/data/product_b/type1/application.json"),
},
type2: {
questions: () => import("@/data/product_b/type2/questions.json"),
application: () => import("@/data/product_b/type2/application.json"),
},
},
...
};
It annoys me that you can’t do this dynamically like:
getImport(product, type, stage) => import(`@/data/{product}/{type}/{stage}.json`);
…but Webpack needs to be able to “see” all the filenames statically at compile time 🤷 oh well!
This is the end of the post 📬🦆