olimorris's avatar

Laravel Elixir versioning and using a CDN

Has anyone used Laravel Elixir's versioning method and figured out a way how to upload to a CDN like AWS's S3 and not get rev-manifest.json error's?

Quite rightly Elixir by default doesn't know I've thrown my content in a bucket on S3. So how can I tell it and now can I make that process automated? I notice @JeffreyWay hosts his JS and CSS on his server and some images are on S3. That's my current backup plan but I'd love to serve all versions JS and CSS from S3.

0 likes
8 replies
tomschlick's avatar

S3 is not a CDN. Use Cloudfront. With Cloudfront you point it at your server so when it doesn't have a file their servers will fetch it off of your server and then serve it to clients. Works perfectly with elixir.

olimorris's avatar

@tomschlick how do you actually achieve that within a Laravel app? How do you reference your assets in your views so that Cloudfront knows where to pluck them from?

tomschlick's avatar
Level 9

I added this function to my helpers.php file (create one in /resources/helpers.php if you don't already have one, reference it in the composer.json autoload section as a file.).


 /**
 * Get the path to a versioned Elixir file.
 *
 * @param  string $file
 *
 * @return string
 */
function elixirCDN($file)
{
    $cdn = '';

    if(env('CDN_URL', false))
    {
        $cdn = env('CDN_URL');
    }

    return $cdn . elixir($file);
}

4 likes
olimorris's avatar

@tomschlick - Nice. For the package I'm working with I could achieve something similar:

{{ Cdn::Asset(elixir('myfile.css')) }}

Thanks

EventFellows's avatar

@tomschlick

Nice implementation - I get a strange error though. I have used your exact code from above and implemented it in a master file like so:

<link rel="stylesheet" href="{{ elixirCDN('assets/css/global.css') }}">

It works like a charm but the global.css file I am refereing gets loaded 2x times during page load. 1 time from the cdn as it should with the cloudfront url and a second time from the server itself (same file, same name, same content).

It seems that the CDN is redirecting to the origin with a 301 status code. Does the exlixr code put out a 301 during elixir versioning or so?

Any idea as to why that might happen?

tomschlick's avatar

That happened to me originally, I believe it was an issue with the http to https redirection or the www to non-www redirection in the nginx config. Check there first.

EventFellows's avatar

Thank you @tomschlick - your answer pointed me into the right direction. For future reference of others, here is what happens in this setup - I think it helps to understand the WHY of it.

In my case I had the CDN_URL set to HTTP://mysubdomain.cloudfront.net and at the same time used a http:// to https:// redirect in the .htaccess on an apache server (I suppose the same effect happens with www. and non-www. redirects)

Laravel will point to http://mysubdomain.cloudfront.net/path-to-resource to load the resource

if the resource is not available there (which is the case when a resource is first requested or had expired on AWS Cloudfront)

Cloudfront will try to get the resource from origin server with THE SAME path attributes (protocol and path)

so if CDN_URL is defined as http:// AWS will look for the resource form http://mydomain.tld/path-to-resource

there cloudfront will get a 301 redirect and CACHE this as the content of the requested resource

On any subsequent page AWS Cloudfront will deliver the 301 redirect as the resource and the resource itself will then be loaded from the server as if there was not CDN setup - quite confusing...

solve it by only using https everywhere

then clear cache on AWS

OR

use a new elixir version of the file

1 like
tomschlick's avatar

@EventFellows yup that was the problem I originally encountered. I couldn't remember what it was as it happened over a year ago but thats exactly it. You need to make sure that origin url is using https if your app is https.

Please or to participate in this conversation.