diff --git a/packages/metro-react-native-babel-preset/package.json b/packages/metro-react-native-babel-preset/package.json index 7934a35f3e..9d167b5cdc 100644 --- a/packages/metro-react-native-babel-preset/package.json +++ b/packages/metro-react-native-babel-preset/package.json @@ -40,6 +40,7 @@ "@babel/plugin-transform-react-jsx": "7.0.0-beta.54", "@babel/plugin-transform-react-jsx-source": "7.0.0-beta.54", "@babel/plugin-transform-regenerator": "7.0.0-beta.54", + "@babel/plugin-transform-runtime": "7.0.0-beta.54", "@babel/plugin-transform-shorthand-properties": "7.0.0-beta.54", "@babel/plugin-transform-spread": "7.0.0-beta.54", "@babel/plugin-transform-sticky-regex": "7.0.0-beta.54", diff --git a/packages/metro-react-native-babel-preset/src/configs/main.js b/packages/metro-react-native-babel-preset/src/configs/main.js index 5871eb5c7f..220910b2cb 100644 --- a/packages/metro-react-native-babel-preset/src/configs/main.js +++ b/packages/metro-react-native-babel-preset/src/configs/main.js @@ -32,6 +32,14 @@ const defaultPlugins = [ [require('@babel/plugin-transform-shorthand-properties')], [require('@babel/plugin-transform-react-jsx')], [require('@babel/plugin-transform-regenerator')], + [ + require('@babel/plugin-transform-runtime'), + { + helpers: true, + polyfill: false, + regenerator: true, + }, + ], [require('@babel/plugin-transform-sticky-regex')], [require('@babel/plugin-transform-unicode-regex')], [ diff --git a/packages/metro-react-native-babel-preset/src/plugins.js b/packages/metro-react-native-babel-preset/src/plugins.js index b53d23bbe4..d64cff8a4f 100644 --- a/packages/metro-react-native-babel-preset/src/plugins.js +++ b/packages/metro-react-native-babel-preset/src/plugins.js @@ -30,6 +30,7 @@ module.exports = { '@babel/plugin-transform-react-jsx': require('@babel/plugin-transform-react-jsx'), '@babel/plugin-transform-react-jsx-source': require('@babel/plugin-transform-react-jsx-source'), '@babel/plugin-transform-regenerator': require('@babel/plugin-transform-regenerator'), + '@babel/plugin-transform-runtime': require('@babel/plugin-transform-runtime'), '@babel/plugin-transform-spread': require('@babel/plugin-transform-spread'), '@babel/plugin-transform-sticky-regex': require('@babel/plugin-transform-sticky-regex'), '@babel/plugin-transform-unicode-regex': require('@babel/plugin-transform-unicode-regex'), diff --git a/packages/metro/src/JSTransformer/worker/__tests__/__snapshots__/worker-test.js.snap b/packages/metro/src/JSTransformer/worker/__tests__/__snapshots__/worker-test.js.snap index 4d0f5d305b..891d460c96 100644 --- a/packages/metro/src/JSTransformer/worker/__tests__/__snapshots__/worker-test.js.snap +++ b/packages/metro/src/JSTransformer/worker/__tests__/__snapshots__/worker-test.js.snap @@ -1,3 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`code transformation worker: reports filename when encountering unsupported dynamic dependency 1`] = `"/root/local/file.js:3:10: calls to \`require\` expect exactly 1 string literal argument, but this was found: \`require(a)\`."`; + +exports[`code transformation worker: transforms an es module with regenerator 1`] = ` +"__d(function (global, _$$_REQUIRE, module, exports, _dependencyMap) { + var _interopRequireDefault = _$$_REQUIRE(_dependencyMap[0], \\"@babel/runtime/helpers/interopRequireDefault\\"); + + Object.defineProperty(exports, \\"__esModule\\", { + value: true + }); + exports.test = test; + + var _regenerator = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[1], \\"@babel/runtime/regenerator\\")); + + function test() { + return _regenerator.default.async(function test$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + case \\"end\\": + return _context.stop(); + } + } + }, null, this); + } +});" +`; diff --git a/packages/metro/src/JSTransformer/worker/__tests__/worker-test.js b/packages/metro/src/JSTransformer/worker/__tests__/worker-test.js index 0ee58efea8..d3305df5c2 100644 --- a/packages/metro/src/JSTransformer/worker/__tests__/worker-test.js +++ b/packages/metro/src/JSTransformer/worker/__tests__/worker-test.js @@ -145,24 +145,66 @@ describe('code transformation worker:', () => { '__d(function (global, _$$_REQUIRE, module, exports, _dependencyMap) {', " 'use strict';", '', - ' var _c = babelHelpers.interopRequireDefault(_$$_REQUIRE(_dependencyMap[0], "./c"));', + ' var _interopRequireDefault = _$$_REQUIRE(_dependencyMap[0], "@babel/runtime/helpers/interopRequireDefault");', '', - ' _$$_REQUIRE(_dependencyMap[1], "./a");', + ' var _c = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[1], "./c"));', + '', + ' _$$_REQUIRE(_dependencyMap[2], "./a");', '', ' arbitrary(code);', '', - ' var b = _$$_REQUIRE(_dependencyMap[2], "b");', + ' var b = _$$_REQUIRE(_dependencyMap[3], "b");', '});', ].join('\n'), ); expect(result.output[0].data.map).toHaveLength(14); expect(result.dependencies).toEqual([ + { + isAsync: false, + name: '@babel/runtime/helpers/interopRequireDefault', + }, {isAsync: false, name: './c'}, {isAsync: false, name: './a'}, {isAsync: false, name: 'b'}, ]); }); + it('transforms an es module with regenerator', async () => { + fs.writeFileSync( + '/root/local/file.js', + ['export async function test() {}'].join('\n'), + ); + + const {result} = await transformCode( + '/root/local/file.js', + 'local/file.js', + transformerPath, + { + dev: true, + transform: {}, + }, + [], + '', + 'minifyModulePath', + 'asyncRequire', + 'reject', + ); + + expect(result.output[0].type).toBe('js/module'); + expect(result.output[0].data.code).toMatchSnapshot(); + expect(result.output[0].data.map).toHaveLength(13); + expect(result.dependencies).toEqual([ + { + isAsync: false, + name: '@babel/runtime/helpers/interopRequireDefault', + }, + { + isAsync: false, + name: '@babel/runtime/regenerator', + }, + ]); + }); + it('reports filename when encountering unsupported dynamic dependency', async () => { fs.writeFileSync( '/root/local/file.js', diff --git a/packages/metro/src/lib/polyfills/__tests__/require-test.js b/packages/metro/src/lib/polyfills/__tests__/require-test.js index 7195074f68..56f2daf1cd 100644 --- a/packages/metro/src/lib/polyfills/__tests__/require-test.js +++ b/packages/metro/src/lib/polyfills/__tests__/require-test.js @@ -14,10 +14,6 @@ const fs = require('fs'); const {transformSync} = require('@babel/core'); -// Include the external-helpers plugin to be able to detect if they're -// needed when transforming the requirejs implementation. -const PLUGINS = ['@babel/plugin-external-helpers']; - function createModule( moduleSystem, moduleId, @@ -34,7 +30,6 @@ describe('require', () => { return transformSync(rawCode, { ast: false, babelrc: false, - plugins: PLUGINS.map(require), presets: [require.resolve('metro-react-native-babel-preset')], retainLines: true, sourceMaps: 'inline', @@ -56,9 +51,9 @@ describe('require', () => { }); it('does not need any babel helper logic', () => { - // Super-simple check to validate that no babel helpers are used. - // This check will need to be updated if https://fburl.com/6z0y2kf8 changes. - expect(moduleSystemCode.includes('babelHelpers')).toBe(false); + // The react native preset uses @babel/transform-runtime so helpers will be + // imported from @babel/runtime. + expect(moduleSystemCode.includes('@babel/runtime')).toBe(false); }); it('works with plain bundles', () => { diff --git a/packages/metro/src/reactNativeTransformer.js b/packages/metro/src/reactNativeTransformer.js index 973f54e4a0..1e4dec9b9f 100644 --- a/packages/metro/src/reactNativeTransformer.js +++ b/packages/metro/src/reactNativeTransformer.js @@ -12,7 +12,6 @@ 'use strict'; const crypto = require('crypto'); -const externalHelpersPlugin = require('babel-plugin-external-helpers'); const fs = require('fs'); const inlineRequiresPlugin = require('babel-preset-fbjs/plugins/inline-requires'); const json5 = require('json5'); @@ -28,7 +27,6 @@ type ModuleES6 = {__esModule?: boolean, default?: {}}; const cacheKeyParts = [ fs.readFileSync(__filename), - require('babel-plugin-external-helpers/package.json').version, require('babel-preset-fbjs/package.json').version, ]; @@ -127,7 +125,7 @@ function buildBabelConfig(filename, options, plugins?: BabelPlugins = []) { let config = Object.assign({}, babelRC, extraConfig); // Add extra plugins - const extraPlugins = [externalHelpersPlugin]; + const extraPlugins = []; if (options.inlineRequires) { extraPlugins.push(inlineRequiresPlugin); diff --git a/yarn.lock b/yarn.lock index 02b1903fe8..40cff81cd2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -491,6 +491,13 @@ dependencies: regenerator-transform "^0.13.3" +"@babel/plugin-transform-runtime@7.0.0-beta.54": + version "7.0.0-beta.54" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.0.0-beta.54.tgz#ad45d1e84a9d0cfc48df148dda609ff09c121fd2" + dependencies: + "@babel/helper-module-imports" "7.0.0-beta.54" + "@babel/helper-plugin-utils" "7.0.0-beta.54" + "@babel/plugin-transform-shorthand-properties@7.0.0-beta.54": version "7.0.0-beta.54" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0-beta.54.tgz#50e73c2afc5898b1055510ddf60ee13a6301517f"