From 1a4852e18a0e2bd1e919df302ce35675bf149b54 Mon Sep 17 00:00:00 2001 From: steve Date: Tue, 16 Jun 2020 22:27:10 +0200 Subject: [PATCH 1/2] remove unneeded dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index baf28a4b..3a48ade8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "ember-cli-eslint": "^5.1.0", "ember-cli-fastboot": "^2.0.4", "ember-cli-htmlbars": "^4.0.1", - "ember-cli-htmlbars-inline-precompile": "^3.0.0", "ember-cli-inject-live-reload": "^1.8.2", "ember-cli-mirage": "1.1.6", "ember-cli-qunit": "^4.3.2", From a8d87a762339e90b266dfadc70b2b2b832539a15 Mon Sep 17 00:00:00 2001 From: steve Date: Tue, 16 Jun 2020 22:29:29 +0200 Subject: [PATCH 2/2] add option to configure when shoebox data expires --- addon/mixins/fastboot-adapter.js | 25 ++++++++++++++++--- .../ember-data-storefront.js | 3 +++ .../app/pods/docs/guides/fastboot/template.md | 13 ++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/addon/mixins/fastboot-adapter.js b/addon/mixins/fastboot-adapter.js index 3e337d8d..03ce4ba3 100644 --- a/addon/mixins/fastboot-adapter.js +++ b/addon/mixins/fastboot-adapter.js @@ -1,8 +1,10 @@ +/* eslint-disable ember/no-new-mixins */ + import Mixin from '@ember/object/mixin'; import { inject as service } from '@ember/service'; import { resolve } from 'rsvp'; import { cacheKey, shoeboxize } from 'ember-data-storefront/-private/utils/get-key'; - +import { getOwner } from '@ember/application'; /** This mixin adds fastboot support to your data adapter. It provides no public API, it only needs to be mixed into your adapter. @@ -28,6 +30,13 @@ export default Mixin.create({ fastboot: service(), storefront: service(), + init() { + this._super(...arguments); + if (this.fastboot.isFastBoot) { + this.set('storefront.fastbootShoeboxCreated', new Date()); + } + }, + ajax(url, type, options = {}) { let cachedPayload = this._getStorefrontBoxedQuery(type, url, options.data); let maybeAddToShoebox = this._makeStorefrontQueryBoxer(type, url, options.data); @@ -59,13 +68,23 @@ export default Mixin.create({ let shoebox = fastboot && fastboot.get('shoebox'); let box = shoebox && shoebox.retrieve('ember-data-storefront'); + const config = getOwner(this).resolveRegistration('config:environment'); + const maxAgeMinutes = config.storefront ? config.storefront.maxAge : undefined; + if (!isFastboot && box && box.queries && Object.keys(box.queries).length > 0) { + const valid = this.isDateValid(box.created, maxAgeMinutes); let key = shoeboxize(cacheKey([type, url.replace(/^.*\/\/[^\/]+/, ''), params])); - payload = box.queries[key]; + + if (valid) { + payload = box.queries[key]; + } delete box.queries[key]; } return payload; - } + }, + isDateValid(createdString, maxAgeMinutes) { + return (new Date() - new Date(createdString)) / 1000 / 60 < maxAgeMinutes; + } }) diff --git a/fastboot/instance-initializers/ember-data-storefront.js b/fastboot/instance-initializers/ember-data-storefront.js index 247ce1c4..7c22d102 100644 --- a/fastboot/instance-initializers/ember-data-storefront.js +++ b/fastboot/instance-initializers/ember-data-storefront.js @@ -6,6 +6,9 @@ export function initialize(applicationInstance) { let storefront = applicationInstance.lookup('service:storefront'); shoebox.put('ember-data-storefront', { + get created() { + return storefront.get('fastbootShoeboxCreated'); + }, get queries() { return storefront.get('fastbootDataRequests'); } diff --git a/tests/dummy/app/pods/docs/guides/fastboot/template.md b/tests/dummy/app/pods/docs/guides/fastboot/template.md index a868fbf1..57e4278d 100644 --- a/tests/dummy/app/pods/docs/guides/fastboot/template.md +++ b/tests/dummy/app/pods/docs/guides/fastboot/template.md @@ -38,3 +38,16 @@ The `FastbootAdapter` works by storing the results of AJAX requests into fastboo The adapter will delete queries from the shoebox as soon as they are used. This ensures that if your application ever tries to re-make a network request in the future, it will not be served a cached version. Fastboot rendered pages need to be generated quickly, since they are rendered on the server in an HTTP request-resposne cycle. Because of this, they tend to not make many network requests. This means that a few seconds after the browser re-renders a fastboot page, the query cache should be empty since the client rendered application will have re-fetched all of the fastboot data. + +## Configure an expiration date + +In certain cases, like the browser restoring its session, a cached version of the index.html page may be served, which contains shoebox data from the initial, cached request. The adapter is not aware that this data is stale, and outdated information is displayed to the user. To prevent this you can configure a duration after which data will no longer be served from the shoebox. + +``` +// config/environment.js +ENV = { + storefront: { + maxAge: 10 // shoebox expires 10 minutes after the fastboot server has rendered the page + } +} +```