Cache Busting with Laravel
Asked Answered
A

4

6

I've been developing a system and every time I update anything on the public folder, each computers must always clear their cache in order for it to take effect.

I've only been coding directly on to the public folder for the js and css files. When I push it to my git repository and pull it to our shared hosting through ssh after that I copy it to the public_html folder through ssh as well, all client computers still need to clear their caches manually in order for new public files to take effect. I've been studying a bit of laravel mix however I am still unsure how to actually use it in a live hosting.

I am unsure if cache busting is the right term at this time but I wanted my client computers to use the latest assets every time I update our system.

Absorber answered 29/5, 2019 at 1:42 Comment(0)
E
4

Laravel has a built-in system for compiling assets like CSS and JavaScript, which includes a versioning system that ensures when you push a new version, users receive those updated assets.

mix.js('resources/js/app.js', 'public/js')
   .version();
Errolerroll answered 29/5, 2019 at 1:53 Comment(5)
I'm currently using a shared hosting. I'm still unsure how I will try it but the way I understand it now it seems like npm run production will compile all files to the project public folder instead of the root directory(public_html)Absorber
@LEADIT You can do the npm run production locally, then place the public files up on your server's public_html folder. I don't generally recommend running Laravel on shared hosting at all, though.Errolerroll
Does it also require me to install npm to my live hosting?Absorber
VPS hosting is very cheap these days. Starting at $3.50 USD from AWS lightsail.Gomphosis
@Errolerroll I've tried it and it works. However, when I use a function from one external js to another one, it returns an error the 'function is not defined'Absorber
N
9

Another quick and dirty way of cache busting is using the last modified timestamp of a file as a version string. This way if you update the file, the timestamp changes too. PHP has the filemtime method for this.

I use this all the time in Wordpress, but in a Laravel blade template it looks something like this:

<script src="{{ asset('js/scripts.js') }}?ver={{ filemtime(public_path('js/scripts.js')) }}"></script>

I do recommend going the built-in Laravel way because it comes with a lot of other advantages. But the principle of this trick can be useful in many other situations.

Neoteric answered 6/11, 2020 at 10:34 Comment(2)
What is the advantage in using the built-in Laravel way?Aristotle
Also, to avoid leaking the time for the last modification, the value could be hashed with e.g. md5 or something more secure such as bcrypt.Aristotle
E
4

Laravel has a built-in system for compiling assets like CSS and JavaScript, which includes a versioning system that ensures when you push a new version, users receive those updated assets.

mix.js('resources/js/app.js', 'public/js')
   .version();
Errolerroll answered 29/5, 2019 at 1:53 Comment(5)
I'm currently using a shared hosting. I'm still unsure how I will try it but the way I understand it now it seems like npm run production will compile all files to the project public folder instead of the root directory(public_html)Absorber
@LEADIT You can do the npm run production locally, then place the public files up on your server's public_html folder. I don't generally recommend running Laravel on shared hosting at all, though.Errolerroll
Does it also require me to install npm to my live hosting?Absorber
VPS hosting is very cheap these days. Starting at $3.50 USD from AWS lightsail.Gomphosis
@Errolerroll I've tried it and it works. However, when I use a function from one external js to another one, it returns an error the 'function is not defined'Absorber
T
0

You can include a version on your css and js files.

<link rel="stylesheet" href="{{asset('css/style.css?v=3.0')}}"> //specific versioning
<link rel="stylesheet" href="{{asset('css/style.css?v='.rand(1,99))}}"> //random .. every it treats as a new file
Twitt answered 29/5, 2019 at 2:33 Comment(4)
The rand approach is not a good idea unless you use a much higher cap than 99. A frequent visitor would see cached stuff regularly (and possibly several different cached versions in one visit), and infrequent visitors would incur much more bandwidth usage and poor performance as the CSS file would be reloaded on every pageview.Errolerroll
@Errolerroll May I ask what would be your suggestion for this? I've also ready about this versioning and some does not recommend it for different reasons.Absorber
@LEADIT See my answer. Versioning is the main way people handle this - you'll see pretty much every major site (including right here on StackOverflow) using some sort of versioning approach. I don't know who "some" are, but they're giving you bad/outdated info.Errolerroll
@Errolerroll I apologize for generalizing some but I also saw this kind of answer on stack overflow and your comment to his answer is quite similar to that (their way of using versioning). That's why I'm finding a better way which I've read in your comment.Absorber
D
0

As per the accepted answer, you can use laravel mix to add version number to the assets but OP said that his assets code are currently in the public folder. To use the laravel mix way, he needs to transfer all the assets(js, css) from public to resource, add .gitignore to ignore assets folder in public, run git rm -r --cached /public to completely remove them from the cache then run npm run prod to generate the assets from resource to public. This way, OP will now continue working using the laravel way.

However if OP does want to continue working in the public folder (too many assets right now), he/she can use the composer package tooleks/laravel-asset-version.

You can use this Github repo for reference.

Note:

You can also add the version number in config/assets.php or you can add the version number in the .env file.

config/assets.php

<?php

return [
    ...
    'version' => env('VERSION', '0.0.1'),
];

run npm i dotenv to install dotenv if not yet installed

Make the necessary changes and create version.js in the root folder. This file will be responsible to generate the version number in the .env dynamically using npm command.

version.js

const fs = require('fs');
const dotenv = require('dotenv');

// Load the .env file
dotenv.config();

// Specify the key and value you want to update or add
const today = new Date();
const year = today.getFullYear().toString().padStart(4, '0');
const month = (today.getMonth() + 1).toString().padStart(2, '0');
const day = today.getDate().toString().padStart(2, '0');

const key = 'VERSION';
const value = `${year}.${month}.${day}`;

// Update the .env file
const envFileContent = fs.readFileSync('.env', 'utf8');
const lines = envFileContent.split('\n');
let keyFound = false;

const updatedLines = lines.map((line) => {
  const [lineKey, lineValue] = line.split('=');
  if (lineKey === key) {
    keyFound = true;
    return `${lineKey}=${value}`;
  }
  return line;
});

if (!keyFound) {
  // Add a line break before adding the variable
  updatedLines.push('');

  // Add the key-value pair
  updatedLines.push(`${key}=${value}`);
}

const updatedEnvConfig = updatedLines.join('\n');

fs.writeFileSync('.env', updatedEnvConfig);

console.log(`Successfully updated ${key} in the .env file.`);

Then add in your package.json

"scripts": {
    ...
    "version" : "node version.js"
},

Now you can run npm run version to add version number to the .env file with format yyyy.mm.dd. Change the format if needed.

If everything is set corretly, you should see something like https://website.domain/path/to/asset.css?v=yyyy.mm.dd

Dundee answered 12/7, 2023 at 4:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.