6

Since webassets won't work on GAE to compress a js/css on the fly, it seems the best approach is to do it upon deployment.

After a lot of googling I came up with the script below to achieve this.

At first I thought the best would be to leave the javascript path in base.html as it is and simply compress the css/js.

cssmin compresses the css and overwrites the original. However closure doesn't allow overwriting the original and this concept fails already.

The second problem is, even if I got closure overwriting the original file, caching will be a problem. For this reason each deployment of minified css/js should come with a random number in file name, so that the new versions are actually picked up after a new deployment. With the concept I came up with, this won't be possible though.

Hence the only way to achieve this would be modifying the base.html with sed or something.

Before I reinvent the wheel, is there a better approach to do this? Many thanks

import sys, os
import cssmin

def main():
    if len(sys.argv) == 1:
        return

    appId = sys.argv[1]
    print "appId", appId

    cmd = r'java -jar compiler.jar --js=/src/application/static/f11/f11.js --js_output_file=/src/application/static/f11/f11.min.js'
    os.system(cmd)

    output = cssmin.cssmin(open('/src/application/static/f11/f11.css').read())
    f = open('/src/application/static/f11/f11.css','w')
    f.write(output)    

    # Perform appcfg.py to update GAE server
    cmd = r'"\google_appengine\appcfg.py"'
    os.system(cmd + " update . " + " -A %s"%appId)


if __name__ == "__main__":
    main()
5
  • Is there a specific reason for not compressing css/js with command-line tools and then having a little bash script to take care of the deployment procedure? My deployment script consists of both minifying the css/js I use as well as running the appcfg command. Commented Jun 20, 2013 at 18:00
  • In development you need the uncompressed assets and for production you need them compressed. Do you change the path to your assets from .js to .min.js manually by hand? And how do you deal with versioning? Commented Jun 20, 2013 at 18:14
  • I have shared my deploy/development scripts here. In my html, I always reference the .min.js files and then I have a script for development (run_debug.sh) and one for deployment (deploy.sh). They both use the compile.sh script which is situated in my static folder. It either just copies development css/js to the .min file or it does actual minification. I don't know if this is helpful but that is at least how I make it work :-) Commented Jun 23, 2013 at 19:15
  • I can suggest one alternative solution here: utilizing memcached and a version number/cache buster on a single /style.css?cb=k2h4k23h4. The style.css points to a class which checks for the cached key of same name and if not found, uses a list of css files, compresses them and merges in order, then stores in memcached. Subsequent requests of the same file come from the cache until next version change when uploading new assests. For my use case, where assets don't change often, this single step of changing version number is OK. This URL could also be used as an origin for an external CDN. Commented Sep 3, 2013 at 17:50
  • and just for other people landing on this somewhat old question, there is the built in support for Pagespeed within App Engine: developers.google.com/appengine/docs/python/config/… Commented Sep 3, 2013 at 17:58

1 Answer 1

1

You should do a one-time detection on instance startup that sets some global vars depending on if your app is running on the dev server. You generate URLs you need to your assets based on that, and have a list of versions for each asset.

python example (full context):

JQUERY_VERSION = '1.7.2'
JQUERY_UI_VERSION = '1.8.20'
ANGULAR_VERSION = '1.0.2'

if os.environ['SERVER_SOFTWARE'].startswith('Google'):
    JQUERY_URL = "//ajax.googleapis.com/ajax/libs/jquery/%(version)s/jquery.min.js" %{ 'version': JQUERY_VERSION }
    JQUERY_UI_URL = "//ajax.googleapis.com/ajax/libs/jqueryui/%(version)s/jquery-ui.min.js" %{ 'version': JQUERY_UI_VERSION }
    JQUERY_UI_CSS_URL = "//ajax.googleapis.com/ajax/libs/jqueryui/%(version)s/themes/base/jquery.ui.all.css" %{ 'version': JQUERY_UI_VERSION }
    ANGULAR_URL = "//ajax.googleapis.com/ajax/libs/angularjs/%(version)s/angular.min.js" %{ 'version': ANGULAR_VERSION }
else:
    JQUERY_URL = "/static/js/jquery-%(version)s.min.js" %{ 'version': JQUERY_VERSION }
    JQUERY_UI_URL = "/static/js/jquery-ui-%(version)s.min.js" %{ 'version': JQUERY_UI_VERSION }
    JQUERY_UI_CSS_URL = "/static/css/jquery-ui/jquery-ui-%(version)s.css" %{ 'version': JQUERY_UI_VERSION }
    ANGULAR_URL = "/static/js/angular-%(version)s.min.js" %{ 'version': ANGULAR_VERSION }

go example (full context):

func init() {
    angular_ver := "1.0.5"
    bootstrap_ver := "2.3.1"
    jquery_ver := "1.9.1"

    if appengine.IsDevAppServer() {
        Angular = fmt.Sprintf("/static/js/angular-%v.js", angular_ver)
        BootstrapCss = fmt.Sprintf("/static/css/bootstrap-%v.css", bootstrap_ver)
        BootstrapJs = fmt.Sprintf("/static/js/bootstrap-%v.js", bootstrap_ver)
        Jquery = fmt.Sprintf("/static/js/jquery-%v.js", jquery_ver)
    } else {
        Angular = fmt.Sprintf("//ajax.googleapis.com/ajax/libs/angularjs/%v/angular.min.js", angular_ver)
        BootstrapCss = fmt.Sprintf("//netdna.bootstrapcdn.com/twitter-bootstrap/%v/css/bootstrap-combined.min.css", bootstrap_ver)
        BootstrapJs = fmt.Sprintf("//netdna.bootstrapcdn.com/twitter-bootstrap/%v/js/bootstrap.min.js", bootstrap_ver)
        Jquery = fmt.Sprintf("//ajax.googleapis.com/ajax/libs/jquery/%v/jquery.min.js", jquery_ver)
    }
}

If you have a deploy stript that minifies your local (i.e., non CDN) content, run that here, and use the method above, but with a local url with a .min extension.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.