CodeSleeve / asset-pipeline

This Laravel 4 package provides a very simple and easy to use asset pipeline. It was heavily inspired by the Rails asset pipeline. We make use of the wonderful Assetic package to help with pre-compliation!
http://www.codesleeve.com
MIT License
489 stars 53 forks source link

Add support for CDNs #150

Open dwightwatson opened 10 years ago

dwightwatson commented 10 years ago

It would be great if the asset pipeline would support CDNs for the hosting of assets. If you're interested in this feature I'll be happy to put together a PR, I might just need a nudge in the right direction in terms of where to inject the functionality.

Basically, helpers for generating JavaScript and stylesheet tags in the production environment would produce URLs that use an alternate base URL provided from the package configuration, rather than the application base URL. The CDN would then hit the file in it's location on the application and cache it for future hits.

This would require that the filenames of the compiled assets change with each change in the contents. It seems as though the new cache-busting functionality in 2.0.0 might achieve this, possibly through the use of MD5/SHA1 fingerprinting of the contents? Let me know what you think.

aheissenberger commented 10 years ago

:+1:

maknz commented 10 years ago

:+1:, this would be very helpful. CloudFront support would be winner.

aheissenberger commented 10 years ago

would nice to be supported by assets:generate #95

kdocki commented 10 years ago

@dwightwatson You wouldn't want to concatenate cdn assets, right?

I mean, when you do like

   <?= javascript_include_tag() ?>

It will spit out like

   <script src="/assets/application.js"></script>

So where would the CDN fit into this?

aheissenberger commented 10 years ago

I have my own lib which uses a config parameter to add the CDN hostname to assets - I use this to use different domains for assets and application to allow caching of assets without cookies:

<img src="{{ assets("path/to/my/image.gif") }}" />

class CDN {

    public static function asset($value='', $issecure = false, $facebook = false, $nocb = false)
    {
        $issecure = $issecure || Request::secure();
        if ($facebook) $issecure = false;
        $url='';
        $host = Config::get('sitesettings.cdn_host');
        if ($host === '') {
            $url = URL::to('/',array(),$issecure);
        } else {
            if ($issecure) {
                $hostssl = Config::get('sitesettings.cdn_hostssl');
                if ($hostssl != '') $host = $hostssl;
            }
            $url = ($issecure?'https://':'http://').$host;
        }
        if ($facebook) $url = Config::get('app.url');
        $cachebreaker = '';
        if (!$nocb && array_key_exists('DEP_VERSION', $_SERVER)) {
            $cachebreaker .= '/res-'.$_SERVER['DEP_VERSION'];
        }
        $value=trim($value);
        if (substr($value,0,4) == 'http') {
            $value=preg_replace('$http(s{0,1})://[^/]*$','',$value);
        }
        if ($value!=='' && substr($value,0,1)!=='/') $value='/'.$value; // add slash
        if (App::environment()=='local' && !$facebook) {
            return $value;
        } 
        return $url.$cachebreaker.$value;

    }

}
kdocki commented 10 years ago

@dwightwatson I misread your stuff...

I guess you are looking for something like this right?

At first I thought you might have been asking for something like

/**
 *= require_cdn //cdnjs.cloudflare.com/ajax/libs/Faker/0.5.11/MinFaker.js
 */

Let me toy around with this and see how rails does it too. Currently I am keeping the last modified date in the headers so browsers know to do 304 caching with assets... but it's becoming more and more apparent that I probably need to store versions in the url.

Looks like we could add an asset_host in the config file so you could set your cdn up with cloud front. Yeah, this would be cool to have... I'm going to look into it some more.

aheissenberger commented 10 years ago

there is no need for version numbers in the url - the normal way is to use a cache buster in the url - my function is using the deployment version and there is a very simple redirect in the .htaccess which will recognize the cache buster part in the url and will redirect to the files.

There is support for this in the Assetic Lib: https://github.com/kriswallsmith/assetic#cache-busting

dwightwatson commented 10 years ago

All good! Yeah, the Rails solution is quite neat. There is a part of me that feels like this functionality should be baked into the framework, but as Laravel doesn't have an asset pipeline it almost doesn't make sense. Plus, with the asset-pipeline package supporting CDNs it means that we can serve our primary assets (stylesheets/scripts) through a CDN while other less important assets are served the old-fashioned way.

I think a configuration variable combined with cache busting (perhaps with the Assetic one @aheissenberger mentioned to reduce the need for additional dependancies) would be the simplest way to achieve this.

Again, happy to help implement such functionality where I can!

kdocki commented 10 years ago

@aheissenberger thanks for the link I had forgotten about this in Assetic. I will check it out and see how easily we can make this work.

kdocki commented 10 years ago

@dwightwatson I will be implementing later, it is at the bottom of my priority though. I have several bugs and bigger issues with caching and assets generate to work on first.

simonweil commented 10 years ago

:+1:

mcblum commented 10 years ago

This would be awesome. We used Max CDN and it would help our load times quite a bit.

dwightwatson commented 10 years ago

If anyone is using this package in production, I highly recommend that you take a look at #188 (and PR #189). Without this patch the pipeline will serve files that should not be available publicly (including your application source code).

Until @kdocki merges this patch you should either fork the patched asset-pipeline repo and use that instead or otherwise find another way to host your assets.

mcblum commented 10 years ago

Sounds good. Can we get this merged? Although if anyone saw my source they'd be like "Who wrote this crap? Not worth stealing" :)