node -v): 10.14.2npm -v): 6.4.1I'm preloading some webfonts by outputting their paths (without any cache-breaking parameters):
<link rel="preload" href="/build/fonts/Reader.woff" as="font" type="font/woff" crossorigin>
However, when compiling SCSS to CSS, Laravel Mix appends cache-busting hashes to webfonts in the CSS:
@font-face {
font-family: "Reader";
src: url(../fonts/Reader.eot?f1ec82fc66114487463c45960084a510);
src: url(../fonts/Reader.eot?f1ec82fc66114487463c45960084a510) format("embedded-opentype"),
url(../fonts/Reader.woff?4c9ee1256e1512a163e9cea978d87609) format("woff"),
url(../fonts/Reader.ttf?96518758b3e99f4c3eb971150cf70544) format("truetype");
font-weight: normal;
font-style: normal;
}
The end result is that Chrome first downloads the plain preloaded font, then downloads the cache-busted font in the CSS separately, and finally complains that the preloaded resource wasn't used within the first few seconds of the page being loaded:

Is there a way to have the fonts included in the generated mix-manifest.json, so we can use that to generate the proper paths even outside the CSS?
Do something like
mix.version(['fonts/**']);
Although actually it doesn't appear to work as the manifest has ?id={hash} but the css just has ?{hash} and the hashes don't match (length 20 vs 32) I guess something to do with file-loader [hash]
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Although actually it doesn't appear to work as the manifest has
?id={hash}but the css just has?{hash}and the hashes don't match (length 20 vs 32) I guess something to do with file-loader [hash]
Yeah, they're both generating different hashes entirely.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This ain't stale; it's still an issue, TYVM.
Having the exact same issue. Any solutions out there?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This ain't stale; it's still an issue, TYVM.
Although actually it doesn't appear to work as the manifest has
?id={hash}but the css just has?{hash}and the hashes don't match (length 20 vs 32) I guess something to do with file-loader [hash]Yeah, they're both generating different hashes entirely.
I can confirm that the hashes are different. Would be really nice if this could be solved
Not sure if this is related, but on a recent project I noticed that the SCSS -> CSS compilation no longer adds hashes to the webfonts. Not sure if this is a change from having a different Mix version (5.0 vs 3.0) or anything...
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Not. Stale. TYVM.
Same issue here. Why do not use the md5 checksum file like file-loader in the File class?
We noticed issues with font versioning when working with Service Worker / PWA. We're unable to cache the fonts with the Service Worker since it has to match with the exact URI from the CSS.
It looks like a simple md5 hash... would something like this work?
Helper function:
if (! function_exists('hashUrl')) {
function hashUrl($url)
{
return "$url?".md5_file(public_path() . $url)
}
}
Implementation (in a blade):
<link rel="preload" as="font" href="{{ hashUrl('/fonts/merriweather-v21-latin-regular.woff2') }}" type="font/woff2" crossorigin="anonymous">
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I didn't find a way to solve the issue, anyway I've tried to manually link the font file without the cache busting suffix, and Chrome is still giving the same warning, so this might be a Chrome issue.
Can anyone confirm?
A workaround for now is to edit the mix-manifest.json file during the build process as below. @raymondtri's solution worked as well (on the backend side). This is a solution on the frontend side instead. It assumes that all fonts are in the /public/fonts directory. It can be tweaked to accept an array of folders as well.
const mix = require('laravel-mix');
const _ = require('lodash');
const jsonfile = require('jsonfile');
const fs = require('fs');
const md5 = require('md5');
const mixManifest = 'public/mix-manifest.json';
mix.js(...)
.sass(...)
.version()
.then(function () {
// Fonts versioned by processCssUrls in the CSS files use MD5 while Mix uses a different hash versioning system.
// This workaround adds font entries using the MD5 scheme so that all files are versioned properly with the same scheme.
jsonfile.readFile(mixManifest, function (err, obj) {
const newJson = {};
_.forIn(obj, function (value, key) {
newJson[key] = value;
});
fs.readdir('public/fonts', function (err, files) {
files.forEach(function (file, index) {
const path = 'public/fonts/' + file;
newJson['/fonts/' + file] = '/fonts/' + file + "?" + md5(fs.readFileSync(path));
});
jsonfile.writeFile(mixManifest, newJson, {spaces: 2}, function (err) {
if (err) console.error(err);
});
});
});
});
Hi, @paras-malhotra. Thanks for your solution.
In laravel-mix 6 (webpack 5) hashing changed from md5 to md4
If I'm understanding this correctly, there are usable workarounds posted, but no proper solve yet, correct? If so, can a repo contributor ( @JeffreyWay ) re-open this issue please? Stupid bots... 馃 馃檮
yea re-open this wtf.
I thought I had posted my answer but it was in a different issue. It doesn't feel like a workaround to me since it uses webpackConfig to change the default settings.
https://github.com/JeffreyWay/laravel-mix/issues/2036#issuecomment-700138460
@gtempesta I don't think that's quite what users were looking for, they want versioned fonts (processCssUrls: true) but they also want the versioned font adding to the manifest so that it can be preloaded, without having to do the md5/md4 calculation within the site (caching and added complexity).
I don't think this is actually an issue as such with laravel-mix, I wouldn't expect the default to include fonts in the mix-manifest.json (you wouldn't include all the other linked assets, images, etc. so why would fonts be treated differently).
I think we'd just like to know if there is a correct or supported way to append to the mix-manifest.json file, the solution by @paras-malhotra with a switch to md4 for v6 looks suitable however I wonder if there's a better way of hooking into laravel-mix to specify files for inclusion in the manifest, rather than editing the file after build.
@mnightingale You鈥檙e right, my solution only works if you want to drop the hash, not in the case required by the OP. Anyway I think it could still be useful for other people investigating the issue.
If some people come to this issue, and are also fine by just excluding it from versioning so they can preload the fonts manually.
This is what i've added to my webpack.mix.js
mix.webpackConfig({
// object will be merged with Laravel Mix config, so matching rules will be overwritten
module: {
rules: [{
// overwriting file-loader rule for fonts in order to remove the hash (so we can pre-load without downloading it twice)
test: /(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/,
loaders: [{
loader: 'file-loader',
options: {
name: (path) => {
if (!/node_modules|bower_components/.test(path)) {
return 'fonts/[name].[ext]';
}
const pathUpdated = path.replace(/\\/g, '/').replace(/((.*(node_modules|bower_components))|fonts|font|assets)\//g, '');
return `fonts/vendor/${pathUpdated}`;
},
},
}],
}],
},
})
@yordivd this looks a lot like the solution I鈥檝e referenced. I think the conversation would be more helpful if you quoted or linked the original in your post, so that it鈥檚 clear that we are talking about the same thing.
Most helpful comment
It looks like a simple md5 hash... would something like this work?
Helper function:
Implementation (in a blade):