Support the ongoing development of Laravel.io →
Configuration Views
Last updated 2 years ago.
0

I append a modified time to version my files:

function asset_timed($path, $secure=null){
    $file = public_path($path);
    if(file_exists($file)){
        return asset($path, $secure) . '?' . filemtime($file);
    }else{
        throw new \Exception('The file "'.$path.'" cannot be found in the public folder');
    }
}

<link rel="stylesheet" type="text/css" href="{{ asset_timed('assets/css/style.css') }}" />

Or is that now what you mean? I minify/concat the files with Gulp: https://laracasts.com/lessons/gulp-this

Last updated 2 years ago.
0

Instead of appending a query string like "file.css?233367899", I rename to "file.233367899.css. This will be rewritten to file.css, if you use the html5boilerplate htaccess and enable the rewrite thats in there.

Last updated 2 years ago.
0

Yes you can also do that. I'm not really sure if that still is needed, but according to this it is still recommened. You could do something like this (.htaccess example from h5bp)

//.htaccess
# ------------------------------------------------------------------------------
# | Filename-based cache busting                                               |
# ------------------------------------------------------------------------------

# If you're not using a build process to manage your filename version revving,
# you might want to consider enabling the following directives to route all
# requests such as `/css/style.12345.css` to `/css/style.css`.

# To understand why this is important and a better idea than `*.css?v231`, read:
# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring

<IfModule mod_rewrite.c>
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L]
</IfModule>

//helpers.php
function version($path){
    $file = public_path($path);
    if(file_exists($file)){
        $parts = explode( '.', $path);
        $extension = array_pop($parts);
        array_push($parts, filemtime($file), $extension);
        $path = implode('.', $parts);
        return $path;
    }else{
        throw new \Exception('The file "'.$path.'" cannot be found in the public folder');
    }
}

//Views:
<link rel="stylesheet" type="text/css" href="{{ asset(version('assets/css/style.css')) }}" />
Last updated 2 years ago.
0

I use Grunt with the hashmap plugin (grunt-hashmap). In my app/asssets folder I then have a json file that holds all my collections. Grunt then pulls that in, and automatically concatenates, minifies, etc. a collection when a file within it changes. The hashmap plugin does 2 things. First it injects the current cache busting string into the concatenated filename and then it saves the new file name in a json file.

I then overloaded the script and style methods in the HtmlBuilder class with this:

    public function style($url, $attributes = array())
    {
        return parent::style($this->getHashedUrl($url), $attributes);
    }

    public function script($url, $attributes = array())
    {
        return parent::script($this->getHashedUrl($url), $attributes);
    }

    protected function getHashedUrl($url)
    {
        try 
        {
            $hashMap = $this->getJsonFile('assets/hashmap.json');
        }
        catch (FileNotFoundException $exception)
        {
            return $url;
        }

        $info = pathinfo($url);
        $name = $info['basename'];
        $hash = isset($hashMap[$name]) ? $hashMap[$name] : false;

        if (!$hash) return $url;

        return $info['dirname'] . DIRECTORY_SEPARATOR . $info['filename'] .'.'. $hash .'.'. $info['extension'];
    }

    protected function getJsonFile($path)
    {
        $file = File::get(app_path($path));

        return json_decode($file, true);
    }

Within a view I can then just do this and I'll get the cachable scripts/styles if they exist:

HTML::script('assets/js/script.min.js');
HTML::style('assets/css/style.min.js');
Last updated 2 years ago.
0

Cool, I was trying to do the same thing with Gulp a while back, but couldn't yet find any plugins that created a good hashmap and renamed files. https://github.com/UltCombo/gulp-buster and https://github.com/litek/gulp-hashmap seem to create a json file with hashes, but not rename the files. https://github.com/sindresorhus/gulp-rev does rename the files, but doesn't save the mappings correctly (at least, not when I tried). So then you would still have to use a different htaccess rewrite technique. I'm not really sure what the best way is, but I just thought to keep it simple. The downside with modified time is that it changes on a new deploy, regardless of changed contents. But it is pretty safe and always works very simple.

Last updated 2 years ago.
0

Had been looking at moving to Gulp, but didn't have much luck with the hashmap stuff neither, so for now I'll be staying with Grunt. Works well enough, so in the end it doesn't really matter.

Last updated 2 years ago.
0

Anyone aware of new stuff for Gulp that might be available yet? I'm doing something very similar to barryvdh; would love to have this done more properly though!

Last updated 2 years ago.
0

I use Gulp Rev "https://github.com/sindresorhus/gulp-rev"

It basically looks at each file, and computes a hash for it (so if it changes the hash is updated).

It then outputs a json file, to map your file name to the hashed file name (like "style.css" : "style-97cwec.css") which you parse for what you need. I had to write a little helper for my views to get it to work cleanly.

So this is my gulp "css" function for example:

