diff --git a/.ado/jobs/cli-init-windows.yml b/.ado/jobs/cli-init-windows.yml
index 35e9736c8bb..cacf9e74b01 100644
--- a/.ado/jobs/cli-init-windows.yml
+++ b/.ado/jobs/cli-init-windows.yml
@@ -22,6 +22,16 @@ parameters:
configuration: Debug
platform: x86
additionalRunArguments: --no-autolink
+ - Name: FabricLibX64Release
+ template: cpp-lib
+ configuration: Release
+ platform: x64
+ additionalRunArguments:
+ - Name: FabricLibX86Debug
+ template: cpp-lib
+ configuration: Debug
+ platform: x86
+ additionalRunArguments:
- BuildEnvironment: Continuous
Matrix:
- Name: FabricX64Debug
@@ -44,6 +54,26 @@ parameters:
configuration: Release
platform: x86
additionalRunArguments: --no-autolink
+ - Name: FabricLibX64Debug
+ template: cpp-lib
+ configuration: Debug
+ platform: x64
+ additionalRunArguments:
+ - Name: FabricLibX64Release
+ template: cpp-lib
+ configuration: ReleaseLib
+ platform: x64
+ additionalRunArguments:
+ - Name: FabricLibX86Debug
+ template: cpp-lib
+ configuration: Debug
+ platform: x86
+ additionalRunArguments:
+ - Name: FabricLibX86Release
+ template: cpp-lib
+ configuration: Release
+ platform: x86
+ additionalRunArguments:
jobs:
- ${{ each config in parameters.buildMatrix }}:
- ${{ if eq(config.BuildEnvironment, parameters.buildEnvironment) }}:
diff --git a/.ado/templates/react-native-init-windows.yml b/.ado/templates/react-native-init-windows.yml
index 7d977a95082..f48cea9335f 100644
--- a/.ado/templates/react-native-init-windows.yml
+++ b/.ado/templates/react-native-init-windows.yml
@@ -40,49 +40,70 @@ steps:
- ${{ if endsWith(parameters.template, '-app') }}:
- script: |
npx --yes react-native@$(reactNativeDevDependency) init testcli --template react-native@$(reactNativeDevDependency)
- displayName: Init new app project
+ displayName: Init new app project with react-native init
workingDirectory: $(Agent.BuildDirectory)
- ${{ if endsWith(parameters.template, '-lib') }}:
- script: |
- npx --yes create-react-native-module@0.20.2 --package-name "testcli" testcli
- displayName: Init new lib project
+ npx --yes create-react-native-library@latest --slug testcli --description testcli --author-name "React-Native-Windows Bot" --author-email 53619745+rnbot@users.noreply.github.com --author-url http://example.com --repo-url http://example.com --languages java-objc --type module-new --react-native-version $(reactNativeDevDependency) testcli
+ displayName: Init new lib project with create-react-native-library
workingDirectory: $(Agent.BuildDirectory)
- - script: |
- rmdir /s /q android
- displayName: Remove broken android folder # See issue https://github.com/microsoft/react-native-windows/issues/12209
- workingDirectory: $(Agent.BuildDirectory)\testcli
-
- script: |
call yarn install
- call yarn upgrade react@$(reactDevDependency) --dev
- call yarn upgrade react-native@$(reactNativeDevDependency) --dev
- displayName: Update project react and react-native dev versions
- workingDirectory: $(Agent.BuildDirectory)\testcli
-
- - script: |
- call yarn add react-native-windows@$(npmVersion)
- displayName: yarn add react-native-windows@$(npmVersion)
+ displayName: yarn install
workingDirectory: $(Agent.BuildDirectory)\testcli
env:
- npm_config_registry: http://localhost:4873
+ YARN_ENABLE_IMMUTABLE_INSTALLS: false
+
+ - ${{ if endsWith(parameters.template, '-app') }}:
+ - script: |
+ call yarn upgrade react@$(reactDevDependency) --dev
+ call yarn upgrade react-native@$(reactNativeDevDependency) --dev
+ displayName: Update project react and react-native dev versions
+ workingDirectory: $(Agent.BuildDirectory)\testcli
+
+ - script: |
+ call yarn add react-native-windows@$(npmVersion)
+ displayName: yarn add react-native-windows@$(npmVersion)
+ workingDirectory: $(Agent.BuildDirectory)\testcli
+ env:
+ npm_config_registry: http://localhost:4873
+
+ - ${{ if endsWith(parameters.template, '-lib') }}:
+ - script: |
+ call yarn config set npmRegistryServer http://localhost:4873
+ call yarn config set unsafeHttpWhitelist --json "[\"localhost\"]"
+ call yarn add react-native-windows@$(npmVersion) --dev
+ call yarn add react-native-windows@* --peer
+ displayName: yarn add react-native-windows@$(npmVersion)
+ workingDirectory: $(Agent.BuildDirectory)\testcli
+ env:
+ YARN_ENABLE_IMMUTABLE_INSTALLS: false
- script: |
call yarn react-native init-windows --template ${{ parameters.template }} --overwrite --logging ${{ parameters.additionalInitArguments }}
displayName: Call react-native init-windows
workingDirectory: $(Agent.BuildDirectory)\testcli
- env:
- npm_config_registry: http://localhost:4873
- - ${{ if endsWith(parameters.template, '-app') }}:
- - powershell: |
- $path = (Get-ChildItem -Filter "Package.appxmanifest" -File -Recurse).FullName;
- [xml] $manifest = Get-Content $path
- $manifest.Package.Identity.Name = 'ReactNative.InitTest'
- $manifest.Save("$path")
- displayName: Set AppX package name to "ReactNative.InitTest"
+ - ${{ if endsWith(parameters.template, '-lib') }}:
+ - script: |
+ call yarn install
+ displayName: yarn install again
+ workingDirectory: $(Agent.BuildDirectory)\testcli
+ env:
+ YARN_ENABLE_IMMUTABLE_INSTALLS: false
+
+ - powershell: |
+ $path = (Get-ChildItem -Filter "Package.appxmanifest" -File -Recurse).FullName;
+ [xml] $manifest = Get-Content $path
+ $manifest.Package.Identity.Name = 'ReactNative.InitTest'
+ $manifest.Save("$path")
+ displayName: Set AppX package name to "ReactNative.InitTest"
+ ${{ if endsWith(parameters.template, '-app') }}:
workingDirectory: $(Agent.BuildDirectory)\testcli\windows
+ ${{ if endsWith(parameters.template, '-lib') }}:
+ workingDirectory: $(Agent.BuildDirectory)\testcli\example\windows
# End npm test server
- template: verdaccio-stop.yml
@@ -95,7 +116,10 @@ steps:
- template: react-native-debug-info.yml
parameters:
- workingDirectory: $(Agent.BuildDirectory)\testcli
+ ${{ if endsWith(parameters.template, '-app') }}:
+ workingDirectory: $(Agent.BuildDirectory)\testcli
+ ${{ if endsWith(parameters.template, '-lib') }}:
+ workingDirectory: $(Agent.BuildDirectory)\testcli\example
- template: ../templates/run-windows-with-certificates.yml
parameters:
@@ -105,7 +129,10 @@ steps:
buildPlatform: ${{ parameters.platform }}
deployOption: ${{ parameters.additionalRunArguments }}
buildLogDirectory: $(Build.BinariesDirectory)\${{ parameters.platform }}\${{ parameters.configuration }}\BuildLogs
- workingDirectory: $(Agent.BuildDirectory)\testcli
+ ${{ if endsWith(parameters.template, '-app') }}:
+ workingDirectory: $(Agent.BuildDirectory)\testcli
+ ${{ if endsWith(parameters.template, '-lib') }}:
+ workingDirectory: $(Agent.BuildDirectory)\testcli\example
restoreLockedMode: false # Allow new lockfile to be created
- template: upload-build-logs.yml
diff --git a/change/react-native-windows-f2a1a001-7c49-48af-8a21-a5947fbec507.json b/change/react-native-windows-f2a1a001-7c49-48af-8a21-a5947fbec507.json
new file mode 100644
index 00000000000..b15137fc642
--- /dev/null
+++ b/change/react-native-windows-f2a1a001-7c49-48af-8a21-a5947fbec507.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Create new arch module template: cpp-lib",
+ "packageName": "react-native-windows",
+ "email": "jthysell@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.Common.props b/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.Common.props
index db2f915b039..3cf960cbc93 100644
--- a/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.Common.props
+++ b/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.Common.props
@@ -16,5 +16,13 @@
true
+
+
+
+
+
+ true
+
+
diff --git a/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.props b/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.props
new file mode 100644
index 00000000000..f9f20164222
--- /dev/null
+++ b/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.props
@@ -0,0 +1,24 @@
+
+
+
+
+
+ true
+ false
+
+
+
+
+
+
+
diff --git a/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.targets b/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.targets
new file mode 100644
index 00000000000..aa824160f5f
--- /dev/null
+++ b/vnext/PropertySheets/External/Microsoft.ReactNative.Composition.CppLib.targets
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vnext/templates/cpp-app/metro.config.js b/vnext/templates/cpp-app/metro.config.js
index f5e6fd068c8..686d4a9eda7 100644
--- a/vnext/templates/cpp-app/metro.config.js
+++ b/vnext/templates/cpp-app/metro.config.js
@@ -48,8 +48,6 @@ const config = {
inlineRequires: true,
},
}),
- // This fixes the 'missing-asset-registry-path` error (see https://github.com/microsoft/react-native-windows/issues/11437)
- assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry',
},
};
diff --git a/vnext/templates/cpp-app/template.config.js b/vnext/templates/cpp-app/template.config.js
index 4627b7c6488..2bf5cb78f35 100644
--- a/vnext/templates/cpp-app/template.config.js
+++ b/vnext/templates/cpp-app/template.config.js
@@ -20,12 +20,7 @@ const templateUtils = require('../templateUtils');
async function preInstall(config = {}, options = {}) {}
async function getFileMappings(config = {}, options = {}) {
- const rnwPath = path.dirname(
- require.resolve('react-native-windows', [config.root]),
- );
- const rnwVersion = require(path.join(rnwPath, 'package.json')).version;
-
- const devMode = existsSync(path.join(rnwPath, 'src'));
+ const {rnwVersion, devMode} = templateUtils.getRnwInfo(config, options);
const projectName =
config?.project?.windows?.project?.projectName ?? options?.name ?? 'MyApp';
@@ -38,6 +33,10 @@ async function getFileMappings(config = {}, options = {}) {
const packageGuid = uuid.v4();
const currentUser = username.sync(); // Gets the current username depending on the platform.
+ const appJsonPath = path.join(config?.root ?? process.cwd(), 'app.json');
+ const mainComponentName =
+ (existsSync(appJsonPath) ? require(appJsonPath).name : null) ?? projectName;
+
const cppNugetPackages = [];
const replacements = {
@@ -50,7 +49,7 @@ async function getFileMappings(config = {}, options = {}) {
rnwVersion: rnwVersion,
- mainComponentName: projectName, // TODO: replace with app.json name
+ mainComponentName,
// Visual Studio is very picky about the casing of the guids for projects, project references and the solution
// https://www.bing.com/search?q=visual+studio+project+guid+casing&cvid=311a5ad7f9fc41089507b24600d23ee7&FORM=ANAB01&PC=U531
@@ -61,7 +60,7 @@ async function getFileMappings(config = {}, options = {}) {
// packaging and signing variables:
packageGuidLower: `{${packageGuid.toLowerCase()}}`,
packageGuidUpper: `{${packageGuid.toUpperCase()}}`,
- currentUser: currentUser,
+ currentUser,
devMode,
diff --git a/vnext/templates/cpp-app/windows/ExperimentalFeatures.props b/vnext/templates/cpp-app/windows/ExperimentalFeatures.props
index 6b4e69eb6c1..be73cb5575a 100644
--- a/vnext/templates/cpp-app/windows/ExperimentalFeatures.props
+++ b/vnext/templates/cpp-app/windows/ExperimentalFeatures.props
@@ -3,7 +3,7 @@
true
- false
+ true
true
diff --git a/vnext/templates/cpp-app/windows/MyApp/AutolinkedNativeModules.g.cpp b/vnext/templates/cpp-app/windows/MyApp/AutolinkedNativeModules.g.cpp
new file mode 100644
index 00000000000..aa6e5db813d
--- /dev/null
+++ b/vnext/templates/cpp-app/windows/MyApp/AutolinkedNativeModules.g.cpp
@@ -0,0 +1,13 @@
+// AutolinkedNativeModules.g.cpp contents generated by "react-native autolink-windows"
+// clang-format off
+#include "pch.h"
+#include "AutolinkedNativeModules.g.h"{{ &autolinkCppIncludes }}
+
+namespace winrt::Microsoft::ReactNative
+{
+
+void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders)
+{ {{ &autolinkCppPackageProviders }}
+}
+
+}
diff --git a/vnext/templates/cpp-app/windows/MyApp/AutolinkedNativeModules.g.h b/vnext/templates/cpp-app/windows/MyApp/AutolinkedNativeModules.g.h
new file mode 100644
index 00000000000..f28bb8be361
--- /dev/null
+++ b/vnext/templates/cpp-app/windows/MyApp/AutolinkedNativeModules.g.h
@@ -0,0 +1,10 @@
+// AutolinkedNativeModules.g.h contents generated by "react-native autolink-windows"
+// clang-format off
+#pragma once
+
+namespace winrt::Microsoft::ReactNative
+{
+
+void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders);
+
+}
diff --git a/vnext/templates/cpp-app/windows/MyApp/MyApp.cpp b/vnext/templates/cpp-app/windows/MyApp/MyApp.cpp
index 6d3f3e7e012..15ac6aba18a 100644
--- a/vnext/templates/cpp-app/windows/MyApp/MyApp.cpp
+++ b/vnext/templates/cpp-app/windows/MyApp/MyApp.cpp
@@ -4,18 +4,10 @@
#include "pch.h"
#include "{{ name }}.h"
-#include
-#include
-
-#include
-#include
+#include "AutolinkedNativeModules.g.h"
#include "NativeModules.h"
-#include "ReactPropertyBag.h"
-
-constexpr size_t MAX_LOADSTRING = 100;
-// Have to use TurboModules to override built in modules.. so the standard attributed package provider doesn't work.
struct CompReactPackageProvider
: winrt::implements {
public: // IReactPackageProvider
@@ -25,229 +17,146 @@ struct CompReactPackageProvider
};
// Global Variables:
-WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
-WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
-
-winrt::Windows::System::DispatcherQueueController g_dispatcherQueueController{nullptr};
-winrt::Windows::UI::Composition::Compositor g_compositor{nullptr};
-
-constexpr auto WindowDataProperty = L"WindowData";
-constexpr PCWSTR c_windowClassName = L"MS_REACTNATIVE_RNTESTER_COMPOSITION";
-constexpr PCWSTR appName = L"{{ mainComponentName }}";
-
-// Forward declarations of functions included in this code module:
-LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
-int RunRNTester(int showCmd);
-
-struct WindowData {
- static HINSTANCE s_instance;
- static constexpr uint16_t defaultDebuggerPort{9229};
-
- bool m_windowInited{false};
- winrt::Microsoft::ReactNative::CompositionHwndHost m_CompositionHwndHost{nullptr};
- winrt::Microsoft::ReactNative::ReactNativeHost m_host{nullptr};
- winrt::Microsoft::ReactNative::ReactInstanceSettings m_instanceSettings{nullptr};
-
-#if BUNDLE
- std::wstring m_bundleFile = L"index.windows";
- bool m_useWebDebugger{false};
- bool m_fastRefreshEnabled{false};
-#else
- std::wstring m_bundleFile = L"index";
- bool m_useWebDebugger{false};
- bool m_fastRefreshEnabled{true};
-#endif
+constexpr PCWSTR windowTitle = L"{{ mainComponentName }}";
+constexpr PCWSTR mainComponentName = L"{{ mainComponentName }}";
- bool m_useDirectDebugger{false};
- bool m_breakOnNextLine{false};
- uint16_t m_debuggerPort{defaultDebuggerPort};
- xaml::ElementTheme m_theme{xaml::ElementTheme::Default};
+HWND global_hwnd;
+winrt::Microsoft::ReactNative::CompositionRootView *global_rootView{nullptr};
- WindowData(const winrt::Microsoft::ReactNative::CompositionHwndHost &compHost) : m_CompositionHwndHost(compHost) {
- winrt::Microsoft::ReactNative::Composition::CompositionUIService::SetCompositionContext(
- InstanceSettings().Properties(),
- winrt::Microsoft::ReactNative::Composition::WindowsCompositionContextHelper::CreateContext(g_compositor));
- }
+float ScaleFactor(HWND hwnd) noexcept {
+ return GetDpiForWindow(hwnd) / static_cast(USER_DEFAULT_SCREEN_DPI);
+}
- static WindowData *GetFromWindow(HWND hwnd) {
- auto data = reinterpret_cast(GetProp(hwnd, WindowDataProperty));
- return data;
- }
+void UpdateRootViewSizeToAppWindow(
+ winrt::Microsoft::ReactNative::CompositionRootView const &rootView,
+ winrt::Microsoft::UI::Windowing::AppWindow const &window) {
+ auto hwnd = winrt::Microsoft::UI::GetWindowFromWindowId(window.Id());
+ auto scaleFactor = ScaleFactor(hwnd);
+ winrt::Windows::Foundation::Size size{
+ window.ClientSize().Width / scaleFactor, window.ClientSize().Height / scaleFactor};
+ rootView.Arrange(size);
+ rootView.Size(size);
+}
- winrt::Microsoft::ReactNative::ReactNativeHost Host() noexcept {
- if (!m_host) {
- m_host = winrt::Microsoft::ReactNative::ReactNativeHost();
- m_host.InstanceSettings(InstanceSettings());
- }
+// Create and configure the ReactNativeHost
+winrt::Microsoft::ReactNative::ReactNativeHost CreateReactNativeHost(
+ HWND hwnd,
+ const winrt::Microsoft::UI::Composition::Compositor &compositor) {
+ WCHAR workingDir[MAX_PATH];
+ GetCurrentDirectory(MAX_PATH, workingDir);
- return m_host;
- }
+ auto host = winrt::Microsoft::ReactNative::ReactNativeHost();
- winrt::Microsoft::ReactNative::ReactInstanceSettings InstanceSettings() noexcept {
- if (!m_instanceSettings) {
- m_instanceSettings = winrt::Microsoft::ReactNative::ReactInstanceSettings();
- }
+ // Include any autolinked modules
+ RegisterAutolinkedNativeModulePackages(host.PackageProviders());
- return m_instanceSettings;
- }
+ host.PackageProviders().Append(winrt::make());
- LRESULT RenderApp(HWND hwnd) {
- WCHAR workingDir[MAX_PATH];
- GetCurrentDirectory(MAX_PATH, workingDir);
-
- auto host = Host();
- // Disable until we have a 3rd party story for custom components
- // RegisterAutolinkedNativeModulePackages(host.PackageProviders()); // Includes any
- // autolinked modules
-
- host.InstanceSettings().JavaScriptBundleFile(m_bundleFile);
-
- host.InstanceSettings().UseWebDebugger(m_useWebDebugger);
- host.InstanceSettings().UseDirectDebugger(m_useDirectDebugger);
- host.InstanceSettings().BundleRootPath(std::wstring(L"file:").append(workingDir).append(L"\\Bundle\\").c_str());
- host.InstanceSettings().DebuggerBreakOnNextLine(m_breakOnNextLine);
- host.InstanceSettings().UseFastRefresh(m_fastRefreshEnabled);
- host.InstanceSettings().DebuggerPort(m_debuggerPort);
- host.InstanceSettings().UseDeveloperSupport(true);
-
- host.PackageProviders().Append(winrt::make());
- winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
- host.InstanceSettings().Properties(), reinterpret_cast(hwnd));
-
- // Nudge the ReactNativeHost to create the instance and wrapping context
- host.ReloadInstance();
-
- winrt::Microsoft::ReactNative::ReactViewOptions viewOptions;
- viewOptions.ComponentName(appName);
- m_CompositionHwndHost.ReactViewHost(
- winrt::Microsoft::ReactNative::ReactCoreInjection::MakeViewHost(host, viewOptions));
-
- auto windowData = WindowData::GetFromWindow(hwnd);
- if (!windowData->m_windowInited) {
- m_CompositionHwndHost.Initialize((uint64_t)(hwnd));
- windowData->m_windowInited = true;
- }
- return 0;
- }
+ host.InstanceSettings().JavaScriptBundleFile(L"index.windows");
+ host.InstanceSettings().DebugBundlePath(L"index");
- LRESULT TranslateMessage(UINT message, WPARAM wparam, LPARAM lparam) noexcept {
- if (m_CompositionHwndHost) {
- return static_cast(m_CompositionHwndHost.TranslateMessage(message, wparam, lparam));
- }
- return 0;
- }
-};
-
-extern "C" IMAGE_DOS_HEADER __ImageBase;
-HINSTANCE WindowData::s_instance = reinterpret_cast(&__ImageBase);
+ host.InstanceSettings().BundleRootPath(std::wstring(L"file:").append(workingDir).append(L"\\Bundle\\").c_str());
+ host.InstanceSettings().DebuggerBreakOnNextLine(false);
+#if _DEBUG
+ host.InstanceSettings().UseDirectDebugger(true);
+ host.InstanceSettings().UseFastRefresh(true);
+#endif
+ host.InstanceSettings().UseDeveloperSupport(true);
-LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
- auto windowData = WindowData::GetFromWindow(hWnd);
- if (windowData) {
- auto result = WindowData::GetFromWindow(hWnd)->TranslateMessage(message, wParam, lParam);
- if (result)
- return result;
- }
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
+ host.InstanceSettings().Properties(), reinterpret_cast(hwnd));
- switch (message) {
- case WM_DESTROY: {
- delete WindowData::GetFromWindow(hWnd);
- SetProp(hWnd, WindowDataProperty, 0);
- PostQuitMessage(0);
- return 0;
- }
- case WM_NCCREATE: {
- auto cs = reinterpret_cast(lParam);
- auto windowData = static_cast(cs->lpCreateParams);
- WINRT_ASSERT(windowData);
- SetProp(hWnd, WindowDataProperty, reinterpret_cast(windowData));
- break;
- }
- case WM_GETOBJECT: {
- {
- auto windowData = WindowData::GetFromWindow(hWnd);
- if (windowData == nullptr || !windowData->m_windowInited)
- break;
-
- auto hwndHost = windowData->m_CompositionHwndHost;
- winrt::com_ptr spReps;
- if (!hwndHost.UiaProvider().try_as(spReps)) {
- break;
- }
- LRESULT lResult = UiaReturnRawElementProvider(hWnd, wParam, lParam, spReps.get());
- return lResult;
- }
- }
- }
+ // By using the MicrosoftCompositionContextHelper here, React Native Windows will use Lifted Visuals for its
+ // tree.
+ winrt::Microsoft::ReactNative::Composition::CompositionUIService::SetCompositionContext(
+ host.InstanceSettings().Properties(),
+ winrt::Microsoft::ReactNative::Composition::MicrosoftCompositionContextHelper::CreateContext(compositor));
- return DefWindowProc(hWnd, message, wParam, lParam);
-}
-
-int RunRNTester(int showCmd) {
- auto windowData = std::make_unique(winrt::Microsoft::ReactNative::CompositionHwndHost());
- HWND hwnd = CreateWindow(
- c_windowClassName,
- appName,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- nullptr,
- nullptr,
- WindowData::s_instance,
- windowData.get());
-
- WINRT_VERIFY(hwnd);
-
- windowData.release();
-
- ShowWindow(hwnd, showCmd);
- UpdateWindow(hwnd);
- SetFocus(hwnd);
- WindowData::GetFromWindow(hwnd)->RenderApp(hwnd);
-
- HACCEL hAccelTable = LoadAccelerators(WindowData::s_instance, MAKEINTRESOURCE(IDC_RNTESTER_COMPOSITION));
-
- MSG msg = {};
- while (GetMessage(&msg, nullptr, 0, 0)) {
- if (!TranslateAccelerator(hwnd, hAccelTable, &msg)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- }
- return static_cast(msg.wParam);
+ return host;
}
_Use_decl_annotations_ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE, PSTR /* commandLine */, int showCmd) {
- WNDCLASSEXW wcex = {};
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.style = CS_HREDRAW | CS_VREDRAW;
- wcex.lpfnWndProc = &WndProc;
- wcex.cbClsExtra = DLGWINDOWEXTRA;
- wcex.cbWndExtra = sizeof(WindowData *);
- wcex.hInstance = WindowData::s_instance;
- wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
- wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_RNTESTER_COMPOSITION);
- wcex.lpszClassName = c_windowClassName;
- wcex.hIcon = LoadIconW(instance, MAKEINTRESOURCEW(IDI_ICON1));
- ATOM classId = RegisterClassEx(&wcex);
- WINRT_VERIFY(classId);
- winrt::check_win32(!classId);
-
- DispatcherQueueOptions options{
- sizeof(DispatcherQueueOptions), /* dwSize */
- DQTYPE_THREAD_CURRENT, /* threadType */
- DQTAT_COM_ASTA /* apartmentType */
- };
-
- // Need to have a Dispatcher on the current thread to be able to create a Compositor
- winrt::check_hresult(CreateDispatcherQueueController(
- options,
- reinterpret_cast(
- winrt::put_abi(g_dispatcherQueueController))));
-
- g_compositor = winrt::Windows::UI::Composition::Compositor();
- return RunRNTester(showCmd);
-}
+ // Initialize WinRT.
+ winrt::init_apartment(winrt::apartment_type::single_threaded);
+
+ // Enable per monitor DPI scaling
+ SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
+
+ // Create a DispatcherQueue for this thread. This is needed for Composition, Content, and
+ // Input APIs.
+ auto dispatcherQueueController{winrt::Microsoft::UI::Dispatching::DispatcherQueueController::CreateOnCurrentThread()};
+
+ // Create a Compositor for all Content on this thread.
+ auto compositor{winrt::Microsoft::UI::Composition::Compositor()};
+
+ // Create a top-level window.
+ auto window = winrt::Microsoft::UI::Windowing::AppWindow::Create();
+ window.Title(windowTitle);
+ window.Resize({1000, 1000});
+ window.Show();
+ auto hwnd = winrt::Microsoft::UI::GetWindowFromWindowId(window.Id());
+ global_hwnd = hwnd;
+ auto scaleFactor = ScaleFactor(hwnd);
+
+ auto host = CreateReactNativeHost(hwnd, compositor);
+
+ // Start the react-native instance, which will create a JavaScript runtime and load the applications bundle
+ host.ReloadInstance();
+
+ // Create a RootView which will present a react-native component
+ winrt::Microsoft::ReactNative::ReactViewOptions viewOptions;
+ viewOptions.ComponentName(mainComponentName);
+ auto rootView = winrt::Microsoft::ReactNative::CompositionRootView(compositor);
+ rootView.ReactViewHost(winrt::Microsoft::ReactNative::ReactCoreInjection::MakeViewHost(host, viewOptions));
+
+ // Update the size of the RootView when the AppWindow changes size
+ window.Changed([wkRootView = winrt::make_weak(rootView)](
+ winrt::Microsoft::UI::Windowing::AppWindow const &window,
+ winrt::Microsoft::UI::Windowing::AppWindowChangedEventArgs const &args) {
+ if (args.DidSizeChange() || args.DidVisibilityChange()) {
+ if (auto rootView = wkRootView.get()) {
+ UpdateRootViewSizeToAppWindow(rootView, window);
+ }
+ }
+ });
+
+ // Quit application when main window is closed
+ window.Destroying(
+ [host](winrt::Microsoft::UI::Windowing::AppWindow const &window, winrt::IInspectable const & /*args*/) {
+ // Before we shutdown the application - unload the ReactNativeHost to give the javascript a chance to save any
+ // state
+ auto async = host.UnloadInstance();
+ async.Completed([host](auto asyncInfo, winrt::Windows::Foundation::AsyncStatus asyncStatus) {
+ assert(asyncStatus == winrt::Windows::Foundation::AsyncStatus::Completed);
+ host.InstanceSettings().UIDispatcher().Post([]() { PostQuitMessage(0); });
+ });
+ });
+
+ // DesktopChildSiteBridge create a ContentSite that can host the RootView ContentIsland
+ auto bridge = winrt::Microsoft::UI::Content::DesktopChildSiteBridge::Create(compositor, window.Id());
+ bridge.Connect(rootView.Island());
+ bridge.ResizePolicy(winrt::Microsoft::UI::Content::ContentSizePolicy::ResizeContentToParentWindow);
+
+ auto invScale = 1.0f / scaleFactor;
+ rootView.RootVisual().Scale({invScale, invScale, invScale});
+ rootView.ScaleFactor(scaleFactor);
+
+ // Set the intialSize of the root view
+ UpdateRootViewSizeToAppWindow(rootView, window);
+
+ bridge.Show();
+
+ // Run the main application event loop
+ dispatcherQueueController.DispatcherQueue().RunEventLoop();
+
+ // Rundown the DispatcherQueue. This drains the queue and raises events to let components
+ // know the message loop has finished.
+ dispatcherQueueController.ShutdownQueue();
+
+ bridge.Close();
+ bridge = nullptr;
+
+ // Destroy all Composition objects
+ compositor.Close();
+ compositor = nullptr;
+}
\ No newline at end of file
diff --git a/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj b/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj
index 1a019b4e4dc..276e3305cd0 100644
--- a/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj
+++ b/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj
@@ -101,11 +101,13 @@
+
+
Create
Create
diff --git a/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj.filters b/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj.filters
index bd8163ead6e..a1d9ae1a198 100644
--- a/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj.filters
+++ b/vnext/templates/cpp-app/windows/MyApp/MyApp.vcxproj.filters
@@ -24,6 +24,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -32,6 +35,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/vnext/templates/cpp-app/windows/MyApp/pch.h b/vnext/templates/cpp-app/windows/MyApp/pch.h
index 8512a671430..77dc1aba971 100644
--- a/vnext/templates/cpp-app/windows/MyApp/pch.h
+++ b/vnext/templates/cpp-app/windows/MyApp/pch.h
@@ -12,17 +12,20 @@
#define WINRT_LEAN_AND_MEAN 1
// Windows Header Files
+#include
#include
-
-#pragma push_macro("GetCurrentTime")
#undef GetCurrentTime
-// Playground pch.h
+// WinRT Header Files
+#include
#include
+#include
#include
-#include
-#include
-#pragma pop_macro("GetCurrentTime")
+#include
+#include
+#include
+#include
+#include
// C RunTime Header Files
#include
@@ -30,6 +33,4 @@
#include
#include
-// reference additional headers your program requires here
-#include
-#include
+// Reference additional headers your project requires here
diff --git a/vnext/templates/cpp-lib/example/metro.config.js b/vnext/templates/cpp-lib/example/metro.config.js
new file mode 100644
index 00000000000..84f46590d09
--- /dev/null
+++ b/vnext/templates/cpp-lib/example/metro.config.js
@@ -0,0 +1,74 @@
+const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
+const fs = require('fs');
+const path = require('path');
+const escape = require('escape-string-regexp');
+const exclusionList = require('metro-config/src/defaults/exclusionList');
+const pak = require('../package.json');
+
+const root = path.resolve(__dirname, '..');
+const modules = Object.keys({ ...pak.peerDependencies });
+
+const rnwPath = fs.realpathSync(
+ path.resolve(require.resolve('react-native-windows/package.json'), '..'),
+);
+
+//{{#devMode}} [devMode
+const rnwRootNodeModules = path.resolve(rnwPath, '..', 'node_modules');
+const rnwPackages = path.resolve(rnwPath, '..', 'packages');
+// devMode]{{/devMode}}
+
+/**
+ * Metro configuration
+ * https://facebook.github.io/metro/docs/configuration
+ *
+ * @type {import('metro-config').MetroConfig}
+ */
+const config = {
+ watchFolders: [root,
+ //{{#devMode}} [devMode
+ rnwPath, rnwRootNodeModules, rnwPackages
+ // devMode]{{/devMode}}
+ ],
+
+ // We need to make sure that only one version is loaded for peerDependencies
+ // So we block them at the root, and alias them to the versions in example's node_modules
+ resolver: {
+ blacklistRE: exclusionList(
+ modules.map(
+ (m) =>
+ new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
+ ).concat([
+ // This stops "react-native run-windows" from causing the metro server to crash if its already running
+ new RegExp(
+ `${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
+ ),
+ // This prevents "react-native run-windows" from hitting: EBUSY: resource busy or locked, open msbuild.ProjectImports.zip or other files produced by msbuild
+ new RegExp(`${rnwPath}/build/.*`),
+ new RegExp(`${rnwPath}/target/.*`),
+ /.*\.ProjectImports\.zip/,
+ ])
+ ),
+
+ extraNodeModules: modules.reduce((acc, name) => {
+ acc[name] = path.join(__dirname, 'node_modules', name);
+ return acc;
+ },
+ {
+ //{{#devMode}} [devMode
+ 'react-native-windows': rnwPath,
+ // devMode]{{/devMode}}
+ }
+ ),
+ },
+
+ transformer: {
+ getTransformOptions: async () => ({
+ transform: {
+ experimentalImportSupport: false,
+ inlineRequires: true,
+ },
+ }),
+ },
+};
+
+module.exports = mergeConfig(getDefaultConfig(__dirname), config);
diff --git a/vnext/templates/cpp-lib/template.config.js b/vnext/templates/cpp-lib/template.config.js
new file mode 100644
index 00000000000..da150434da0
--- /dev/null
+++ b/vnext/templates/cpp-lib/template.config.js
@@ -0,0 +1,235 @@
+/**
+ * Copyright (c) Microsoft Corporation.
+ * Licensed under the MIT License.
+ *
+ * @ts check
+ * @format
+ */
+
+const existsSync = require('fs').existsSync;
+const path = require('path');
+const username = require('username');
+const uuid = require('uuid');
+const util = require('util');
+
+const glob = util.promisify(require('glob'));
+
+const templateUtils = require('../templateUtils');
+
+function resolveArgs(config = {}, options = {}) {
+ const projectRoot = config?.root ?? process.cwd();
+
+ const libConfig = {...config};
+ const libOptions = {...options};
+
+ if (libConfig.project?.windows?.project?.projectFile?.startsWith('Error:')) {
+ libConfig.project.windows =
+ templateUtils.getWindowsDependencyConfig(projectRoot);
+ }
+
+ const exampleProjectPath = path.join(projectRoot, 'example');
+
+ const exExists = existsSync(exampleProjectPath);
+ const exProjectConfig = exExists
+ ? templateUtils.getWindowsProjectConfig(exampleProjectPath)
+ : null;
+ const exOptions = exExists
+ ? {
+ ...options,
+ template: 'cpp-app',
+ name: `${options?.name ?? 'MyLib'}Example`,
+ namespace: `${options?.namespace ?? 'MyLib'}Example`,
+ }
+ : null;
+
+ return {
+ libConfig,
+ libOptions,
+ exExists,
+ exConfig: {
+ root: exampleProjectPath,
+ project: {
+ windows: exProjectConfig,
+ },
+ },
+ exOptions,
+ };
+}
+
+const exampleTemplateConfig = require('../cpp-app/template.config');
+
+async function preInstall(config = {}, options = {}) {
+ const {exExists, exConfig, exOptions} = resolveArgs(config, options);
+
+ if (exExists) {
+ if (exOptions?.logging) {
+ console.log('Running cpp-app template preInstall() for example...');
+ }
+ await exampleTemplateConfig.preInstall(exConfig, exOptions);
+ }
+}
+
+async function getFileMappings(config = {}, options = {}) {
+ const {libConfig, libOptions, exExists, exConfig, exOptions} = resolveArgs(
+ config,
+ options,
+ );
+
+ const {rnwVersion, devMode} = templateUtils.getRnwInfo(libConfig, libOptions);
+
+ const projectName =
+ libConfig?.project?.windows?.projects[0]?.projectName ??
+ libOptions?.name ??
+ 'MyLib';
+ const namespace = libOptions?.namespace ?? projectName;
+ const namespaceCpp = namespace.replace(/\./g, '::');
+ const projectGuid =
+ libConfig?.project?.windows?.projects[0]?.projectGuid
+ ?.replace('{', '')
+ .replace('}', '') ?? uuid.v4();
+ const currentUser = username.sync(); // Gets the current username depending on the platform.
+
+ const cppNugetPackages = [];
+
+ const replacements = {
+ useMustache: true,
+ regExpPatternsToRemove: [],
+
+ name: projectName,
+ pascalName: templateUtils.pascalCase(projectName),
+ namespace: namespace,
+ namespaceCpp: namespaceCpp,
+
+ rnwVersion: rnwVersion,
+
+ // Visual Studio is very picky about the casing of the guids for projects, project references and the solution
+ // https://www.bing.com/search?q=visual+studio+project+guid+casing&cvid=311a5ad7f9fc41089507b24600d23ee7&FORM=ANAB01&PC=U531
+ // we therefore have to precariously use the right casing in the right place or risk building in VS breaking.
+ projectGuidLower: `{${projectGuid.toLowerCase()}}`,
+ projectGuidUpper: `{${projectGuid.toUpperCase()}}`,
+
+ currentUser,
+
+ devMode,
+
+ cppNugetPackages,
+ };
+
+ let fileMappings = [];
+
+ const templateFiles = await glob('**/*', {
+ cwd: __dirname,
+ ignore: 'template.config.js',
+ nodir: true,
+ });
+
+ for (const file of templateFiles) {
+ const fileMapping = {
+ from: path.resolve(__dirname, path.normalize(file)),
+ to: path.normalize(file),
+ replacements,
+ };
+
+ // Don't copy example files if there is no example in the destination
+ if (!exExists && fileMapping.to.startsWith('example')) {
+ continue;
+ }
+
+ // Perform simple file renames
+ const fileName = path.basename(fileMapping.to);
+ switch (fileName) {
+ case '_gitignore':
+ fileMapping.to = path.join(path.dirname(fileMapping.to), '.gitignore');
+ break;
+ case 'NuGet_Config':
+ fileMapping.to = path.join(
+ path.dirname(fileMapping.to),
+ 'NuGet.config',
+ );
+ break;
+ }
+
+ // Rename files with MyLib in the name
+ fileMapping.to = fileMapping.to.replace(/MyLib/g, projectName);
+
+ fileMappings.push(fileMapping);
+ }
+
+ // Add the file mappings from the cpp-app template for the example app
+ if (exExists) {
+ const exampleFileMappings = await exampleTemplateConfig.getFileMappings(
+ exConfig,
+ exOptions,
+ );
+
+ for (const exFileMap of exampleFileMappings) {
+ exFileMap.to = path.join('example', exFileMap.to);
+
+ // Only add the file map if there isn't a mapping from this cpp-lib template
+ if (fileMappings.filter(fm => fm.to === exFileMap.to).length === 0) {
+ fileMappings.push(exFileMap);
+ }
+ }
+ }
+
+ return fileMappings;
+}
+
+async function postInstall(config = {}, options = {}) {
+ const {libConfig, libOptions, exExists, exConfig, exOptions} = resolveArgs(
+ config,
+ options,
+ );
+
+ const projectName =
+ libConfig?.project?.windows?.projects[0]?.projectName ??
+ libOptions?.name ??
+ 'MyLib';
+ const namespace = libOptions?.namespace ?? projectName;
+ const namespaceCpp = namespace.replace(/\./g, '::');
+
+ // Update package.json codegen
+ await templateUtils.updateProjectPackageJson(libConfig, libOptions, {
+ codegenConfig: {
+ windows: {
+ namespace: namespaceCpp + 'Codegen',
+ outputDirectory: `windows/${projectName}/codegen`,
+ separateDataTypes: true,
+ },
+ },
+ });
+
+ if (exExists) {
+ const {rnwVersion} = templateUtils.getRnwInfo(exConfig, exOptions);
+
+ // Update example package.json with new scripts and dependencies
+ await templateUtils.updateProjectPackageJson(exConfig, exOptions, {
+ scripts: {
+ windows: 'react-native run-windows',
+ 'test:windows': 'jest --config jest.config.windows.js',
+ },
+ dependencies: {
+ 'react-native-windows': rnwVersion,
+ },
+ devDependencies: {
+ '@rnx-kit/jest-preset': '^0.1.16',
+ },
+ });
+
+ // Install recently added dependencies
+ await templateUtils.runNpmInstall(libConfig, libOptions);
+
+ console.log(
+ '\nRun the example app on Windows:\n\n > yarn example windows\n',
+ );
+ }
+}
+
+module.exports = {
+ name: 'React Native Windows Turbo Module (New Arch, C++)',
+ description:
+ "[Experimental] A RNW turbo module targeting RN's new architecture.",
+ preInstall,
+ getFileMappings,
+ postInstall,
+};
diff --git a/vnext/templates/cpp-lib/windows/ExperimentalFeatures.props b/vnext/templates/cpp-lib/windows/ExperimentalFeatures.props
new file mode 100644
index 00000000000..be73cb5575a
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/ExperimentalFeatures.props
@@ -0,0 +1,11 @@
+
+
+
+
+ true
+ true
+
+ true
+
+
+
diff --git a/vnext/templates/cpp-lib/windows/MyLib.sln b/vnext/templates/cpp-lib/windows/MyLib.sln
new file mode 100644
index 00000000000..7d36d07392c
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib.sln
@@ -0,0 +1,156 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.3.32929.385
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "{{ name }}", "{{ name }}\{{ name }}.vcxproj", "{{ projectGuidUpper }}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\node_modules\react-native-windows\fmt\fmt.vcxproj", "{14B93DC8-FD93-4A6D-81CB-8BC96644501C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\node_modules\react-native-windows\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}"
+EndProject
+Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Debug|ARM64 = Debug|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ Release|ARM64 = Release|ARM64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {{ projectGuidUpper }}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {{ projectGuidUpper }}.Debug|ARM64.Build.0 = Debug|ARM64
+ {{ projectGuidUpper }}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {{ projectGuidUpper }}.Debug|x64.ActiveCfg = Debug|x64
+ {{ projectGuidUpper }}.Debug|x64.Build.0 = Debug|x64
+ {{ projectGuidUpper }}.Debug|x64.Deploy.0 = Debug|x64
+ {{ projectGuidUpper }}.Debug|x86.ActiveCfg = Debug|Win32
+ {{ projectGuidUpper }}.Debug|x86.Build.0 = Debug|Win32
+ {{ projectGuidUpper }}.Debug|x86.Deploy.0 = Debug|Win32
+ {{ projectGuidUpper }}.Release|ARM64.ActiveCfg = Release|ARM64
+ {{ projectGuidUpper }}.Release|ARM64.Build.0 = Release|ARM64
+ {{ projectGuidUpper }}.Release|ARM64.Deploy.0 = Release|ARM64
+ {{ projectGuidUpper }}.Release|x64.ActiveCfg = Release|x64
+ {{ projectGuidUpper }}.Release|x64.Build.0 = Release|x64
+ {{ projectGuidUpper }}.Release|x64.Deploy.0 = Release|x64
+ {{ projectGuidUpper }}.Release|x86.ActiveCfg = Release|Win32
+ {{ projectGuidUpper }}.Release|x86.Build.0 = Release|Win32
+ {{ projectGuidUpper }}.Release|x86.Deploy.0 = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Deploy.0 = Debug|Win32
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}
+ EndGlobalSection
+EndGlobal
diff --git a/vnext/templates/cpp-lib/windows/MyLib/MyLib.cpp b/vnext/templates/cpp-lib/windows/MyLib/MyLib.cpp
new file mode 100644
index 00000000000..5dd2b28ca5e
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/MyLib.cpp
@@ -0,0 +1,18 @@
+#include "pch.h"
+
+#include "{{ name }}.h"
+
+namespace winrt::{{ namespaceCpp }}
+{
+
+// See https://microsoft.github.io/react-native-windows/docs/native-modules for details on writing native modules
+
+void {{ pascalName }}::Initialize(React::ReactContext const &reactContext) noexcept {
+ m_context = reactContext;
+}
+
+double {{ pascalName }}::multiply(double a, double b) noexcept {
+ return a * b;
+}
+
+} // namespace winrt::{{ namespaceCpp }}
\ No newline at end of file
diff --git a/vnext/templates/cpp-lib/windows/MyLib/MyLib.def b/vnext/templates/cpp-lib/windows/MyLib/MyLib.def
new file mode 100644
index 00000000000..24e7c1235c3
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/MyLib.def
@@ -0,0 +1,3 @@
+EXPORTS
+DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
+DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
diff --git a/vnext/templates/cpp-lib/windows/MyLib/MyLib.h b/vnext/templates/cpp-lib/windows/MyLib/MyLib.h
new file mode 100644
index 00000000000..4f89df5b5bb
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/MyLib.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "pch.h"
+#include "resource.h"
+
+#if __has_include("codegen\Native{{ pascalName }}DataTypes.g.h")
+ #include "codegen\Native{{ pascalName }}DataTypes.g.h"
+#endif
+#include "codegen\Native{{ pascalName }}Spec.g.h"
+
+#include "NativeModules.h"
+
+namespace winrt::{{ namespaceCpp }}
+{
+
+REACT_MODULE({{ pascalName }})
+struct {{ pascalName }}
+{
+ using ModuleSpec = {{ namespaceCpp }}Codegen::{{ pascalName }}Spec;
+
+ REACT_INIT(Initialize)
+ void Initialize(React::ReactContext const &reactContext) noexcept;
+
+ REACT_SYNC_METHOD(multiply)
+ double multiply(double a, double b) noexcept;
+
+private:
+ React::ReactContext m_context;
+};
+
+} // namespace winrt::{{ namespaceCpp }}
\ No newline at end of file
diff --git a/vnext/templates/cpp-lib/windows/MyLib/MyLib.rc b/vnext/templates/cpp-lib/windows/MyLib/MyLib.rc
new file mode 100644
index 00000000000..3212c105fce
Binary files /dev/null and b/vnext/templates/cpp-lib/windows/MyLib/MyLib.rc differ
diff --git a/vnext/templates/cpp-lib/windows/MyLib/MyLib.vcxproj b/vnext/templates/cpp-lib/windows/MyLib/MyLib.vcxproj
new file mode 100644
index 00000000000..89cb24908df
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/MyLib.vcxproj
@@ -0,0 +1,140 @@
+
+
+
+
+
+ true
+ true
+ {{ projectGuidUpper }}
+ {{ name }}
+ Win32Proj
+ {{ namespace }}
+ 10.0
+ en-US
+ 17.0
+ false
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\
+ false
+
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ DynamicLibrary
+ Unicode
+ v143
+ false
+
+
+ true
+
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level3
+ true
+ %(AdditionalOptions) /bigobj
+ 4453;28204
+ _WINRT_DLL;%(PreprocessorDefinitions)
+ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)
+ stdcpp17
+
+
+ shell32.lib;user32.lib;windowsapp.lib;%(AdditionalDependenices)
+ Console
+ true
+ {{ name }}.def
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ USE_FABRIC;%(PreprocessorDefinitions)
+
+
+
+
+
+
+ ReactPackageProvider.idl
+
+
+
+
+
+
+
+
+ Create
+
+
+ ReactPackageProvider.idl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{#cppNugetPackages}}
+
+ {{/cppNugetPackages}}
+
+
+
+ This project references targets in your node_modules\react-native-windows folder. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/vnext/templates/cpp-lib/windows/MyLib/MyLib.vcxproj.filters b/vnext/templates/cpp-lib/windows/MyLib/MyLib.vcxproj.filters
new file mode 100644
index 00000000000..0f7dbff1fb5
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/MyLib.vcxproj.filters
@@ -0,0 +1,44 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.cpp b/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.cpp
new file mode 100644
index 00000000000..c2386f60205
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.cpp
@@ -0,0 +1,20 @@
+#include "pch.h"
+
+#include "ReactPackageProvider.h"
+#if __has_include("ReactPackageProvider.g.cpp")
+#include "ReactPackageProvider.g.cpp"
+#endif
+
+#include "{{ name }}.h"
+
+using namespace winrt::Microsoft::ReactNative;
+
+namespace winrt::{{ namespaceCpp }}::implementation
+{
+
+void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
+{
+ AddAttributedModules(packageBuilder, true);
+}
+
+} // namespace winrt::{{ namespaceCpp }}::implementation
diff --git a/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.h b/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.h
new file mode 100644
index 00000000000..22532fd6449
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "ReactPackageProvider.g.h"
+
+using namespace winrt::Microsoft::ReactNative;
+
+namespace winrt::{{ namespaceCpp }}::implementation
+{
+
+struct ReactPackageProvider : ReactPackageProviderT
+{
+ ReactPackageProvider() = default;
+
+ void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
+};
+
+} // namespace winrt::{{ namespaceCpp }}::implementation
+
+namespace winrt::{{ namespaceCpp }}::factory_implementation
+{
+
+struct ReactPackageProvider : ReactPackageProviderT {};
+
+} // namespace winrt::{{ namespaceCpp }}::factory_implementation
diff --git a/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.idl b/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.idl
new file mode 100644
index 00000000000..1465f2e7184
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/ReactPackageProvider.idl
@@ -0,0 +1,9 @@
+namespace {{ namespace }}
+{
+ [webhosthidden]
+ [default_interface]
+ runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider
+ {
+ ReactPackageProvider();
+ };
+}
diff --git a/vnext/templates/cpp-lib/windows/MyLib/_gitignore b/vnext/templates/cpp-lib/windows/MyLib/_gitignore
new file mode 100644
index 00000000000..82fabe9662a
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/_gitignore
@@ -0,0 +1 @@
+/Bundle
\ No newline at end of file
diff --git a/vnext/templates/cpp-lib/windows/MyLib/pch.cpp b/vnext/templates/cpp-lib/windows/MyLib/pch.cpp
new file mode 100644
index 00000000000..1d9f38c57d6
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/pch.cpp
@@ -0,0 +1 @@
+#include "pch.h"
diff --git a/vnext/templates/cpp-lib/windows/MyLib/pch.h b/vnext/templates/cpp-lib/windows/MyLib/pch.h
new file mode 100644
index 00000000000..b93cec13351
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/pch.h
@@ -0,0 +1,30 @@
+// pch.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#define NOMINMAX 1
+#define WIN32_LEAN_AND_MEAN 1
+#define WINRT_LEAN_AND_MEAN 1
+
+// Windows Header Files
+#include
+#include
+#undef GetCurrentTime
+
+// WinRT Header Files
+#include
+#include
+#include
+
+// C RunTime Header Files
+#include
+#include
+#include
+#include
+
+// Reference additional headers your project requires here
diff --git a/vnext/templates/cpp-lib/windows/MyLib/resource.h b/vnext/templates/cpp-lib/windows/MyLib/resource.h
new file mode 100644
index 00000000000..964739b0b37
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/resource.h
@@ -0,0 +1,5 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by {{ name }}.rc
+
+#pragma once
diff --git a/vnext/templates/cpp-lib/windows/MyLib/targetver.h b/vnext/templates/cpp-lib/windows/MyLib/targetver.h
new file mode 100644
index 00000000000..87c0086de75
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/MyLib/targetver.h
@@ -0,0 +1,8 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include
diff --git a/vnext/templates/cpp-lib/windows/_gitignore b/vnext/templates/cpp-lib/windows/_gitignore
new file mode 100644
index 00000000000..5bc72a4416d
--- /dev/null
+++ b/vnext/templates/cpp-lib/windows/_gitignore
@@ -0,0 +1,41 @@
+*AppPackages*
+*BundleArtifacts*
+
+#OS junk files
+[Tt]humbs.db
+*.DS_Store
+
+#Visual Studio files
+*.[Oo]bj
+*.user
+*.aps
+*.pch
+*.vspscc
+*.vssscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.[Cc]ache
+*.ilk
+*.log
+*.lib
+*.sbr
+*.sdf
+*.opensdf
+*.opendb
+*.unsuccessfulbuild
+ipch/
+[Oo]bj/
+[Bb]in
+[Dd]ebug*/
+[Rr]elease*/
+Ankh.NoLoad
+.vs/
+# Visual C++ cache files
+
+#Files generated by the VS build
+**/Generated Files/**
diff --git a/vnext/templates/templateUtils.js b/vnext/templates/templateUtils.js
index e9f2bb7174b..d3c9646d95a 100644
--- a/vnext/templates/templateUtils.js
+++ b/vnext/templates/templateUtils.js
@@ -7,41 +7,131 @@
*/
const existsSync = require('fs').existsSync;
+const fs = require('fs').promises;
const path = require('path');
const util = require('util');
const exec = util.promisify(require('child_process').exec);
+const _ = require('lodash');
+
const pkgUtils = require('@react-native-windows/package-utils');
+const projectConfig = require('@react-native-windows/cli').projectConfig;
+const dependencyConfig = require('@react-native-windows/cli').dependencyConfig;
+
+function getRnwInfo(config = {}, options = {}) {
+ const projectRoot = config?.root ?? process.cwd();
+
+ const rnwPath = path.dirname(
+ require.resolve('react-native-windows', [projectRoot]),
+ );
+
+ const rnwVersion = require(path.join(rnwPath, 'package.json')).version;
+
+ const devMode = existsSync(path.join(rnwPath, 'src'));
+
+ if (options?.logging) {
+ console.log(
+ `Found react-native-windows@${rnwVersion} at ${rnwPath}${
+ devMode ? ' (devMode enabled)' : ''
+ }...`,
+ );
+ }
+
+ return {rnwPath, rnwVersion, devMode};
+}
+
+function getWindowsProjectConfig(root) {
+ if (!existsSync(root)) {
+ return {};
+ }
+
+ const userConfigPath = path.join(root, 'react-native.config.js');
+
+ const userConfig = existsSync(userConfigPath) ? require(userConfigPath) : {};
+
+ return projectConfig(root, userConfig);
+}
+
+function getWindowsDependencyConfig(root) {
+ if (!existsSync(root)) {
+ return {};
+ }
+
+ const userConfigPath = path.join(root, 'react-native.config.js');
+
+ const userConfig = existsSync(userConfigPath) ? require(userConfigPath) : {};
+
+ return dependencyConfig(root, userConfig);
+}
+
+function pascalCase(str) {
+ const camelCase = _.camelCase(str);
+ return camelCase[0].toUpperCase() + camelCase.substr(1);
+}
+
+async function replaceInFile(
+ config = {},
+ options = {},
+ relativePath = '',
+ searchValue = '',
+ replaceValue = '',
+) {
+ const filePath = path.join(config?.root ?? process.cwd(), relativePath);
+ if (existsSync(filePath)) {
+ const contents = await fs.readFile(filePath, {encoding: 'utf-8'});
+ const newContents = contents.replace(searchValue, replaceValue);
+ if (contents !== newContents) {
+ if (options?.logging) {
+ console.log(`Modifying ${filePath}...`);
+ }
+ await fs.writeFile(filePath, newContents, {encoding: 'utf-8'});
+ }
+ }
+}
+
async function runNpmInstall(config = {}, options = {}) {
- const projectPath = config?.root ?? process.cwd();
+ const projectRoot = config?.root ?? process.cwd();
if (options?.logging) {
- console.log('Installing dependencies...');
+ console.log(`Installing dependencies for ${projectRoot}...`);
+ }
+ const isYarn = existsSync(path.join(projectRoot, 'yarn.lock'));
+ const cmd = isYarn ? 'yarn' : 'npm i';
+
+ try {
+ await exec(cmd, options?.logging ? {stdio: 'inherit'} : {});
+ } catch (ex) {
+ console.log(
+ `Failed to install dependencies for ${projectRoot}. Please run '${cmd}' manually to update the dependencies.`,
+ );
}
- const isYarn = existsSync(path.join(projectPath, 'yarn.lock'));
- await exec(
- isYarn ? 'yarn' : 'npm i',
- options?.logging ? {stdio: 'inherit'} : {},
- );
}
async function updateProjectPackageJson(config = {}, options = {}, props = {}) {
- const projectPath = config?.root ?? process.cwd();
+ const projectRoot = config?.root ?? process.cwd();
const projectPackage = await pkgUtils.WritableNpmPackage.fromPath(
- projectPath,
+ projectRoot,
);
if (!projectPackage) {
throw new Error(
- `The directory '${projectPath}' is not the root of an npm package`,
+ `The directory '${projectRoot}' is not the root of an npm package`,
);
}
if (options?.logging) {
- console.log('Modifying project package.json...');
+ console.log(`Modifying ${path.join(projectRoot, 'package.json')}...`);
}
await projectPackage.mergeProps(props);
}
-module.exports = {runNpmInstall, updateProjectPackageJson};
+module.exports = {
+ getRnwInfo,
+ getWindowsProjectConfig,
+ getWindowsDependencyConfig,
+ pascalCase,
+ replaceInFile,
+ runNpmInstall,
+ updateProjectPackageJson,
+};