Building and deploying apps

Now that we've gone through every step from creating an app to testing it, we're ready to actually deploy our work. This is quite easily done with SproutCore's build tools, you just need to have an understanding of what a built and deployed SproutCore app really is. Remember, SproutCore apps are just static files that run in the client. There is no need for a special app server, any web server will do.

First off, when we work on the app in "debug" mode (that is, locally), we have code and styles split across several files that are served individually to the browser using a development server, sproutcore server. But when we are ready to deploy the app, we want to build it in "production" mode so that it can be properly served remotely to the end user.

There are two important objectives of a production ready web app, the first is that it should load extremely fast and the second is that it should be correctly cacheable. To achieve the first objective, when SproutCore builds our app, the multiple files are concatenated into a single JavaScript file and a single stylesheet file that are then minified to remove whitespace and comments and to greatly compact the code. While a working project may be a few megabytes of code, comments, and whitespace; the minified version will be a fraction of that. Also, because the code is compiled into a single file, it requires only one request from the user's browser that is significantly faster than multiple requests each with added latency. When you add gzip compression to the files, you will find that even gigantic SproutCore apps load faster than the typical blog or news site.

Note

Concatenation of the files is done alphabetically unless there is an sc_require directive found in the file. The sc_require directive informs the build tools that a separate file is required first and should take the form of sc_require('path_from_app_root_to_other_file').

For example, in my_app/resources/main_page.js, we would require the file my_app/views/my_view.js using the following:

sc_require('views/my_view'),

To achieve the second objective, to be cached correctly, SproutCore outputs our app to a unique path. Properly caching and invalidating cached resources is a very tricky process. If we use a fixed path to our resources each time we deploy a new version, it would not appear to the end user until they cleared their browser cache. Obviously, we want all our users to be using the latest version that may be the only version that works with the current API for instance. On the other hand, if we use a process like appending random numbers to the end of the resource URLs when we request them, we will be preventing the files from being cached and the user would be re-downloading the code on each reload. What SproutCore does is that it generates a hash path for each unique build that ensures that the resource is cacheable and that new builds properly invalidate the cache. We'll look at how to deploy a SproutCore app considering the hash path in a moment, but first let's build an app.

Using our Contacts app for example, we simply change to the project and type the following command:

$ sproutcore build contacts

Where sproutcore build (sc-build for short) is the command and contacts is the name of the app we want to build. Have a look at the following screenshot:

Building and deploying apps

This creates a new directory in the project's tmp directory called build, in which we will find the built version of the app inside of a directory called static.

This static directory is the directory that you're going to want to upload to a web server somewhere to make your app public. So it really is just about as easy as running the build command and copying the static directory over to your web server, except for one thing. If you inspect the static directory, you will find that the path to the generated index.html file is something similar to the following:

static/contacts/en/18fd57681cc926bbc3c49d6d58f7ae41f95cebe2/index.html

Note

The actual path will differ on your system, because the hash portion (for example, 18fd57681cc926bbc3c49d6d58f7ae41f95cebe2) is unique and changes for each new build of the application. Having unique hashes is of critical importance, as it ensures that assets are cached properly so that users aren't re-downloading assets unnecessarily or using stale assets.

Now you obviously wouldn't want your users to type a URL like http://{my_app_domain}/static/contacts/en/{some_long_hash} each time to launch your app. So there is a third step to take after copying the files to your web server, that is, to either move the index.html file to the root of the web server directory alongside the static directory or to symbolically link to the index.html file inside of static from within the root of the web server.

Moving the index.html file is actually not recommended because when you redeploy, you will end up overwriting the previous index.html file that could make it impossible to rollback your deployment. Instead, it's better to keep several builds deployed on the server and simply switch the symbolic link to the most recent version. That way if there are any problems, you can quickly rollback your deployment to a previous version by simply changing the link.

For example, on the server you would perform something like the following command after copying the new build over:

$ cd /var/www
$ ln -is static/contacts/en/{NEW_BUILD_NUMBER}/index.html index.html

And there you have it, a live SproutCore application is deployed in only a few steps that you can easily automate in the future if you like.

Additional configuration options

Before we finish up, let's take one final moment to go through a few more Buildfile configuration options that you can use for more complex requirements. The first option you will definitely use is the :title option. This simply sets the value of the <title> element in the <head>. For example, have a look at the following code:

config :my_app,
  :title => "My Wonderful App"

Another option you will likely use at some point is :javascript_libs. This option allows you to specify external JavaScript files to include in your application. For example, to include the Google Maps API in an app, we would add the following code to the Buildfile:

config :my_app,
  :javascript_libs => [
    'https://maps.googleapis.com/maps/api/js?v=3&sensor=false'
  ]

Likewise we can include external stylesheets using the :stylesheet_libs configuration option.

Another option useful for deploying SproutCore apps in a native wrapper is the :build_number option. This will actually always build the app to a fixed path so that it is easier to include as static files inside of another project. For example, have a look at the following code:

config :my_app,
  :build_number => 'latest'

Be warned though, fixed paths should never be used for an app served from a web server, since caching will not work correctly.

Lastly, you can also specify configurations depending on the build mode that allows you to more easily keep the debug, testing, and production code separate. For example, if I were to use analytics in an app, I would not want it to log while developing or testing the app. One approach I might take is to put the analytics code in a framework that I would only require in production mode like the following code:

mode :production do
  config :my_app,
    required => ['analytics']
end

If I wanted to ensure that my code ran unaffected in debug mode, I might create a dummy analytics framework with placeholder functions that do nothing and include it like the following code:

mode :debug do
  config :my_app,
    required => ['dummy_analytics']
end

Note

The default mode of sproutcore server is debug and the default mode of sproutcore build is production, but you can easily change that by passing --mode=mode to the command.

There are a few other options for manipulating the build that you can learn about in the SproutCore Guides at http://guides.sproutcore.com, but these few options are likely the only ones you'll ever need.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.197.10