From e63ef0524745628e9d1b48eff2ba74ac8b46046b Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 7 Jun 2017 16:33:09 -0700 Subject: [PATCH] RFC: Do not include package-local polyfills. This removes babel's core-js polyfills from the distributed NPM builds. This aids in further reducing app bundle size when targeting modern browsers, and allows flexibility in how these polyfills are provided if necessary, which can help fix React Native specific issues, as illustrated in #1799 and #1704 and #1818. The drawback is that polyfills for these things are now something that client developers will need to think about directly. Shipping Relay to older browsers before this diff should work fine, but after this diff will require global polyfills. As such, this diff may constitute at least a minor-breaking change. --- docs/modern/Introduction.md | 26 +++++++++++++++++++ gulpfile.js | 15 ++--------- .../classic/ReactRelayClassicExports.js | 21 ++++++++++----- packages/relay-runtime/RelayRuntime.js | 16 ++++++++++++ scripts/getBabelOptions.js | 4 +-- scripts/jest/preprocessor.js | 1 + 6 files changed, 61 insertions(+), 22 deletions(-) diff --git a/docs/modern/Introduction.md b/docs/modern/Introduction.md index b7eca9b710fb6..3f58b8ea103ba 100644 --- a/docs/modern/Introduction.md +++ b/docs/modern/Introduction.md @@ -48,6 +48,32 @@ Run the Relay Compiler after making changes to any GraphQL in your Relay applica Then after making edits to your application files, just run `yarn run relay` to generate new files, or `yarn run relay -- --watch` to run the compiler as a long-lived process which automatically generates new files whenever you save. +## JavaScript environment requirements + +The Relay Modern packages distributed on NPM use the widely-supported ES5 +version of JavaScript to support as many browser environments as possible. + +However, Relay Modern expects modern JavaScript global types (`Map`, `Set`, +`Promise`, `Object.assign`) to be defined. If you support older browsers and +devices which may not yet provide these natively, consider including a global +polyfill in your bundled application, such as [core-js][] or +[babel-polyfill](https://babeljs.io/docs/usage/polyfill/). + +A polyfilled environment for Relay using [core-js][] to support older browsers +might look like: + +```js +require('core-js/es6/map'); +require('core-js/es6/set'); +require('core-js/es6/promise'); +require('core-js/es6/object'); + +require('./myRelayApplication'); +``` + +[core-js]: https://github.com/zloirock/core-js + + ## Migrating to Relay Modern Migrating a Relay Classic app to Relay Modern doesn't require rewriting from diff --git a/gulpfile.js b/gulpfile.js index f36d1006d0c4f..fef56f61aa44f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -15,18 +15,6 @@ const babelOptions = require('./scripts/getBabelOptions')({ 'babel-core': 'babel-core', 'babel-generator': 'babel-generator', 'babel-polyfill': 'babel-polyfill', - 'babel-runtime/core-js/array/from': 'babel-runtime/core-js/array/from', - 'babel-runtime/core-js/json/stringify': 'babel-runtime/core-js/json/stringify', - 'babel-runtime/core-js/map': 'babel-runtime/core-js/map', - 'babel-runtime/core-js/object/assign': 'babel-runtime/core-js/object/assign', - 'babel-runtime/core-js/object/freeze': 'babel-runtime/core-js/object/freeze', - 'babel-runtime/core-js/object/get-own-property-names': 'babel-runtime/core-js/object/get-own-property-names', - 'babel-runtime/core-js/object/is-frozen': 'babel-runtime/core-js/object/is-frozen', - 'babel-runtime/core-js/object/keys': 'babel-runtime/core-js/object/keys', - 'babel-runtime/core-js/object/values': 'babel-runtime/core-js/object/values', - 'babel-runtime/core-js/promise': 'fbjs/lib/Promise', - 'babel-runtime/core-js/set': 'babel-runtime/core-js/set', - 'babel-runtime/core-js/weak-map': 'babel-runtime/core-js/weak-map', 'babel-runtime/helpers/asyncToGenerator': 'babel-runtime/helpers/asyncToGenerator', 'babel-runtime/helpers/classCallCheck': 'babel-runtime/helpers/classCallCheck', 'babel-runtime/helpers/defineProperty': 'babel-runtime/helpers/defineProperty', @@ -42,6 +30,7 @@ const babelOptions = require('./scripts/getBabelOptions')({ 'fb-watchman': 'fb-watchman', 'fs': 'fs', 'graphql': 'graphql', + 'immutable': 'immutable', 'net': 'net', 'path': 'path', 'prop-types': 'prop-types', @@ -56,7 +45,7 @@ const babelOptions = require('./scripts/getBabelOptions')({ }, plugins: [ 'transform-flow-strip-types', - 'transform-runtime', + ['transform-runtime', {"polyfill": false}], ], postPlugins: [ 'transform-async-to-generator', diff --git a/packages/react-relay/classic/ReactRelayClassicExports.js b/packages/react-relay/classic/ReactRelayClassicExports.js index ac6bc22cf7ba4..518d5a9b85b73 100644 --- a/packages/react-relay/classic/ReactRelayClassicExports.js +++ b/packages/react-relay/classic/ReactRelayClassicExports.js @@ -17,14 +17,21 @@ const RelayDefaultNetworkLayer = require('RelayDefaultNetworkLayer'); const RelayPublic = require('RelayPublic'); const RelayStore = require('RelayStore'); -const warning = require('warning'); - +// As early as possible, check for the existence of the JavaScript globals which +// React Relay relies upon, and produce a clear message if they do not exist. if (__DEV__) { - warning( - typeof Promise === 'function' && Array.prototype.find, - 'Relay relies on polyfills for ES6 features in older browsers. ' + - 'Babel provides a good one: https://babeljs.io/docs/usage/polyfill/', - ); + if ( + typeof Map !== 'function' || + typeof Set !== 'function' || + typeof Promise !== 'function' || + typeof Object.assign !== 'function' || + typeof Array.prototype.find !== 'function' + ) { + throw new Error( + 'react-relay requires Map, Set, Promise, Object.assign, and Array#find ' + + 'to exist. Use a polyfill to provide these for older browsers.' + ); + } } // By default, assume that GraphQL is served at `/graphql` on the same domain. diff --git a/packages/relay-runtime/RelayRuntime.js b/packages/relay-runtime/RelayRuntime.js index 9eb8c786bbc69..486950883b11b 100644 --- a/packages/relay-runtime/RelayRuntime.js +++ b/packages/relay-runtime/RelayRuntime.js @@ -35,6 +35,22 @@ export type { ConcreteFragment, } from 'RelayConcreteNode'; +// As early as possible, check for the existence of the JavaScript globals which +// Relay Runtime relies upon, and produce a clear message if they do not exist. +if (__DEV__) { + if ( + typeof Map !== 'function' || + typeof Set !== 'function' || + typeof Promise !== 'function' || + typeof Object.assign !== 'function' + ) { + throw new Error( + 'relay-runtime requires Map, Set, Promise, and Object.assign to exist. ' + + 'Use a polyfill to provide these for older browsers.' + ); + } +} + /** * The public interface to Relay Runtime. */ diff --git a/scripts/getBabelOptions.js b/scripts/getBabelOptions.js index f0de6266c4a50..928b4fe58c6e7 100644 --- a/scripts/getBabelOptions.js +++ b/scripts/getBabelOptions.js @@ -19,11 +19,11 @@ module.exports = function(options) { }, options); const fbjsPreset = require('babel-preset-fbjs/configure')({ - autoImport: true, + autoImport: false, + objectAssign: false, inlineRequires: true, rewriteModules: { map: assign({}, - require('fbjs-scripts/third-party-module-map'), require('fbjs/module-map'), options.moduleMap ), diff --git a/scripts/jest/preprocessor.js b/scripts/jest/preprocessor.js index 3d3bde5cafcad..1fc0543b74fa0 100644 --- a/scripts/jest/preprocessor.js +++ b/scripts/jest/preprocessor.js @@ -22,6 +22,7 @@ const SCHEMA_PATH = path.resolve(__dirname, '../../packages/relay-compiler/testu const babelOptions = getBabelOptions({ env: 'test', moduleMap: { + 'immutable': 'immutable', 'React': 'react', 'reactComponentExpect': 'react-dom/lib/reactComponentExpect', 'ReactDOM': 'react-dom',