Skip to content


Subversion checkout URL

You can clone with
Download ZIP
100644 226 lines (171 sloc) 8.841 kB
1d927d0 @wycats Initial commit
1 h1. HTML5 Offline
3 HTML5 provides two robust offline capabilities already implemented in popular mobile devices, such as the iPhone and Android, and on modern desktop browsers based on the Webkit and Gecko rendering engines.
5 h2. Usage
7 The easiest way to use Rack::Offline is by using Rails::Offline in a Rails application.
8 In your router:
10 <pre lang="ruby">
11 match "/application.manifest" => Rails::Offline
12 </pre>
14 This will automatically cache all JavaScript, CSS, and HTML in your @public@
15 directory, and will cause the cache to be updated each request in development
16 mode.
18 You can fine-tune the behavior of Rack::Offline by using it directly:
20 <pre lang="ruby">
21 offline = Rack::Offline.configure do
22 cache "images/masthead.png"
24 public_path = Rails.public_path
25 Dir[public_path.join("javascripts/*.js")].each do |file|
26 cache file.relative_path_from(public_path)
27 end
29 network "/"
30 end
31 </pre>
dbc6b06 @jzinedine add sample code snippet on how to use it with Rails asset pipeline
jzinedine authored
33 And when used with Rails asset pipeline:
35 <pre lang="ruby">
36 if Rails.env.production?
37 offline = Rack::Offline.configure :cache_interval => 120 do
38 cache ActionController::Base.helpers.asset_path("application.css")
39 cache ActionController::Base.helpers.asset_path("application.js")
40 # cache other assets
41 network "/"
42 end
43 match "/application.manifest" => offline
44 end
45 </pre>
1d927d0 @wycats Initial commit
47 You can pass an options Hash into #configure in Rack::Offline:
49 |_. name |_. purpose |_. value in Rails::Offline |
50 | :cache | false means that the browser should download the assets on each request if a connection to the server can be made | the same as config.cache_classes |
51 | :logger | a logger to send messages to | Rails.logger |
52 | :root | The location of files listed in the manifest | Rails.public_path |
54 h2. Application Cache
56 The App Cache allows you to specify that the browser should cache certain files, and ensure that the user can access them even if the device is offline.
58 You specify an application's cache with a new @manifest@ attribute on the @html@ element, which must point at a location on the web that serves the manifest. A manifest looks something like this:
60 <pre>
63 javascripts/application.js
64 javascripts/jquery.js
65 images/masthead.png
68 /
69 </pre>
71 This specifies that the browser should cache the three files immediately following <code>CACHE MANIFEST</code>, and require a network connection for all other URLs.
73 Unlike HTTP caches, the browser treats the files listed in the manifest as an atomic unit: either it can serve all of them out of the manifest or it needs to update all of them. It will not flush the cache unless the user specifically asks the browser to clear the cache or for security reasons.
75 Additionally, the HTML file that supplies the @manifest@ attribute is implicitly in the manifest. This means that the browser can load the HTML file and all its cached assets as a unit, even if the device is offline.
77 In short, the App Cache is a much stickier, atomic cache. After storing an App Cache, the browser takes the following (simplified) steps in subsequent requests:
79 # Immediately serve the HTML file and its assets from the App Cache. This happens
80 whether or not the device is online
81 # If the device is offline, treat any resources not specified in the App Cache
82 as 404s. This means that images will appear broken, for instance, unless you
83 make sure to include them in the App Cache.
84 # Asynchronously try to download the file specified in the @manifest@ attribute
85 # If it successfully downloads the file, compare the manifest byte-for-byte with
86 the stored manifest.
87 ** If it is identical, do nothing.
88 ** If it is not identical, download (again, asynchronously), all assets specified
89 in the manifest
90 # Along the way, fire a number of JavaScript events. For instance, if the browser
91 updates the cache, fire an @updateready@ event. You can use this event to
92 display a notice to the user that the version of the HTML they are using is
93 out of date
95 h3. App Cache Considerations
97 The first browser hit after you change the HTML will always serve up stale HTML
98 and JavaScript. You can mitigate this in two obvious ways:
100 # Treat your mobile web app as an API consumer and make sure that your app
101 can support a "client" that's one version older than the current version
102 of the API.
103 # Force the user to reload the HTML to see newer data. You can detect this
104 situation by listening for the @updateready@ event
106 A good recommendation is to have your server support clients at most one
107 version old, but force older clients to reload the page to get newer data.
109 Regular users of your application will receive updates through normal usage,
110 and will never be forced to update. Irregular users may be forced to update
111 if they pick up the application months after they last used in. In all, a
112 pretty good trade-off.
114 While this may seem cumbersome at first, it makes it possible for your users
115 to browse around your application more naturally when they have flaky
116 connections, because the process of updating assets (including HTML)
117 always happens in the background.
119 h3. Updating the App Cache
121 You will need to make sure that you update the cache manifest when any of
122 the underlying assets change.
124 <code>Rack::Offline</code> handles this using two strategies:
126 # In development, it generates a SHA hash based on the timestamp for each
127 request. This means that the browser will always interpret the cache
128 manifest as stale. Note that, as discussed in the previous section,
129 you will need to reload the page twice to get updated assets.
130 # In production, it generates a SHA hash once based on the contents of
131 all the assets in the manifest. This means that the cache manifest will
132 not be considered stale unless the underlying assets change.
134 <code>Rails::Offline</code> caches all JavaScript, CSS, images and HTML
135 files in @public@ and uses @config.cache_classes@ to determine which of
136 the above modes to use. In Rails, you can get more fine-grained control
137 over the process by using <code>Rack::Offline</code> directly.
139 h2. Local Storage
141 Browsers that support the App Cache also support Local Storage, from the
142 <code>HTML5 Web Storage Spec</code>. IE8 and above also support Local
143 Storage.
145 Local Storage is a JavaScript API to an extremely simple key-value store.
147 It works the same as accessing an Object in JavaScript, but persists the
148 value across sessions.
150 <pre>
151 localStorage.title = "Welcome!"
152 localStorage.title //=> "Welcome!"
154 delete localStorage.title
155 localStorage.title //=> undefined
156 </pre>
158 Browsers can offer different amounts of storage using this API. The
159 iPhone, for instance, offers 5MB of storage, after which it asks the
160 user for permission to store an additional 10MB.
162 You can reclaim storage from a key by <code>delete</code>ing it or
163 by overwriting its value. You can also enumerate over all keys in
164 the localStorage using the normal JavaScript <code>for/in</code>
165 API.
167 In combination with the App Cache, you can use Local Storge to store
168 data on the device, making it possible to show stale data to your
169 users even if no connection is available (or in flaky connection
170 scenarios).
172 h2. Basic JavaScript Strategy
174 You can implement a simple offline application using only a few
175 lines of JavaScript. For simplicity, I will use jQuery, but you
176 can easily implement this in pure JavaScript as well. The
177 example is heavily commented, but the total number of lines of
178 actual JavaScript is quite small.
180 <pre lang="javascript">
181 jQuery(function($) {
182 // Declare a function that can take a JS object and
183 // populate our HTML. Because we used the App Cache
184 // the HTML will be present regardless of online status
185 var updateArticles = function(object) {
186 template = $("#articles")
187 localStorage.articles = JSON.stringify(object);
188 $("#article-list").html(template.render(object));
189 }
191 // Create a flag so we don't poll the server twice
192 // at once
193 var updating = false;
195 // Create a function that will ask the server for
196 // updates to the article list
197 var remoteUpdate = function() {
198 // Don't ping the server again if we're in the
199 // process of updating
200 if(updating) return;
202 updating = true;
204 $("#loading").show();
205 $.getJSON("/article_list.json", function(json) {
206 updateArticles(json);
207 $("#loading").hide();
208 updating = false;
209 });
210 }
212 // If we have "articles" in the localStorage object,
213 // update the HTML with the stale articles. Even if
214 // the user never gets online, they will at least
215 // see the stale content
216 if(localStorage.articles) updateArticles(JSON.parse(localStorage.articles));
218 // If the user was offline, and goes online, ask
219 // the server for updates
220 $(window).bind("online", remoteUpdate);
222 // If the user is online, ask for updates now
223 if(window.navigator.onLine) remoteUpdate();
224 })
dbc6b06 @jzinedine add sample code snippet on how to use it with Rails asset pipeline
jzinedine authored
225 </pre>
Something went wrong with that request. Please try again.