bminer / node-static-asset

Static asset manager for Node.JS and Express
MIT License
48 stars 13 forks source link

Added support for running multiple instances of your web server. #18

Closed cdeutsch closed 9 years ago

cdeutsch commented 9 years ago

Not sure if you're interested in this but in my scenario I needed to add support for multiple instances of a web server running.

Without this only the first thread will initially make the req.assetFingerprint() calls in your view which populates our collection of fingerprints. The other threads will not have the fingerprints collection populated but will likely handle one or more requests for the assets and when they do your strategy will not be applied.

Feel free to use it or not and thanks for creating this package. :)

bminer commented 9 years ago

@crdeutsch - This isn't a bad idea, but I feel like this could be resolved with a simple middleware like this:

app.use(function(req, res, next) {
    if(req.url.match(autoFingerprintRegex)) {
        req.assetFingerprint();
    }
    next();
});

Will that work? What are your thoughts? Closing this issue for now, but please feel free to post back here.

cdeutsch commented 9 years ago

That would almost work.

The issue with doing it that way is you'd be calling req.assetFingerprint() on every request and I don't see any logic that would stop it from re-building the cache strategy for the file every time.

bminer commented 9 years ago

The middleware would have to be placed after the node-static-asset middleware to work properly. If your server gets a fingerprinted URL (i.e. /js/jquery.min.js?v=3dd-983jk2a), and the URL has been previously registered, static-asset will handle the request with the 304 response (if the client sent If-None-Match or Last-Modified-Since headers)... no computations or hitting the disk is necessary unless the client doesn't have the asset at all. In this case, Express's static middleware will handle the request. Either way, the response will also contain the Etag and strong caching headers to encourage the client not to request the fingerprinted asset again.

The client is only going to request the fingerprinted URLs because those are the URLs that appear in the views. Suppose process A serves a view that calls assetFingerprint. As in a single-threaded environment, the client will request the document using the fingerprinted URL, and the server will respond with either 200 or 304 along with the strong and weak caching headers. In the case where 304 is returned, no other middleware will be called.

Suppose process B handled the request and process B hasn't served the views yet and registered the fingerprints. In this case, we simply register the fingerprint using the regex. The query string on the end of the request is ignored by Express's static middleware, and the asset is read from disk and served. Now, for that request, the server will respond with 200 (or maybe 304 if the client's If-None-Match matches the CRC from the file just read from disk), but the weak/strong caching headers will not be added by static-asset on this request. But now both process A and process B have the fingerprint registered for that asset, so a subsequent request for that same asset will likely result in a 200 or 304 along with the strong/weak caching headers, regardless of which client or web browser that submitted the request.

Does that make sense?

cdeutsch commented 9 years ago

Ok, I see what you're saying.

Makes sense.

For now I'll keep using my forked version, but if it becomes a pain to keep in sync with your repo I may revisit it.

bminer commented 9 years ago

OK... wait... I think I see what you mean now. If a client hits the server with a fingerprinted URL and the client does not send any weak caching headers (i.e. If-None-Match, Last-Modified, etc.), then the middleware will run. In this case, the response is going to be slow because the file has to be loaded from disk using Express's static middleware... or whatever.

However... for these cases, the default strategy uses a cache to prevent the fingerprint from being re-computed over and over.

bminer commented 9 years ago

OK, cool. Whatever you decide sounds good. This repo doesn't change often, so you're probably all good. :) Thanks for the PR and for the discussion... re-visiting this lib from time to time is a good refresher on how it actually works.