diff --git a/packages/reload/reload.js b/packages/reload/reload.js index 2a400bdece..86a841883a 100644 --- a/packages/reload/reload.js +++ b/packages/reload/reload.js @@ -218,8 +218,10 @@ Reload._reload = function (options) { var tryReload = function () { _.defer(function () { if (Reload._migrate(tryReload, options)) { - // Tell the browser to shut down this VM and make a new one - window.location.reload(); + // Make the browser reload the page + // Using location.replace() instead of location.reload() avoids + // validating assets with the server if we still have a fresh cached copy. + window.location.replace(window.location.href); } }); }; diff --git a/packages/webapp/.npm/package/npm-shrinkwrap.json b/packages/webapp/.npm/package/npm-shrinkwrap.json index dc8dc414d6..ce2b3a2da8 100644 --- a/packages/webapp/.npm/package/npm-shrinkwrap.json +++ b/packages/webapp/.npm/package/npm-shrinkwrap.json @@ -1,65 +1,390 @@ { "dependencies": { "connect": { - "version": "2.9.0", + "version": "2.30.2", "dependencies": { - "qs": { - "version": "0.6.5" + "basic-auth-connect": { + "version": "1.0.0" }, - "cookie-signature": { - "version": "1.0.1" - }, - "buffer-crc32": { - "version": "0.2.1" - }, - "cookie": { - "version": "0.1.0" - }, - "bytes": { - "version": "0.2.0" - }, - "fresh": { - "version": "0.2.0" - }, - "pause": { - "version": "0.0.1" - }, - "uid2": { - "version": "0.0.2" - }, - "debug": { - "version": "0.7.2" - }, - "methods": { - "version": "0.0.1" - }, - "multiparty": { - "version": "2.1.8", + "body-parser": { + "version": "1.13.3", "dependencies": { - "readable-stream": { - "version": "1.0.17" + "iconv-lite": { + "version": "0.4.11" }, - "stream-counter": { - "version": "0.1.0" + "on-finished": { + "version": "2.3.0", + "dependencies": { + "ee-first": { + "version": "1.1.1" + } + } + }, + "raw-body": { + "version": "2.1.5", + "dependencies": { + "bytes": { + "version": "2.2.0" + }, + "iconv-lite": { + "version": "0.4.13" + }, + "unpipe": { + "version": "1.0.0" + } + } } } + }, + "bytes": { + "version": "2.1.0" + }, + "cookie": { + "version": "0.1.3" + }, + "cookie-parser": { + "version": "1.3.5" + }, + "cookie-signature": { + "version": "1.0.6" + }, + "compression": { + "version": "1.5.2", + "dependencies": { + "accepts": { + "version": "1.2.13", + "dependencies": { + "mime-types": { + "version": "2.1.9", + "dependencies": { + "mime-db": { + "version": "1.21.0" + } + } + }, + "negotiator": { + "version": "0.5.3" + } + } + }, + "compressible": { + "version": "2.0.6", + "dependencies": { + "mime-db": { + "version": "1.21.0" + } + } + }, + "vary": { + "version": "1.0.1" + } + } + }, + "connect-timeout": { + "version": "1.6.2", + "dependencies": { + "ms": { + "version": "0.7.1" + } + } + }, + "content-type": { + "version": "1.0.1" + }, + "csurf": { + "version": "1.8.3", + "dependencies": { + "csrf": { + "version": "3.0.0", + "dependencies": { + "base64-url": { + "version": "1.2.1" + }, + "rndm": { + "version": "1.1.1" + }, + "scmp": { + "version": "1.0.0" + }, + "uid-safe": { + "version": "2.0.0" + } + } + } + } + }, + "debug": { + "version": "2.2.0", + "dependencies": { + "ms": { + "version": "0.7.1" + } + } + }, + "depd": { + "version": "1.0.1" + }, + "errorhandler": { + "version": "1.4.2", + "dependencies": { + "accepts": { + "version": "1.2.13", + "dependencies": { + "mime-types": { + "version": "2.1.9", + "dependencies": { + "mime-db": { + "version": "1.21.0" + } + } + }, + "negotiator": { + "version": "0.5.3" + } + } + }, + "escape-html": { + "version": "1.0.2" + } + } + }, + "express-session": { + "version": "1.11.3", + "dependencies": { + "crc": { + "version": "3.3.0" + }, + "uid-safe": { + "version": "2.0.0", + "dependencies": { + "base64-url": { + "version": "1.2.1" + } + } + } + } + }, + "finalhandler": { + "version": "0.4.0", + "dependencies": { + "escape-html": { + "version": "1.0.2" + }, + "on-finished": { + "version": "2.3.0", + "dependencies": { + "ee-first": { + "version": "1.1.1" + } + } + }, + "unpipe": { + "version": "1.0.0" + } + } + }, + "fresh": { + "version": "0.3.0" + }, + "http-errors": { + "version": "1.3.1", + "dependencies": { + "inherits": { + "version": "2.0.1" + }, + "statuses": { + "version": "1.2.1" + } + } + }, + "method-override": { + "version": "2.3.5", + "dependencies": { + "methods": { + "version": "1.1.1" + }, + "vary": { + "version": "1.0.1" + } + } + }, + "morgan": { + "version": "1.6.1", + "dependencies": { + "basic-auth": { + "version": "1.0.3" + }, + "on-finished": { + "version": "2.3.0", + "dependencies": { + "ee-first": { + "version": "1.1.1" + } + } + } + } + }, + "multiparty": { + "version": "3.3.2", + "dependencies": { + "readable-stream": { + "version": "1.1.13", + "dependencies": { + "core-util-is": { + "version": "1.0.2" + }, + "isarray": { + "version": "0.0.1" + }, + "string_decoder": { + "version": "0.10.31" + }, + "inherits": { + "version": "2.0.1" + } + } + }, + "stream-counter": { + "version": "0.2.0" + } + } + }, + "on-headers": { + "version": "1.0.1" + }, + "parseurl": { + "version": "1.3.0" + }, + "pause": { + "version": "0.1.0" + }, + "qs": { + "version": "4.0.0" + }, + "response-time": { + "version": "2.3.1" + }, + "serve-favicon": { + "version": "2.3.0", + "dependencies": { + "etag": { + "version": "1.7.0" + }, + "ms": { + "version": "0.7.1" + } + } + }, + "serve-index": { + "version": "1.7.2", + "dependencies": { + "accepts": { + "version": "1.2.13", + "dependencies": { + "negotiator": { + "version": "0.5.3" + } + } + }, + "batch": { + "version": "0.5.2" + }, + "escape-html": { + "version": "1.0.2" + }, + "mime-types": { + "version": "2.1.9", + "dependencies": { + "mime-db": { + "version": "1.21.0" + } + } + } + } + }, + "serve-static": { + "version": "1.10.0", + "dependencies": { + "escape-html": { + "version": "1.0.2" + } + } + }, + "type-is": { + "version": "1.6.10", + "dependencies": { + "media-typer": { + "version": "0.3.0" + }, + "mime-types": { + "version": "2.1.9", + "dependencies": { + "mime-db": { + "version": "1.21.0" + } + } + } + } + }, + "utils-merge": { + "version": "1.0.0" + }, + "vhost": { + "version": "3.0.2" } } }, + "parseurl": { + "version": "1.3.0" + }, "send": { - "version": "0.1.4", + "version": "0.13.0", "dependencies": { "debug": { - "version": "0.7.2" + "version": "2.2.0" }, - "mime": { - "version": "1.2.11" + "depd": { + "version": "1.0.1" + }, + "destroy": { + "version": "1.0.3" + }, + "escape-html": { + "version": "1.0.2" + }, + "etag": { + "version": "1.7.0" }, "fresh": { - "version": "0.2.0" + "version": "0.3.0" + }, + "http-errors": { + "version": "1.3.1", + "dependencies": { + "inherits": { + "version": "2.0.1" + } + } + }, + "mime": { + "version": "1.3.4" + }, + "ms": { + "version": "0.7.1" + }, + "on-finished": { + "version": "2.3.0", + "dependencies": { + "ee-first": { + "version": "1.1.1" + } + } }, "range-parser": { - "version": "0.0.4" + "version": "1.0.3" + }, + "statuses": { + "version": "1.2.1" } } }, diff --git a/packages/webapp/package.js b/packages/webapp/package.js index 68ff08e369..06fc1e0ecb 100644 --- a/packages/webapp/package.js +++ b/packages/webapp/package.js @@ -3,8 +3,9 @@ Package.describe({ version: '1.2.3' }); -Npm.depends({connect: "2.9.0", - send: "0.1.4", +Npm.depends({connect: "2.30.2", + parseurl: "1.3.0", + send: "0.13.0", useragent: "2.0.7"}); Npm.strip({ diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index d3ef354378..961e23fafb 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -8,6 +8,7 @@ var url = Npm.require("url"); var crypto = Npm.require("crypto"); var connect = Npm.require('connect'); +var parseurl = Npm.require('parseurl'); var useragent = Npm.require('useragent'); var send = Npm.require('send'); @@ -326,7 +327,7 @@ WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) { next(); return; } - var pathname = connect.utils.parseUrl(req).pathname; + var pathname = parseurl(req).pathname; try { pathname = decodeURIComponent(pathname); } catch (e) { @@ -367,17 +368,9 @@ WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) { // Cacheable files are files that should never change. Typically // named by their hash (eg meteor bundled js and css files). // We cache them ~forever (1yr). - // - // We cache non-cacheable files anyway. This isn't really correct, as users - // can change the files and changes won't propagate immediately. However, if - // we don't cache them, browsers will 'flicker' when rerendering - // images. Eventually we will probably want to rewrite URLs of static assets - // to include a query parameter to bust caches. That way we can both get - // good caching behavior and allow users to change assets without delay. - // https://github.com/meteor/meteor/issues/773 var maxAge = info.cacheable ? 1000 * 60 * 60 * 24 * 365 - : 1000 * 60 * 60 * 24; + : 0; // Set the X-SourceMap header, which current Chrome, FireFox, and Safari // understand. (The SourceMap header is slightly more spec-correct but FF @@ -403,14 +396,19 @@ WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) { } } + if (info.hash) { + res.setHeader('ETag', '"' + info.hash + '"'); + } + if (info.content) { res.write(info.content); res.end(); } else { - send(req, info.absolutePath) - .maxage(maxAge) - .hidden(true) // if we specified a dotfile in the manifest, serve it - .on('error', function (err) { + send(req, info.absolutePath, { + maxage: maxAge, + dotfiles: 'allow', // if we specified a dotfile in the manifest, serve it + lastModified: false // don't set last-modified based on the file date + }).on('error', function (err) { Log.error("Error serving static file " + err); res.writeHead(500); res.end(); @@ -475,6 +473,7 @@ var runWebAppServer = function () { staticFiles[urlPrefix + getItemPathname(item.url)] = { absolutePath: path.join(clientDir, item.path), cacheable: item.cacheable, + hash: item.hash, // Link from source to its map sourceMapUrl: item.sourceMapUrl, type: item.type @@ -505,6 +504,7 @@ var runWebAppServer = function () { staticFiles[path.join(urlPrefix, getItemPathname('/manifest.json'))] = { content: JSON.stringify(program), cacheable: true, + hash: program.version, type: "json" }; }; @@ -687,8 +687,19 @@ var runWebAppServer = function () { return undefined; } + if (request.url.query && request.url.query['meteor_dont_serve_index']) { + // When downloading files during a Cordova hot code push, we need + // to detect if a file is not available instead of inadvertently + // downloading the default index page. + // So similar to the situation above, we serve an uncached 404. + headers['Cache-Control'] = 'no-cache'; + res.writeHead(404, headers); + res.end("404 Not Found"); + return undefined; + } + // /packages/asdfsad ... /__cordova/dafsdf.js - var pathname = connect.utils.parseUrl(req).pathname; + var pathname = parseurl(req).pathname; var archKey = pathname.split('/')[1]; var archKeyCleaned = 'web.' + archKey.replace(/^__/, '');