diff --git a/change/@office-iss-react-native-win32-2020-02-10-23-09-16-platform-constants.json b/change/@office-iss-react-native-win32-2020-02-10-23-09-16-platform-constants.json new file mode 100644 index 0000000000..ab929b8816 --- /dev/null +++ b/change/@office-iss-react-native-win32-2020-02-10-23-09-16-platform-constants.json @@ -0,0 +1,9 @@ +{ + "type": "prerelease", + "comment": "Provide a Minimal PlatformConstants Implementation", + "packageName": "@office-iss/react-native-win32", + "email": "ngerlem@microsoft.com", + "commit": "cae1620822a386c4a52fb7351e922485d4f81ac1", + "dependentChangeType": "patch", + "date": "2020-02-11T07:09:14.058Z" +} \ No newline at end of file diff --git a/change/react-native-windows-2020-02-10-23-09-16-platform-constants.json b/change/react-native-windows-2020-02-10-23-09-16-platform-constants.json new file mode 100644 index 0000000000..5d36445513 --- /dev/null +++ b/change/react-native-windows-2020-02-10-23-09-16-platform-constants.json @@ -0,0 +1,9 @@ +{ + "type": "prerelease", + "comment": "Provide a Minimal PlatformConstants Implementation", + "packageName": "react-native-windows", + "email": "ngerlem@microsoft.com", + "commit": "cae1620822a386c4a52fb7351e922485d4f81ac1", + "dependentChangeType": "patch", + "date": "2020-02-11T07:09:16.192Z" +} \ No newline at end of file diff --git a/packages/react-native-win32/src/Libraries/Utilities/NativePlatformConstantsWin.js b/packages/react-native-win32/src/Libraries/Utilities/NativePlatformConstantsWin.js new file mode 100644 index 0000000000..fcaac84584 --- /dev/null +++ b/packages/react-native-win32/src/Libraries/Utilities/NativePlatformConstantsWin.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + * @format + * @flow + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + |}; +} + +export default (TurboModuleRegistry.getEnforcing( + 'PlatformConstants', +): Spec); diff --git a/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js b/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js index 055da8c72f..c5237c55c5 100644 --- a/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js +++ b/packages/react-native-win32/src/Libraries/Utilities/Platform.win32.js @@ -8,23 +8,41 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativePlatformConstantsWin from './NativePlatformConstantsWin'; + +export type PlatformSelectSpec = { + default?: D, + win32?: I, +}; const Platform = { + __constants: null, OS: 'win32', - get Version() { - const constants = NativeModules.PlatformConstants; - return constants && constants.Version; + get constants(): {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + |} { + if (this.__constants == null) { + this.__constants = NativePlatformConstantsWin.getConstants(); + } + return this.__constants; }, get isTesting(): boolean { - const constants = NativeModules.PlatformConstants; - return constants && constants.isTesting; + if (__DEV__) { + return this.constants.isTesting; + } + return false; }, - select: (obj: Object) => ('win32' in obj ? obj.win32 : obj.default), get isTV() { - const constants = NativeModules.PlatformConstants; - return constants ? constants.interfaceIdiom === 'tv' : false; + return false; }, + select: (spec: PlatformSelectSpec): D | I => + 'win32' in spec ? spec.win32 : spec.default, }; module.exports = Platform; diff --git a/packages/react-native-win32/src/Libraries/core/ReactNativeVersionCheck.win32.js b/packages/react-native-win32/src/Libraries/core/ReactNativeVersionCheck.win32.js index d336163787..3673313e70 100644 --- a/packages/react-native-win32/src/Libraries/core/ReactNativeVersionCheck.win32.js +++ b/packages/react-native-win32/src/Libraries/core/ReactNativeVersionCheck.win32.js @@ -23,7 +23,7 @@ const ReactNativeVersion = require('./ReactNativeVersion'); */ exports.checkVersions = function checkVersions(): void { // [Windows - // $FlowFixMe constants doesn't exist yet + // This can be removed once devmain adopts 0.61 if (!Platform.constants) { return; } diff --git a/vnext/.flowconfig b/vnext/.flowconfig index c7e5a313f0..cae67e9402 100644 --- a/vnext/.flowconfig +++ b/vnext/.flowconfig @@ -13,7 +13,6 @@ /Libraries/AppTheme/AppTheme.js /Libraries/Color/normalizeColor.js /Libraries/Core/setUpDeveloperTools.js -/Libraries/Core/ReactNativeVersionCheck.js /Libraries/Components/ActivityIndicator/RCTActivityIndicatorViewNativeComponent.js /Libraries/Components/Button.js /Libraries/Components/DatePicker/DatePicker.js diff --git a/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp b/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp index 3695fb1418..a1b904e23e 100644 --- a/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp +++ b/vnext/Desktop.IntegrationTests/DesktopTestRunner.cpp @@ -7,8 +7,8 @@ #include #include #include +#include #include -#include #include "ChakraRuntimeHolder.h" #include "DesktopTestInstance.h" #include "TestMessageQueueThread.h" diff --git a/vnext/Desktop.IntegrationTests/WebSocketModuleIntegrationTest.cpp b/vnext/Desktop.IntegrationTests/WebSocketModuleIntegrationTest.cpp index 8601820fb4..16923d8225 100644 --- a/vnext/Desktop.IntegrationTests/WebSocketModuleIntegrationTest.cpp +++ b/vnext/Desktop.IntegrationTests/WebSocketModuleIntegrationTest.cpp @@ -3,7 +3,7 @@ #include -#include +#include using namespace facebook::react; using namespace folly; diff --git a/vnext/Desktop.UnitTests/WebSocketModuleTest.cpp b/vnext/Desktop.UnitTests/WebSocketModuleTest.cpp index ea8c521551..cced3d4ab5 100644 --- a/vnext/Desktop.UnitTests/WebSocketModuleTest.cpp +++ b/vnext/Desktop.UnitTests/WebSocketModuleTest.cpp @@ -2,7 +2,7 @@ // Licensed under the MIT License. #include -#include +#include using namespace facebook::react; using namespace facebook::xplat::module; diff --git a/vnext/Desktop/Modules/WebSocketModule.cpp b/vnext/Desktop/Modules/WebSocketModule.cpp index 134b3c1067..63696e1245 100644 --- a/vnext/Desktop/Modules/WebSocketModule.cpp +++ b/vnext/Desktop/Modules/WebSocketModule.cpp @@ -3,7 +3,7 @@ #include "pch.h" -#include +#include #include #include diff --git a/vnext/Desktop/React.Windows.Desktop.vcxproj b/vnext/Desktop/React.Windows.Desktop.vcxproj index e597d3bbdf..df9052a76d 100644 --- a/vnext/Desktop/React.Windows.Desktop.vcxproj +++ b/vnext/Desktop/React.Windows.Desktop.vcxproj @@ -93,9 +93,9 @@ + - diff --git a/vnext/ReactWindowsCore/Modules/PlatformConstantsModule.cpp b/vnext/ReactWindowsCore/Modules/PlatformConstantsModule.cpp new file mode 100644 index 0000000000..30706618d0 --- /dev/null +++ b/vnext/ReactWindowsCore/Modules/PlatformConstantsModule.cpp @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#include "PlatformConstantsModule.h" +#include + +using Method = facebook::xplat::module::CxxModule::Method; + +namespace facebook::react { + +const char *PlatformConstantsModule::Name = "PlatformConstants"; + +std::string PlatformConstantsModule::getName() { + return PlatformConstantsModule::Name; +} + +std::vector PlatformConstantsModule::getMethods() { + return {}; +} + +std::map PlatformConstantsModule::getConstants() { + return { + // We don't currently treat Native code differently in a test environment + {"isTesting", false}, + + // Since we're out-of-tree, we don't know the exact version of React Native + // we're paired with. Provide something sane for now, and try to provide a + // better source of truth later. Tracked by Issue #4073 + {"reactNativeVersion", folly::dynamic::object("major", 0)("minor", 61)("patch", 0)} + + // We don't provide the typical OS version here. Windows make it hard to + // get an exact version by-design. In the future we should consider + // exposing something here like a facility to check Universal API + // Contract. + }; +} + +} // namespace facebook::react diff --git a/vnext/ReactWindowsCore/Modules/PlatformConstantsModule.h b/vnext/ReactWindowsCore/Modules/PlatformConstantsModule.h new file mode 100644 index 0000000000..5bfcabedc2 --- /dev/null +++ b/vnext/ReactWindowsCore/Modules/PlatformConstantsModule.h @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once + +#include + +namespace facebook::react { + +class PlatformConstantsModule : public facebook::xplat::module::CxxModule { + public: + static const char *Name; + + std::string getName() override; + std::map getConstants() override; + std::vector getMethods() override; +}; + +} // namespace facebook::react diff --git a/vnext/ReactWindowsCore/Modules/SourceCodeModule.cpp b/vnext/ReactWindowsCore/Modules/SourceCodeModule.cpp index a59184e56d..b55dc42bb9 100644 --- a/vnext/ReactWindowsCore/Modules/SourceCodeModule.cpp +++ b/vnext/ReactWindowsCore/Modules/SourceCodeModule.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include +#include "SourceCodeModule.h" using namespace folly; using namespace facebook::xplat; @@ -9,12 +9,12 @@ using namespace facebook::xplat; namespace facebook { namespace react { -const char *SourceCodeModule::name = "SourceCode"; +const char *SourceCodeModule::Name = "SourceCode"; SourceCodeModule::SourceCodeModule(const std::string &bundleUrl) : m_bundleUrl(bundleUrl) {} std::string SourceCodeModule::getName() { - return name; + return Name; } auto SourceCodeModule::getConstants() -> std::map { diff --git a/vnext/include/ReactWindowsCore/SourceCodeModule.h b/vnext/ReactWindowsCore/Modules/SourceCodeModule.h similarity index 96% rename from vnext/include/ReactWindowsCore/SourceCodeModule.h rename to vnext/ReactWindowsCore/Modules/SourceCodeModule.h index 16747eae2c..29228033f2 100644 --- a/vnext/include/ReactWindowsCore/SourceCodeModule.h +++ b/vnext/ReactWindowsCore/Modules/SourceCodeModule.h @@ -20,7 +20,7 @@ class SourceCodeModule : public facebook::xplat::module::CxxModule { virtual auto getConstants() -> std::map; virtual auto getMethods() -> std::vector; - static const char *name; + static const char *Name; private: std::string m_bundleUrl; diff --git a/vnext/ReactWindowsCore/WebSocketModule.h b/vnext/ReactWindowsCore/Modules/WebSocketModule.h similarity index 100% rename from vnext/ReactWindowsCore/WebSocketModule.h rename to vnext/ReactWindowsCore/Modules/WebSocketModule.h diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj index d94f2172ce..a95a17fc43 100644 --- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj +++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj @@ -127,7 +127,10 @@ + + + @@ -139,7 +142,6 @@ - @@ -158,6 +160,7 @@ + diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters index cafca865e8..a51a4920c6 100644 --- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters +++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters @@ -72,6 +72,9 @@ Source Files\Modules + + Source Files\Modules + Source Files\Modules @@ -191,9 +194,15 @@ Header Files\Modules + + Header Files\Modules + Header Files\Modules + + Header Files\Modules + Header Files @@ -227,9 +236,7 @@ Header Files - - Header Files - + diff --git a/vnext/Shared/OInstance.cpp b/vnext/Shared/OInstance.cpp index 99e03627f8..d146d24e16 100644 --- a/vnext/Shared/OInstance.cpp +++ b/vnext/Shared/OInstance.cpp @@ -27,10 +27,11 @@ #include #if (defined(_MSC_VER) && !defined(WINRT)) -#include +#include #endif #include -#include +#include +#include #if (defined(_MSC_VER) && (defined(WINRT))) #include @@ -738,7 +739,7 @@ std::vector> InstanceImpl::GetDefaultNativeModules : std::string(); modules.push_back(std::make_unique( m_innerInstance, - facebook::react::SourceCodeModule::name, + facebook::react::SourceCodeModule::Name, [bundleUrl]() -> std::unique_ptr { return std::make_unique(bundleUrl); }, @@ -747,12 +748,17 @@ std::vector> InstanceImpl::GetDefaultNativeModules modules.push_back(std::make_unique( m_innerInstance, "ExceptionsManager", - [&]() -> std::unique_ptr { - return std::make_unique( - std::move(m_devSettings->jsExceptionCallback)); + [callback{std::move(m_devSettings->jsExceptionCallback)}]() mutable { + return std::make_unique(std::move(callback)); }, nativeQueue)); + modules.push_back(std::make_unique( + m_innerInstance, + PlatformConstantsModule::Name, + []() { return std::make_unique(); }, + nativeQueue)); + return modules; } diff --git a/vnext/src/Libraries/Utilities/NativePlatformConstantsWin.js b/vnext/src/Libraries/Utilities/NativePlatformConstantsWin.js new file mode 100644 index 0000000000..523a4f10f0 --- /dev/null +++ b/vnext/src/Libraries/Utilities/NativePlatformConstantsWin.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + * @format + * @flow + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule { + +getConstants: () => {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + |}; +} + +export default (TurboModuleRegistry.getEnforcing( + 'PlatformConstants', +): Spec); diff --git a/vnext/src/Libraries/Utilities/Platform.windesktop.js b/vnext/src/Libraries/Utilities/Platform.windesktop.js index 77a3bdbb2c..0dc6066927 100644 --- a/vnext/src/Libraries/Utilities/Platform.windesktop.js +++ b/vnext/src/Libraries/Utilities/Platform.windesktop.js @@ -1,24 +1,48 @@ /** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. + * * @format + * @flow */ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativePlatformConstantsWin from './NativePlatformConstantsWin'; + +export type PlatformSelectSpec = { + default?: D, + windesktop?: I, +}; const Platform = { + __constants: null, OS: 'windesktop', - get Version() { - const constants = NativeModules.PlatformConstants; - return constants && constants.Version; + get constants(): {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + |} { + if (this.__constants == null) { + this.__constants = NativePlatformConstantsWin.getConstants(); + } + return this.__constants; }, get isTesting(): boolean { - const constants = NativeModules.PlatformConstants; - return constants && constants.isTesting; + if (__DEV__) { + return this.constants.isTesting; + } + return false; }, - select: (obj: Object) => ('windesktop' in obj ? obj.windesktop : obj.default), + get isTV() { + return false; + }, + select: (spec: PlatformSelectSpec): D | I => + 'windesktop' in spec ? spec.windesktop : spec.default, }; module.exports = Platform; diff --git a/vnext/src/Libraries/Utilities/Platform.windows.js b/vnext/src/Libraries/Utilities/Platform.windows.js index 5dcb1bfad8..be6dd3a3dd 100644 --- a/vnext/src/Libraries/Utilities/Platform.windows.js +++ b/vnext/src/Libraries/Utilities/Platform.windows.js @@ -8,23 +8,41 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativePlatformConstantsWin from './NativePlatformConstantsWin'; + +export type PlatformSelectSpec = { + default?: D, + windows?: I, +}; const Platform = { + __constants: null, OS: 'windows', - get Version() { - const constants = NativeModules.PlatformConstants; - return constants && constants.Version; + get constants(): {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + |} { + if (this.__constants == null) { + this.__constants = NativePlatformConstantsWin.getConstants(); + } + return this.__constants; }, get isTesting(): boolean { - const constants = NativeModules.PlatformConstants; - return constants && constants.isTesting; + if (__DEV__) { + return this.constants.isTesting; + } + return false; }, - select: (obj: Object) => ('windows' in obj ? obj.windows : obj.default), get isTV() { - const constants = NativeModules.PlatformConstants; - return constants ? constants.interfaceIdiom === 'tv' : false; + return false; }, + select: (spec: PlatformSelectSpec): D | I => + 'windows' in spec ? spec.windows : spec.default, }; module.exports = Platform; diff --git a/vnext/src/Libraries/core/ReactNativeVersionCheck.windesktop.js b/vnext/src/Libraries/core/ReactNativeVersionCheck.windesktop.js deleted file mode 100644 index 3f566e2c84..0000000000 --- a/vnext/src/Libraries/core/ReactNativeVersionCheck.windesktop.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ -'use strict'; - -exports.checkVersions = function checkVersions(): void { - return; -}; diff --git a/vnext/src/Libraries/core/ReactNativeVersionCheck.windows.js b/vnext/src/Libraries/core/ReactNativeVersionCheck.windows.js deleted file mode 100644 index 310b19e24e..0000000000 --- a/vnext/src/Libraries/core/ReactNativeVersionCheck.windows.js +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ -'use strict'; - -import Platform from '../Utilities/Platform'; -const ReactNativeVersion = require('./ReactNativeVersion'); - -/** - * Checks that the version of this React Native JS is compatible with the native - * code, throwing an error if it isn't. - * - * The existence of this module is part of the public interface of React Native - * even though it is used only internally within React Native. React Native - * implementations for other platforms (ex: Windows) may override this module - * and rely on its existence as a separate module. - */ -exports.checkVersions = function checkVersions(): void { - // [Windows - // $FlowFixMe Platform.contstants doesn't exist yet - if (!Platform.constants) { - return; - } - // Windows] - - const nativeVersion = Platform.constants.reactNativeVersion; - if ( - ReactNativeVersion.version.major !== nativeVersion.major || - ReactNativeVersion.version.minor !== nativeVersion.minor - ) { - console.error( - `React Native version mismatch.\n\nJavaScript version: ${_formatVersion( - ReactNativeVersion.version, - )}\n` + - `Native version: ${_formatVersion(nativeVersion)}\n\n` + - 'Make sure that you have rebuilt the native code. If the problem ' + - 'persists try clearing the Watchman and packager caches with ' + - '`watchman watch-del-all && react-native start --reset-cache`.', - ); - } -}; - -function _formatVersion(version): string { - return ( - `${version.major}.${version.minor}.${version.patch}` + - // eslint-disable-next-line eqeqeq - (version.prerelease != undefined ? `-${version.prerelease}` : '') - ); -}