Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 226 lines (171 sloc) 8.841 kB
1d927d0 @wycats Initial commit
authored
1 h1. HTML5 Offline
2
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.
4
5 h2. Usage
6
7 The easiest way to use Rack::Offline is by using Rails::Offline in a Rails application.
8 In your router:
9
10 <pre lang="ruby">
11 match "/application.manifest" => Rails::Offline
12 </pre>
13
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.
17
18 You can fine-tune the behavior of Rack::Offline by using it directly:
19
20 <pre lang="ruby">
21 offline = Rack::Offline.configure do
22 cache "images/masthead.png"
23
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
28
29 network "/"
30 end
31 </pre>
32
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:
34
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>
46
1d927d0 @wycats Initial commit
authored
47 You can pass an options Hash into #configure in Rack::Offline:
48
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 |
53
54 h2. Application Cache
55
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.
57
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:
59
60 <pre>
61 CACHE MANIFEST
62
63 javascripts/application.js
64 javascripts/jquery.js
65 images/masthead.png
66
67 NETWORK:
68 /
69 </pre>
70
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.
72
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.
74
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.
76
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:
78
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
94
95 h3. App Cache Considerations
96
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:
99
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
105
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.
108
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.
113
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.
118
119 h3. Updating the App Cache
120
121 You will need to make sure that you update the cache manifest when any of
122 the underlying assets change.
123
124 <code>Rack::Offline</code> handles this using two strategies:
125
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.
133
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.
138
139 h2. Local Storage
140
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.
144
145 Local Storage is a JavaScript API to an extremely simple key-value store.
146
147 It works the same as accessing an Object in JavaScript, but persists the
148 value across sessions.
149
150 <pre>
151 localStorage.title = "Welcome!"
152 localStorage.title //=> "Welcome!"
153
154 delete localStorage.title
155 localStorage.title //=> undefined
156 </pre>
157
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.
161
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.
166
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).
171
172 h2. Basic JavaScript Strategy
173
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.
179
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 }
190
191 // Create a flag so we don't poll the server twice
192 // at once
193 var updating = false;
194
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;
201
202 updating = true;
203
204 $("#loading").show();
205 $.getJSON("/article_list.json", function(json) {
206 updateArticles(json);
207 $("#loading").hide();
208 updating = false;
209 });
210 }
211
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));
217
218 // If the user was offline, and goes online, ask
219 // the server for updates
220 $(window).bind("online", remoteUpdate);
221
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.