From 882a8e682cb9e6aa4ba5be2d02f5b9ebcbdf7c2c Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Thu, 9 Feb 2023 16:20:08 -0700 Subject: [PATCH] Octane-ify runtime code --- .../clear-double-boot.js | 24 +-- .../addon/locations/none.js | 57 ++++--- .../addon/services/fastboot.js | 148 +++++++++++------- .../unit/services/fastboot/shoebox-test.js | 2 +- yarn.lock | 13 ++ 5 files changed, 150 insertions(+), 94 deletions(-) diff --git a/packages/ember-cli-fastboot/addon/instance-initializers/clear-double-boot.js b/packages/ember-cli-fastboot/addon/instance-initializers/clear-double-boot.js index fd851cc9d..95a0d17a0 100644 --- a/packages/ember-cli-fastboot/addon/instance-initializers/clear-double-boot.js +++ b/packages/ember-cli-fastboot/addon/instance-initializers/clear-double-boot.js @@ -11,32 +11,36 @@ export function clearHtml() { let endMarker = document.getElementById('fastboot-body-end'); if (current && endMarker) { - let shoeboxNodes = document.querySelectorAll('[type="fastboot/shoebox"]'); - let shoeboxNodesArray = []; // Note that IE11 doesn't support more concise options like Array.from, so we have to do something like this - for(let i=0; i < shoeboxNodes.length; i++){ - shoeboxNodesArray.push(shoeboxNodes[i]); - } + let shoeboxNodes = Array.from( + document.querySelectorAll('[type="fastboot/shoebox"]') + ); + let parent = current.parentElement; let nextNode; do { nextNode = current.nextSibling; parent.removeChild(current); current = nextNode; - } while (nextNode && nextNode !== endMarker && shoeboxNodesArray.indexOf(nextNode) < 0); + } while ( + nextNode && + nextNode !== endMarker && + !shoeboxNodes.includes(nextNode) + ); endMarker.parentElement.removeChild(endMarker); } } + export default { - name: "clear-double-boot", + name: 'clear-double-boot', initialize(instance) { if (typeof FastBoot === 'undefined') { var originalDidCreateRootView = instance.didCreateRootView; - instance.didCreateRootView = function() { + instance.didCreateRootView = function () { clearHtml(); originalDidCreateRootView.apply(instance, arguments); }; } - } -} + }, +}; diff --git a/packages/ember-cli-fastboot/addon/locations/none.js b/packages/ember-cli-fastboot/addon/locations/none.js index 2224a5409..13178e275 100644 --- a/packages/ember-cli-fastboot/addon/locations/none.js +++ b/packages/ember-cli-fastboot/addon/locations/none.js @@ -1,32 +1,41 @@ -import { computed, get } from '@ember/object'; -import { bool, readOnly } from '@ember/object/computed'; import { inject as service } from '@ember/service'; -import { getOwner } from '@ember/application' -import NoneLocation from '@ember/routing/none-location' +import { getOwner } from '@ember/application'; +import NoneLocation from '@ember/routing/none-location'; const TEMPORARY_REDIRECT_CODE = 307; -export default NoneLocation.extend({ - implementation: 'fastboot', - fastboot: service(), +export default class FastbootLocation extends NoneLocation { + implementation = 'fastboot'; - _config: computed(function () { - return getOwner(this).resolveRegistration('config:environment'); - }), + @service fastboot; - _fastbootHeadersEnabled: bool('_config.fastboot.fastbootHeaders'), + #config; + get _config() { + return ( + this.#config ?? + (this.#config = getOwner(this).resolveRegistration('config:environment')) + ); + } + + get _fastbootHeadersEnabled() { + return this._config.fastboot.fastbootHeaders; + } - _redirectCode: computed(function () { - return get(this, '_config.fastboot.redirectCode') || TEMPORARY_REDIRECT_CODE; - }), + get _redirectCode() { + return this._config.fastboot.redirectCode || TEMPORARY_REDIRECT_CODE; + } - _response: readOnly('fastboot.response'), - _request: readOnly('fastboot.request'), + get _response() { + return this.fastboot.response; + } + get _request() { + return this.fastboot.request; + } setURL(path) { - if (get(this, 'fastboot.isFastBoot')) { - let response = get(this, '_response'); - let currentPath = get(this, 'path'); + if (this.fastboot.isFastBoot) { + let response = this._response; + let currentPath = this.path; let isInitialPath = !currentPath || currentPath.length === 0; if (!isInitialPath) { @@ -34,20 +43,20 @@ export default NoneLocation.extend({ let isTransitioning = currentPath !== path; if (isTransitioning) { - let host = get(this, '_request.host'); + let host = this._request.host; let redirectURL = `//${host}${path}`; - response.statusCode = this.get('_redirectCode'); + response.statusCode = this._redirectCode; response.headers.set('location', redirectURL); } } // for testing and debugging - if (get(this, '_fastbootHeadersEnabled')) { + if (this._fastbootHeadersEnabled) { response.headers.set('x-fastboot-path', path); } } - this._super(...arguments); + super.setURL(...arguments); } -}); +} diff --git a/packages/ember-cli-fastboot/addon/services/fastboot.js b/packages/ember-cli-fastboot/addon/services/fastboot.js index 9d3e004fd..68d511927 100644 --- a/packages/ember-cli-fastboot/addon/services/fastboot.js +++ b/packages/ember-cli-fastboot/addon/services/fastboot.js @@ -1,18 +1,10 @@ /* global FastBoot */ import { getOwner } from '@ember/application'; -import { computed, get } from '@ember/object'; -import { readOnly } from '@ember/object/computed'; import { assert } from '@ember/debug'; -import EObject from '@ember/object'; import Service from '@ember/service'; -const RequestObject = EObject.extend({ - init() { - this._super(...arguments); - - let request = this.request; - delete this.request; - +class RequestObject { + constructor(request) { this.method = request.method; this.body = request.body; this.cookies = request.cookies; @@ -20,94 +12,132 @@ const RequestObject = EObject.extend({ this.queryParams = request.queryParams; this.path = request.path; this.protocol = request.protocol; - this._host = function() { + this._host = function () { return request.host(); }; - }, + } - host: computed(function() { - return this._host(); - }) -}); + get host() { + return this._host; + } +} + +class Shoebox { + /** + * + * @param {FastBootService} fastboot + */ + constructor(fastboot) { + this.fastboot = fastboot; + } -const Shoebox = EObject.extend({ put(key, value) { - assert('shoebox.put is only invoked from the FastBoot rendered application', this.get('fastboot.isFastBoot')); + assert( + 'shoebox.put is only invoked from the FastBoot rendered application', + this.fastboot.isFastBoot + ); assert('the provided key is a string', typeof key === 'string'); - let fastbootInfo = this.get('fastboot._fastbootInfo'); - if (!fastbootInfo.shoebox) { fastbootInfo.shoebox = {}; } + let fastbootInfo = this.fastboot._fastbootInfo; + if (!fastbootInfo.shoebox) { + fastbootInfo.shoebox = {}; + } fastbootInfo.shoebox[key] = value; - }, + } retrieve(key) { - if (this.get('fastboot.isFastBoot')) { - let shoebox = this.get('fastboot._fastbootInfo.shoebox'); - if (!shoebox) { return; } + if (this.fastboot.isFastBoot) { + let shoebox = this.fastboot._fastbootInfo.shoebox; + if (!shoebox) { + return; + } return shoebox[key]; } - let shoeboxItem = this.get(key); - if (shoeboxItem) { return shoeboxItem; } + let shoeboxItem = this[key]; + if (shoeboxItem) { + return shoeboxItem; + } let el = document.querySelector(`#shoebox-${key}`); - if (!el) { return; } + if (!el) { + return; + } let valueString = el.textContent; - if (!valueString) { return; } + if (!valueString) { + return; + } shoeboxItem = JSON.parse(valueString); - this.set(key, shoeboxItem); + this[key] = shoeboxItem; return shoeboxItem; } -}); +} + +class FastBootService extends Service { + isFastBoot = typeof FastBoot !== 'undefined'; -const FastBootService = Service.extend({ - isFastBoot: typeof FastBoot !== 'undefined', + /** @type {Shoebox} */ + shoebox; - isFastboot: computed(function() { + // eslint-disable-next-line getter-return + get isFastboot() { assert( 'The fastboot service does not have an `isFastboot` property. This is likely a typo. Please use `isFastBoot` instead.', false ); - }), + } - init() { - this._super(...arguments); + constructor(owner) { + super(owner); + this.shoebox = new Shoebox(this); + } - let shoebox = Shoebox.create({ fastboot: this }); - this.set('shoebox', shoebox); - }, + get response() { + return this._fastbootInfo?.response; + } - response: readOnly('_fastbootInfo.response'), - metadata: readOnly('_fastbootInfo.metadata'), + get metadata() { + return this._fastbootInfo?.metadata; + } - request: computed(function() { + #request; + get request() { if (!this.isFastBoot) return null; - return RequestObject.create({ request: get(this, '_fastbootInfo.request') }); - }), - - // this getter/setter pair is to avoid deprecation from [RFC - 680](https://github.com/emberjs/rfcs/pull/680) - _fastbootInfo: computed({ - get() { - if (this.__fastbootInfo) { - return this.__fastbootInfo; - } + if (!this.#request) { + // eslint-disable-next-line ember/no-side-effects + this.#request = RequestObject.create(this._fastbootInfo?.request); + } + + return this.#request; + } - return getOwner(this).lookup('info:-fastboot'); - }, - set(_key, value) { - this.__fastbootInfo = value; - return value; + #fastbootInfo; + + get _fastbootInfo() { + if (!this.#fastbootInfo) { + // eslint-disable-next-line ember/no-side-effects + this.#fastbootInfo = getOwner(this).lookup('info:-fastboot'); } - }), + + return this.#fastbootInfo; + } + + /** @internal */ // Intended for use only in tests! + set _fastbootInfo(value) { + this.#fastbootInfo = value; + } deferRendering(promise) { - assert('deferRendering requires a promise or thennable object', typeof promise.then === 'function'); + assert( + 'deferRendering requires a promise or thennable object', + typeof promise.then === 'function' + ); this._fastbootInfo.deferRendering(promise); } -}); +} export default FastBootService; diff --git a/packages/ember-cli-fastboot/tests/unit/services/fastboot/shoebox-test.js b/packages/ember-cli-fastboot/tests/unit/services/fastboot/shoebox-test.js index 120277422..c421c68f8 100644 --- a/packages/ember-cli-fastboot/tests/unit/services/fastboot/shoebox-test.js +++ b/packages/ember-cli-fastboot/tests/unit/services/fastboot/shoebox-test.js @@ -89,4 +89,4 @@ module('Unit | Service | fastboot | shoebox', function(hooks) { assert.strictEqual(service.get('shoebox').retrieve('foo'), 'bar'); }); -}); \ No newline at end of file +}); diff --git a/yarn.lock b/yarn.lock index 9c9f188bf..8f7a0547d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9819,6 +9819,19 @@ fastboot-transform@^0.1.3: broccoli-stew "^1.5.0" convert-source-map "^1.5.1" +fastboot@^3.0.3: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fastboot/-/fastboot-3.3.2.tgz#bf1ac7b01937846b63423a88138e13eb50406d2e" + integrity sha512-2NKTW32GvEsDyBrdw1trW1JsbS+9/7sAQuKwkht12mNitimRrSKVLP2AxsM/HSXQE+aiET4XCfKdyeIy0kQbKQ== + dependencies: + chalk "^4.1.2" + cookie "^0.4.1" + debug "^4.3.3" + jsdom "^19.0.0" + resolve "^1.22.0" + simple-dom "^1.4.0" + source-map-support "^0.5.21" + fastq@^1.6.0: version "1.8.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481"