From 32604cb0ba3e80d4aee527b80e4c2f695b2c5cb5 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 | 15 +++++ .../app/routes/person/new.js | 10 +++ .../app/templates/person/new.hbs | 6 ++ packages/-fastboot-test-app/package.json | 65 +++++++++++++++++++ .../tests/fastboot/person/new-test.js | 16 +++++ .../-private/identifiers/utils/uuid-v4.ts | 28 ++++++-- packages/store/types/fastboot/index.d.ts | 4 ++ 7 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 packages/-fastboot-test-app/app/router.ts 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/package.json 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 new file mode 100644 index 00000000000..c4ff0a4c695 --- /dev/null +++ b/packages/-fastboot-test-app/app/router.ts @@ -0,0 +1,15 @@ +import EmberRouter from '@ember/routing/router'; +import config from './config/environment'; + +const Router = EmberRouter.extend({ + location: config.locationType, + rootURL: config.rootURL, +}); + +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 new file mode 100644 index 00000000000..6eee03142b5 --- /dev/null +++ b/packages/-fastboot-test-app/package.json @@ -0,0 +1,65 @@ +{ + "name": "fastboot-test-app", + "version": "3.15.0-alpha.1", + "private": true, + "description": "Small description for fastboot-test-app goes here", + "repository": "", + "license": "MIT", + "author": "", + "directories": { + "doc": "doc", + "test": "tests" + }, + "scripts": { + "build": "ember build", + "lint:hbs": "ember-template-lint .", + "lint:js": "eslint --config ../../.eslintrc.js --ignore-path ../../.eslintignore .", + "start": "ember serve", + "test": "ember test --test-port=0" + }, + "dependencies": { + "ember-data": "3.15.0-alpha.1", + "ember-inflector": "^3.0.1" + }, + "devDependencies": { + "@ember/optional-features": "^1.1.0", + "@types/ember": "^3.1.1", + "@types/ember-qunit": "^3.4.7", + "@types/ember__test-helpers": "~0.7.9", + "@types/qunit": "^2.5.3", + "@types/rsvp": "^4.0.3", + "broccoli-asset-rev": "^3.0.0", + "ember-cli": "~3.13.1", + "ember-cli-app-version": "^3.2.0", + "ember-cli-babel": "^7.12.0", + "ember-cli-dependency-checker": "^3.2.0", + "ember-cli-fastboot": "^2.2.1", + "ember-cli-fastboot-testing": "^0.2.3", + "ember-cli-htmlbars": "^4.0.8", + "ember-cli-inject-live-reload": "^2.0.2", + "ember-cli-template-lint": "^1.0.0-beta.1", + "ember-cli-typescript": "^3.0.0", + "ember-cli-typescript-blueprints": "^3.0.0", + "ember-export-application-global": "^2.0.0", + "ember-fetch": "^6.7.1", + "ember-load-initializers": "^2.1.0", + "ember-maybe-import-regenerator": "^0.1.6", + "ember-qunit": "^4.5.1", + "ember-resolver": "^5.3.0", + "ember-simple-tree": "^0.7.1", + "ember-source": "^3.13.3", + "eslint": "^6.5.1", + "eslint-plugin-ember": "^7.2.0", + "eslint-plugin-node": "^10.0.0", + "loader.js": "^4.7.0", + "qunit": "^2.9.3", + "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 a41ec7e88c5..407fd007103 100644 --- a/packages/store/addon/-private/identifiers/utils/uuid-v4.ts +++ b/packages/store/addon/-private/identifiers/utils/uuid-v4.ts @@ -9,12 +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;