Showing posts with label HTML5. Show all posts
Showing posts with label HTML5. Show all posts

Sunday, August 13, 2017

versioning js and css with gulp-rev and gulp-revReplace

I've discussed before how I run https://apps.frickjack.com on S3, but one issue I did not address was how to version updates, so that each visitor loads a consistent set of assets. Here's the problem.

  • on Monday I publish v1 assets to the S3 bucket behind apps.frickjack.com
  • later on Monday Fred visits apps.frickjack.com, and his browser caches several v1 javascript and CSS files - a.js, b.js, x.css, y.css, ...
  • on Tuesday I publish v2 assets to S3 - just changing a few files
  • on Wednesday Fred visits apps.frickjack.com, but for whatever reason his browser cache updates b.js to v2, but loads v1 of the other assets from cache

On Wednesday Fred loads an inconsistent set of assets that might not work together. There are several approaches people take to avoid this problem. Surma gave a good overview of HTTP cache headers and thinking in this talk on YouTube, and Jake Archibald goes into more detail in this bLog (we set cache-headers directly on our apps.frickjack.com S3 objects).

Long story short - I finally wired up my gulpfile with gulp-rev and gulp-rev-replace to add a hash to the javascript and css file names. Each visitor to apps.frickjack.com is now guaranteed to load a consistent set of assets, because an asset's name changes when its content changes. I was really happy to find gulp-rev - it just takes care of things for me. The only gotcha is that gulp-rev-rewrite does not like to work with relative asset paths (ex - <script src="511.js"), so I had to update a few files to use absolute paths (src="/511/511.js") - otherwise things worked great.

Friday, May 17, 2013

Updating Web-login for Javascript Webapp

I've been coding away for several days on some old web-login logic I had implemented in littleware to work in web applications with JSF-managed UX. I'm updating the code for use in apps where a javascript program manages the user experience. I've been thinking lately about the similarities and differences between the two application architectures.

The first difference between the two designs is in deployment. The old JSF architecture relied on JSF and JSP templates managed by the server, so I would usually bundle up the entire application in a .war file, and deploy it to some glassfish or tomcat or whatever container. The user interacted with the application by clicking links and submitting forms that moved the browser between web pages rendered by the server.

I'm trying to structure the newer code so that most client-side assets (javascript, CSS, hadlebar templates, ...) are served as static files from S3. The user's in-browser interactions with the application trigger events that are handled by javascript event-handlers. The javascript code running in the user's browser can access remote services via cross-origin AJAX requests. There are various CORS servlet filters open sourced online that take care of setting the HTTP response headers that browsers look for; today I grabbed this one posted by some Ebay coders to github - hopefully it works.

In the login code, both the old and new setups rely on a request filter (javax.servlet.Filter) to intercept unauthenticated client requests. The old code would intercept an unauthenticated page-load request, and forward the request on the server to a login page via RequestDispatcher.forward.

The new code intercepts unauthenticated AJAX requests to JSON services, and responds to the javascript client with an HTTP 401 (unauthorized) response, and relies upon the javascript code on the client to initiate a login process that eventually authenticates with the server by submitting credentials to a login AJAX service.

Finally - in the older applications I had the bad habit of tracking session state on the server via beans stashed in container-managed in-memory session. Tracking user data in-memory on a particular server required that a client continued to interact with the same server it began a session with. In-memory session state also made it difficult to partition a server's functionality between different endpoints. In other words - if I had a server that implemented some functionality "ABC", and I later decided that I would like to split the functionality on that server (or server cluster) between separate "A", "B", and "C" servers (or clusters), then it would be hard to do that if the code relied on shared in-memory session state.

Anyway, the new code avoids session state on the server - instead it relies on the client-side javascript code to track session state in most cases, and transient cookies in a few others.

In the end - I get to throw away a bunch of crazy server-side JSF beans and templates, and replace them with javascript modules and REST services.

Saturday, April 20, 2013

511 labor contraction counter app

I coded up a little 511 app to help track the duration and period of labor contractions. Childbirth extends over several hours for most women, so the rule of thumb for a woman trying to decide when to head into the hospital (or whatever) is to wait until after contractions occur every 5 minutes averaging one minute in length for one hour - the "5-1-1" rule.

Anyway - the "5-1-1" rule was news to me when I learned about it watching this goofy video where the expecting parents were tracking contractions on a pad of paper. I thought, "why don't they track the contractions on their smart phone?". Such a genius!

I poked around looking for a 511 app, and didn't find one, so I decided to take it on as a project. After I started a friend mentioned that there is an iPhone app - doh! By then I was already committed to the project. There's one for Android now too - ugh.

Anyway - in addition to demonstrating my complete incompetence in web design, the app allowed me to play around with some "HTML5" tech that is pretty cool. I used YUI - which I like a lot. The app is wired with a manifest, so our poor pregnant woman can pull up the app even when she's offline, and an apple-touch icon, so she can "pin" the app to her start screen as a standalone app.

Unfortunately, I made some newb mistakes too. I designed the app to just maintain its state in memory - assuming that when a user starts having contractions, then she'll pull up the app, use it until she goes into full labor or not, and that's that. I expected a webapp launched from the start-screen would maintain its state if the user switched between apps - the same way a browser tab maintains its state if the user switches tabs. Bad assumption! It turns out that a pinned webapp loses its in-memory state whenever the user switches between apps - at least the iPhone behaves that way. I went back and added code to save and restore the apps state to local cache, but it would have been better if I had designed the code to work that way from the start.

The app could of course benefit from several improvements. First, I currently have the thing wired to save state to local cache after every UX event, because I couldn't figure out how to detect a "user is leaving this page" event, and only save then. I recently found this thread on stackoverflow that describes the "leaving page" event, so I'd like to give that a try.

I'd also like to wire-up the app to somehow auto-suggest that the user pin the app to her home screen, and make that easy to do (it's kind of a hassle in Android Chrome for example). I'm pretty sure some apps do that kind of thing, but it may be more trouble than I'm willing to go through - we'll see.

Anyway - I'm pretty happy with how the project came out - even though the woman I built it for didn't use it, because her water broke (doh!), but the baby came out healthy, so all's well that ends well. The source code is online under my dev-clone of my littleware mercurial repo on google code - mixed in with a bunch of other code I've been playing with. At some point I started making breaking changes to the littleware code, so I forked off to that clone, but still haven't merged back to the main repo - which is stupid, because nobody uses that code but me. Anyway - I need to clean up the repo, and probably setup a clone on github - which is where all the cool kids track code these days, but I'll save that project for another day ...