How can I force refresh after deploy?

Asked

Viewed 365 times

11

I have a web application made in PHP, and I wanted to force that whenever I deploy a new version of the application the client is "obliged" to update everything that has changed, such as images, CSS, JS, etc.

How can I do that?

  • 7

    Asks the user to press CTRL+SHIFT+R!

  • 2

    Use a parameter as a version with a timestamp. Ex: https://www.example.com/images/icons.png?v=1519330900

  • I usually do what Valdeir said, but I’m working on a change that will warn clients connected via socket that the site has changed and force Reload

  • Maybe configure the underlying web server, e.g. using the Apache mod_expires module

  • 1

    You can browse your Assets (CSS, JS, etc.) using tools such as webpack. Tools like this, allow among other things to add a version number at the end of the original file name as Valdeir Psr said. So the browser will ignore the previously versioned Asset cache and load the newer one.

  • Objective question: Are you using any tools to manage Assets? Is it feasible to use? Or want to do this in a project where you’re using the Assets urls directly?

  • The best is to change the name of the Assets. Creating a version in querystring only changes the mess. You can change one main.css?v=125 for main.css?v=127 and suddenly forgot to climb the real main.css version 127 - just shot in the foot, because when you climb the real 127, you’ll have to change the version again, because what’s curly like v=127 is 125. If you change the file name, be sure not to confuse either the development or the deploy.

  • "Ah, but if I change the name I’ll have to go through the sources". But it’s better to go through the sources than pretend to solve them. Anyway, you can use a centralized variety and config of names, so in the sources you use link rel="" src="$config_cssmain" and exchange $config_cssmain in a centralized or manifest file, so you have a little more predictability (and ease of giving an emergency rollback only by changing the config if any Asset has problem deploying)

  • @Bacco but this brings me a problem, that not being serious is boring. In terms of version repository, you will always be creating a new file and never changing the previous one.

  • 1

    @Wallacemaxters I’m not using any tool. It might be feasible to use if it doesn’t involve a lot of time/work.

  • @Jorgeb. Anyway, a deploy system is supposed to be able to remove obsolete things, isn’t it? There are many situations where files become unnecessary when updating a framework or even a stylesheet.

  • @Right Bacco. That’s no problem. The only "problem" is no record of changes in the repository.

Show 7 more comments

2 answers

3

The best way to do this is to use a single parameter in the link that forces you to update your scripts. Example, within the tag head of your page load the scripts this way:

<script src="script.js?v=<?php echo $version; ?>"></script>
<link href="style.css?v=<?php echo $version; ?>" rel="stylesheet">

Being $version some string that can be unique depending on each deploy. I usually put the version of the last deploy via Git.

3


In a remote time, I even created a library to manage my scripts and style sheets added to the site.

The main point that made me want to create the library was to have a parameter that I defined in one place that would affect all scripts, images and style sheets I had on my site.

My goal is not to advertise the library here (because I think nowadays I would try to solve it in other ways), but thinking about the case where you have a site with your scripts, images and style sheets, without using modern tools like gulp, webpack and the like.

Technique 1: Forcing the upgrade of all Assets

I think you could create a function that you would normally receive as a parameter the name of your Asset. And within that function, he would mount the name for his asset based on some flag, which would force an update on all your customers.

Sort of like this:

somewhere you define:

 define('APP_VERSION', '1.0.0');

You create a small function.

 function asset($url) {
      return sprintf('%s?version=%s', $url, APP_VERSION);
 }

Then, instead of declaring your scripts and images like this:

 <img src="/img/futebol.jpg">
 <script src="/js/app.js">

You would declare so:

<img src="<?= asset('/img/futebol.jpg') ?>">
<script src="<?= asset('/js/app.js') ?>"></script>

This would make the above generated url:

 /img/futebol.jpg?version=1.0.0
 /js/app.js?version=1.0.0

Then, if you were to publish a new version in the system, you would just change your constant APP_VERSION.

 define('APP_VERSION', '1.0.1')

This would make your Assets have one ?version=1.0.1 added, thus forcing the client’s browser to pick up new server information.

Advantages of the above method:

  • You change in one place and everything is updated.
  • No need to change folder structure or use libraries to do the job

Disadvantages:

  • If you just want to update a file, it would not be possible, as with the change of version, all Assets would receive an addition ?version=VERSÃO different.
  • You have to call a function instead of simply stating the src or href from your Asset directly

Technique 2: Forcing individual upgrade

The second technique I had thought of aims to upgrade each Asset individually. But, to do this, it is necessary to know the physical path from Asset, through PHP.

The idea is the same as the above function, with a small modification:

  function asset($path)
  {

      // exemplo : 'c:\window\xampp\htdocs\project\assets/img/futebol.jpg'
      $fullpath = __DIR__ . '/assets/' . $path;

      return sprintf('%s?last_modified=%d', $path, filemtime($fullpath));
  }

In the above case, the function filemtime is responsible for reading a file on disk and informing, through a unixtimestamp, the last modification date.

In doing so, you would be generating something like this:

   /img/futebol.png?last_modified=1535132483
   /js/app.js?last_modified=1535632483

Perks

  • Updates each file individually
  • You do not need to change any value manually. If the file is modified then it will always be updated in the browser

Disadvantages:

  • Makes it impossible to use an absolute url in the function, since we use part of the path to build the physical path of the file to get the modification date.
  • Every added Asset will call the function filemtime. Some minimalist people would like to avoid so many calls to that function.

But still, it is possible to get around the problem of option 1, described in the disadvantages of the second method. Just check if the file exists, to apply the modification date check. If it does not exist, use option 1 shown!

Example:

define('APP_VERSION', '1.0.1');

function asset($path)
{
    $fullpath = __DIR__ . '/assets/' . $path;

    // Se existir, coloca a data de modificação

    if (file_exists($fullpath)) {
        return sprintf('%s?last_modified=%d', $path, filemtime($fullpath));
    }

    return sprintf('%s?version=%d', $path, APP_VERSION);
}
  • Comment there, I was wondering if I could use # instead of ?. It would work??

  • 1

    Dude, awesome! It would only change one thing, the APP_VERSION could come from a static file, and in case I would recommend a types of Assets have different versions, but everything else including filemtime I think solves a lot.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.