gulp.task('production_css', function()
{
    return gulp.src('app/assets/back/**/*.css')
        .pipe(minifycss())              // Minify CSS
        .pipe(rev())                        // Put version number on file
        .pipe(gulp.dest('public/assets/back'))     // Move CSS into the public folder
        .pipe(rev.manifest())                               // Create a manifest of CSS files
        .pipe(rename('css.manifest.json'))         // Save the name of the manifest file as "css.manifest.json"
        .pipe(gulp.dest('app/assets/back'));       // And save my manifest file inside my assets folder (which I .gitnore the .json in that folder.
});

Then I have a Form::macro() as a helper function

Form::macro('generateCSS', function($link)
{
    $list = json_decode(File::get(base_path().'/app/assets/back/css.manifest.json'));
    return ('<link rel="stylesheet" type="text/css" href="/assets/back/' . $list->$link . '">');
});

Finally I just put this in my view file to show the CSS. It will automatically generate the "new" CSS filename, with the hash included on the fly.

{{ Form::generateCSS(`bootstrap.min.css') }}
{{ Form::generateCSS(`jquery-ui.css') }}
{{ Form::generateCSS(`style.css') }}

Works perfectly...

Last updated 2 years ago.
0

Why use the Form::macro()?'

Last updated 2 years ago.
0

Yeah - it wasnt a good place to put it - I just needed a quick place to 'build' the solution while I worked out the solution.

Now I know it works perfectly I'll refactor it into a class later.

Last updated 2 years ago.
0

You can just use HTML::macro instead of Form::macro.. And you mean https://github.com/sindresorhus/gulp-rev, not gulp-buster right? The problem I had with that, was that it had to use different .json files, one for each task, otherwise it would just overwrite the old manifest with only new tasks..

Last updated 2 years ago.
0

barryvdh said:

You can just use HTML::macro instead of Form::macro..

Yes - much better idea - I just hacked something together, but I'll refactor the code into there.

And you mean https://github.com/sindresorhus/gulp-rev, not gulp-buster right?

Yes - sorry - I'll edit my post

The problem I had with that, was that it had to use different .json files, one for each task, otherwise it would just overwrite the old manifest with only new tasks..

Yes - which is why you combine it with gulp-rename (as in my code above) so you can rename the manifest to whatever you want - that was the trick that took me a while to work out. In my case I run "back" and "front" gulps, so I do a css.front.manifest and css.back.manifest

Last updated 2 years ago.
0

p.s. dont forgot to then set your JS and CSS files to "never" expire - since you will automatically bust the cache on any file if/when the file name changes. If the filename never changes, it is the same file version!

You can also do this with images if you want as well...

Last updated 2 years ago.
0

Hello guys,

I want to share, how I solve css/js etc versioning problem:

My .htccess looks like

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    # Handle cached assets
	RewriteRule ^(.*)-rev\d+\.(css|js)$ $1.$2 [L]

    # Redirect Trailing Slashes...
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

<ifModule mod_headers.c>
    ExpiresActive On

    # Expires after 1 month
    <filesMatch "\.(css|js|jpg|png|gif|woff)$">
        Header set Cache-Control "max-age=2592000, public"
        Header set Pragma "Cache"
        Header set Connection "Keep-Alive"
        Header set Last-Modified "Mon, 01 Mar 2014 23:00:00 GMT"
        ExpiresDefault "access plus 1 year"
    </filesMatch>
</ifModule>

I also overridden HtmlBuilder, however you can make macro for that, however I did not want to refactor my code.

class Builder extends HtmlBuilder{

    public function style($url, $attributes = array(), $secure = null)
    {
        return parent::style($this->getFileName($url), $attributes, $secure);
    }

    public function script($url, $attributes = array('async'), $secure = null)
    {
        return parent::script($this->getFileName($url), $attributes, $secure);
    }

    protected function getMTime($url)
    {
        $path = public_path($url);
        if (File::exists($path)) {
            return filemtime($path);
        }

        return false;
    }

    protected function getFileName($url)
    {
        $mtime = $this->getMTime($url);
        if ($mtime) {
            $info = pathinfo($url);
            return $info['dirname'] . '/' . $info['filename'] . '-rev' . $mtime . '.' . $info['extension'];
        }

        return $url;
    }
}

What it basically does, it adds file modification time, so filename look like filename-rev234235243523.[js/css], and .htaccess knows how to handle and load that file :)

Last updated 2 years ago.
0

I am not a very frontend-y dev so I might be wrong. Isn't an asset pipeline all that you need to do all of this :

  • Minification
  • Concat
  • Linking to css & js

?

Last updated 2 years ago.
0

And less/sass compiling, auto-prefixing, jslinting, optimizing images, cachebusting etc. The problem here is that you want to set your files to expire never, to make your website faster (assets get requested only once), but you have to invalidate the cache on updates, so you can either use filemtime or a hash of the contents. And you can choose to just rewrite the urls with htaccess or really rename the files.

Last updated 2 years ago.
0

Sign in to participate in this thread!

Eventy

Your banner here too?

tven7 tven7 Joined 11 Mar 2014

Moderators

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2024 Laravel.io - All rights reserved.