From 57c1e622193b385c6911ecabc3b93350b378d5a2 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 25 Oct 2019 07:24:27 -0700 Subject: [PATCH] [BUGFIX release] Enable `store.createRecord` in FastBoot (#6568) * Add FastBoot test for store.createRecord Fails at the moment. * Enable store.createRecord in FastBoot Changes the V4 UUID generation to leverage `FastBoot.require` when possible. This currently requires that the host application add the following to their `package.json`: ``` "fastbootDependencies": [ "crypto" ] ``` * fix types --- packages/-fastboot-test-app/app/router.ts | 6 ++++- .../app/routes/person/new.js | 10 +++++++ .../app/templates/person/new.hbs | 6 +++++ packages/-fastboot-test-app/package.json | 3 +++ .../tests/fastboot/person/new-test.js | 16 ++++++++++++ .../-private/identifiers/utils/uuid-v4.ts | 26 ++++++++++++++++--- packages/store/types/fastboot/index.d.ts | 4 +++ 7 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 packages/-fastboot-test-app/app/routes/person/new.js create mode 100644 packages/-fastboot-test-app/app/templates/person/new.hbs create mode 100644 packages/-fastboot-test-app/tests/fastboot/person/new-test.js create mode 100644 packages/store/types/fastboot/index.d.ts diff --git a/packages/-fastboot-test-app/app/router.ts b/packages/-fastboot-test-app/app/router.ts index 8f6f4598916..c4ff0a4c695 100644 --- a/packages/-fastboot-test-app/app/router.ts +++ b/packages/-fastboot-test-app/app/router.ts @@ -6,6 +6,10 @@ const Router = EmberRouter.extend({ rootURL: config.rootURL, }); -Router.map(function() {}); +Router.map(function() { + this.route('person', function() { + this.route('new'); + }); +}); export default Router; diff --git a/packages/-fastboot-test-app/app/routes/person/new.js b/packages/-fastboot-test-app/app/routes/person/new.js new file mode 100644 index 00000000000..29d4d380b62 --- /dev/null +++ b/packages/-fastboot-test-app/app/routes/person/new.js @@ -0,0 +1,10 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default Route.extend({ + store: service(), + + model() { + return this.store.createRecord('person'); + }, +}); diff --git a/packages/-fastboot-test-app/app/templates/person/new.hbs b/packages/-fastboot-test-app/app/templates/person/new.hbs new file mode 100644 index 00000000000..f16b2fa3520 --- /dev/null +++ b/packages/-fastboot-test-app/app/templates/person/new.hbs @@ -0,0 +1,6 @@ +
+ +
diff --git a/packages/-fastboot-test-app/package.json b/packages/-fastboot-test-app/package.json index 884425abc37..6eee03142b5 100644 --- a/packages/-fastboot-test-app/package.json +++ b/packages/-fastboot-test-app/package.json @@ -56,6 +56,9 @@ "qunit-dom": "^0.9.0", "typescript": "~3.6.4" }, + "fastbootDependencies": [ + "crypto" + ], "engines": { "node": "8.* || >= 10.*" } diff --git a/packages/-fastboot-test-app/tests/fastboot/person/new-test.js b/packages/-fastboot-test-app/tests/fastboot/person/new-test.js new file mode 100644 index 00000000000..8aaf0940e66 --- /dev/null +++ b/packages/-fastboot-test-app/tests/fastboot/person/new-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setup, visit } from 'ember-cli-fastboot-testing/test-support'; + +module('FastBoot | /person/new', function(hooks) { + setup(hooks); + + test('it does not error in SSR (GH#6563)', async function(assert) { + await visit('/person/new'); + + // from application.hbs + assert.dom('h1').hasText('Ember Data'); + assert.dom('a').hasAttribute('href', '/tests'); + + assert.dom('.person-name').exists(); + }); +}); diff --git a/packages/store/addon/-private/identifiers/utils/uuid-v4.ts b/packages/store/addon/-private/identifiers/utils/uuid-v4.ts index d32511f080c..407fd007103 100644 --- a/packages/store/addon/-private/identifiers/utils/uuid-v4.ts +++ b/packages/store/addon/-private/identifiers/utils/uuid-v4.ts @@ -9,10 +9,28 @@ declare global { } } -const CRYPTO = - typeof window !== 'undefined' && window.msCrypto && typeof window.msCrypto.getRandomValues === 'function' - ? window.msCrypto - : window.crypto; +const CRYPTO = (() => { + const hasWindow = typeof window !== 'undefined'; + const isFastBoot = typeof FastBoot !== 'undefined'; + + if (isFastBoot) { + return { + getRandomValues(buffer: Uint8Array) { + return (FastBoot as FastBoot).require('crypto').randomFillSync(buffer); + }, + }; + } else if (hasWindow && typeof window.crypto !== 'undefined') { + return window.crypto; + } else if ( + hasWindow && + typeof window.msCrypto !== 'undefined' && + typeof window.msCrypto.getRandomValues === 'function' + ) { + return window.msCrypto; + } else { + throw new Error('ember-data: Cannot find a valid way to generate local identifiers'); + } +})(); // we might be able to optimize this by requesting more bytes than we need at a time function rng() { diff --git a/packages/store/types/fastboot/index.d.ts b/packages/store/types/fastboot/index.d.ts new file mode 100644 index 00000000000..818a8a945a4 --- /dev/null +++ b/packages/store/types/fastboot/index.d.ts @@ -0,0 +1,4 @@ +interface FastBoot { + require(moduleName: string): any; +} +const FastBoot: undefined | FastBoot;