Skip to content

[WIP] [DRAFT] Implement New Architecture C# template cs-app #15013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Implement New Architecture C# template `cs-app`",
"packageName": "@react-native-windows/cli",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Implement New Architecture C# template `cs-app`",
"packageName": "react-native-windows",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,22 @@ export function getRawTemplateInfo(filePath: string): RawTemplateInfo {
) {
result.projectType = 'lib';
result.projectArch = 'old';
} else if (
importProjectExists(
projectContents,
'Microsoft.ReactNative.Composition.CSharpApp.targets',
)
) {
result.projectType = 'app';
result.projectArch = 'new';
} else if (
importProjectExists(
projectContents,
'Microsoft.ReactNative.Composition.CSharpLib.targets',
)
) {
result.projectType = 'lib';
result.projectArch = 'new';
}
} else if (result.projectLang === 'cpp') {
if (
Expand Down Expand Up @@ -377,11 +393,18 @@ export function importProjectExists(
projectContents: Node,
projectName: string,
): boolean {
const nodes = msbuildSelect(
let nodes = msbuildSelect(
`//msbuild:Import[contains(@Project,'${projectName}')]`,
projectContents,
);

if (nodes.length === 0) {
nodes = msbuildSelect(
`//Import[contains(@Project,'${projectName}')]`,
projectContents,
);
}

return nodes.length > 0;
}

Expand Down
1 change: 1 addition & 0 deletions vnext/PropertySheets/Bundle.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<Target Name="CompileHermesBytecode" AfterTargets="MakeBundle" Condition="'$(UseBundle)' == 'true' AND '$(UseHermes)' == 'true'">
<Message Importance="High" Text="Running [$(HermesCompilerCommand) -emit-binary -out $(BundleOutputFile).hbc $(BundleOutputFile) $(HermesCompilerFlags) -output-source-map] to precompile bundle file." />
<Exec Command='$(HermesCompilerCommand) -emit-binary -out "$(BundleOutputFile).hbc" "$(BundleOutputFile)" $(HermesCompilerFlags) -output-source-map' ConsoleToMSBuild="true" WorkingDirectory="$(BundleCommandWorkingDir)" />
<Delete Files="$(BundleOutputFile)" />
<Move SourceFiles="$(BundleOutputFile).hbc" DestinationFiles="$(BundleOutputFile)" />
<Move SourceFiles="$(BundleOutputFile).hbc.map" DestinationFiles="$(HermesSourceMap)" />
<Exec Command='node "$(ReactNativeDir)\scripts\compose-source-maps.js" "$(PackagerSourceMap)" "$(HermesSourceMap)" -o "$(BundleSourceMap)"' ConsoleToMSBuild="true" WorkingDirectory="$(BundleCommandWorkingDir)" />
Expand Down
9 changes: 6 additions & 3 deletions vnext/PropertySheets/Bundle.props
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@
<BundleEntryFile Condition="'$(BundleEntryFile)' == '' and Exists('$(BundleCommandWorkingDir)\index.windows.js')">index.windows.js</BundleEntryFile>
<BundleEntryFile Condition="'$(BundleEntryFile)' == ''">index.js</BundleEntryFile>

<FullOutDir Condition="'$([System.IO.Path]::GetFullPath($(OutDir)))' == '$(OutDir)'">$(OutDir)</FullOutDir>
<FullOutDir Condition="'$([System.IO.Path]::GetFullPath($(OutDir)))' != '$(OutDir)'">$(ProjectDir)$(OutDir)</FullOutDir>
<BundleOutDir>$(OutDir)</BundleOutDir>
<!-- OutDir isn't set this early in .NET projects, need to re-create it -->
<BundleOutDir Condition="'$(BundleOutDir)'=='' And '$(MSBuildProjectExtension)' == '.csproj'">bin\$(Platform)\$(Configuration)\$(TargetFramework)</BundleOutDir>
<BundleFullOutDir Condition="'$([System.IO.Path]::GetFullPath($(BundleOutDir)))' == '$(BundleOutDir)'">$(BundleOutDir)</BundleFullOutDir>
<BundleFullOutDir Condition="'$([System.IO.Path]::GetFullPath($(BundleOutDir)))' != '$(BundleOutDir)'">$(ProjectDir)$(BundleOutDir)</BundleFullOutDir>

<!-- Location where source map file for the JS bundle will be created -->
<BundleSourceMapDir Condition="'$(BundleSourceMapDir)' == ''">$([MSBuild]::NormalizePath('$(FullOutDir)\sourcemaps\react'))</BundleSourceMapDir>
<BundleSourceMapDir Condition="'$(BundleSourceMapDir)' == ''">$([MSBuild]::NormalizePath('$(BundleFullOutDir)\sourcemaps\react'))</BundleSourceMapDir>

<!-- Base (extensionless) filename for bundle sourcemaps -->
<BaseBundleSourceMap Condition="'$(BaseBundleSourceMap)' == ''">$(BundleSourceMapDir)\$(BundleAssetName)</BaseBundleSourceMap>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,17 @@
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Only include Microsoft.ReactNative.* NuGet packages that C# (app and lib) projects need when using UseExperimentalNuget. -->
<ItemGroup>
<PackageReference Include="Microsoft.ReactNative" Version="$(ReactNativeWindowsVersion)" />
<PackageReference Include="Microsoft.ReactNative.Managed" Version="$(ReactNativeWindowsVersion)" />
</ItemGroup>
<Choose>
<When Condition="'$(RnwNewArch)' == 'true'">
<ItemGroup>
<PackageReference Include="Microsoft.ReactNative" Version="$(ReactNativeWindowsVersion)" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<PackageReference Include="Microsoft.ReactNative" Version="$(ReactNativeWindowsVersion)" />
<PackageReference Include="Microsoft.ReactNative.Managed" Version="$(ReactNativeWindowsVersion)" />
</ItemGroup>
</Otherwise>
</Choose>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,29 @@
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- To avoid having these references show in in Visual Studio which ignores conditions on items we have to put the source references in source. -->
<ItemGroup>
<ProjectReference Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\Microsoft.ReactNative.vcxproj">
<Project>{f7d32bd0-2749-483e-9a0d-1635ef7e3136}</Project>
<Name>Microsoft.ReactNative</Name>
<Private Condition="'$(ConfigurationType)' != 'Application'">false</Private>
</ProjectReference>
<ProjectReference Include="$(ReactNativeWindowsDir)Microsoft.ReactNative.Managed\Microsoft.ReactNative.Managed.csproj">
<Project>{F2824844-CE15-4242-9420-308923CD76C3}</Project>
<Name>Microsoft.ReactNative.Managed</Name>
<Private Condition="'$(ConfigurationType)' != 'Application'">false</Private>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(RnwNewArch)' == 'true'">
<ItemGroup>
<ProjectReference Include="$(ReactNativeWindowsDir)Microsoft.ReactNative.CsWinRT\Microsoft.ReactNative.CsWinRT.csproj">
<Project>{B76BB397-D882-48D8-AA8D-DA9921860B2B}</Project>
<Name>Microsoft.ReactNative.CsWinRT</Name>
<Private Condition="'$(ConfigurationType)' != 'Application'">false</Private>
</ProjectReference>
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<ProjectReference Include="$(ReactNativeWindowsDir)Microsoft.ReactNative\Microsoft.ReactNative.vcxproj">
<Project>{f7d32bd0-2749-483e-9a0d-1635ef7e3136}</Project>
<Name>Microsoft.ReactNative</Name>
<Private Condition="'$(ConfigurationType)' != 'Application'">false</Private>
</ProjectReference>
<ProjectReference Include="$(ReactNativeWindowsDir)Microsoft.ReactNative.Managed\Microsoft.ReactNative.Managed.csproj">
<Project>{F2824844-CE15-4242-9420-308923CD76C3}</Project>
<Name>Microsoft.ReactNative.Managed</Name>
<Private Condition="'$(ConfigurationType)' != 'Application'">false</Private>
</ProjectReference>
</ItemGroup>
</Otherwise>
</Choose>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.

This file will be consumed by ALL Win32 C# app projects (both inside
and outside of this repo) that build on top of Microsoft.ReactNative.
Do not make any changes here unless it applies to ALL such projects.
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Keeping this at the top of the imports ensures we can use the autolinking
process to set properties without having to edit the project file -->
<Import Project="$(ProjectDir)\AutolinkedNativeModules.g.props"
Condition="Exists('$(ProjectDir)\AutolinkedNativeModules.g.props')" />

<!-- Check that Microsoft.ReactNative.WindowsSdk.Default.props has already been imported. -->
<Target Name="EnsureRnwSdkDefaultsSetTarget" BeforeTargets="PrepareForBuild" Condition="'$(RnwSdkDefaultsSet)'!='true'">
<Warning Text="Property `RnwSdkDefaultsSet` was not set. Please ensure your project imports 'Microsoft.ReactNative.WindowsSdk.Default.props' before importing this prop sheet." />
</Target>

<!-- Import common props sheets common to all Composition projects. -->
<Import Project="$(MSBuildThisFileDirectory)Microsoft.ReactNative.Composition.Common.props" />

<!-- Set props and import specific prop sheets for this kind of project. -->
<PropertyGroup>
<TargetFramework Condition="'$(TargetFramework)'==''">net6.0-windows10.0.22621.0</TargetFramework>
<AssetTargetFallback>net6.0-windows$(TargetPlatformVersion);$(AssetTargetFallback)</AssetTargetFallback>
<!-- Workaround to stop msbuild from getting confused about copying hermes twice -->
<NugetRootOverride>$([MSBuild]::NormalizePath($(HermesPackage)\))</NugetRootOverride>
<!-- Workaround to stop WebView2 targets from trying to copy their DLLs from Hermes package. -->
<WebView2EnableCsWinRTProjection>false</WebView2EnableCsWinRTProjection>
</PropertyGroup>
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\Appx.props" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\Autolink.props" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\Codegen.props" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\HybridCRT.props" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\NuGet.CSharp.props" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\WinUI.props" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\PackageVersionDefinitions.props" />

<PropertyGroup>
<RnwExternalPropsLoaded>$(MSBuildThisFile)</RnwExternalPropsLoaded>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) Microsoft Corporation.
Licensed under the MIT License.

This file will be consumed by ALL Win32 C# app projects (both inside
and outside of this repo) that build on top of Microsoft.ReactNative.
Do not make any changes here unless it applies to ALL such projects.
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Check that the correct props have already been imported. -->
<Target Name="EnsureRnwExternalPropsLoadedTarget" BeforeTargets="PrepareForBuild" Condition="'$(RnwExternalPropsLoaded)'!='Microsoft.ReactNative.Composition.CSharpApp.props'">
<Warning Text="Property `RnwExternalPropsLoaded` was incorrectly set to '$(RnwExternalPropsLoaded)'. Please ensure your project imports 'Microsoft.ReactNative.Composition.CSharpApp.props' before importing this prop sheet." />
</Target>

<Import Project="$(ReactNativeWindowsDir)PropertySheets\External\Microsoft.ReactNative.Common.targets" />

<!-- Due to visual studio unconditionally showing references, we have to trick it by making it impossible for VS to find the reference differences between building as source and building as NuGet -->
<Import Project="$(ReactNativeWindowsDir)PropertySheets\External\Microsoft.ReactNative.CSharp.ProjectReferences.props" Condition="!$(UseExperimentalNuget)" />
<Import Project="$(ReactNativeWindowsDir)PropertySheets\External\Microsoft.ReactNative.CSharp.PackageReferences.props" Condition="$(UseExperimentalNuget)" />

<ItemGroup>
<!-- <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.756" /> -->
<!-- <PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" /> -->
<!-- WinUI package name and version are set by WinUI.props -->
<PackageReference Include="$(WinUIPackageName)" Version="$(WinUIPackageVersion)" Condition="'$(OverrideWinUIPackage)'!='true'" />
<!-- Hermes version is set by JSEngine.props -->
<PackageReference Include="Microsoft.JavaScript.Hermes" Version="$(HermesVersion)" Condition="$(UseHermes)" />
</ItemGroup>

<!-- The props file for bundling is not set up to be just defaults, it assumes to be run at the end of the project. -->
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\Bundle.props" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\Bundle.targets" />
<Import Project="$(ReactNativeWindowsDir)\PropertySheets\Autolink.targets" />
<Import Project="$(ProjectDir)\AutolinkedNativeModules.g.targets"
Condition="Exists('$(ProjectDir)\AutolinkedNativeModules.g.targets')" />

<Import Project="$(AppxPackageRecipe)"
Condition="Exists('$(AppxPackageRecipe)') And '$(DeployLayout)'=='true'" />
<Target Name="Deploy" Condition="'$(DeployLayout)'=='true'">
<Error Condition="!Exists('$(AppxPackageRecipe)')"
Text="You must first build the project before deploying it. Did not find: $(AppxPackageRecipe)" />
<Copy SourceFiles="%(AppxPackagedFile.Identity)"
DestinationFiles="$(MSBuildProjectDirectory)\$(OutputPath)Appx\%(AppxPackagedFile.PackagePath)" />
<Copy SourceFiles="%(AppXManifest.Identity)"
DestinationFiles="$(MSBuildProjectDirectory)\$(OutputPath)Appx\%(AppxManifest.PackagePath)"
Condition="'%(AppxManifest.SubType)'!='Designer'"/>
<Exec Command="powershell -NonInteractive -NoProfile -Command Add-AppxPackage -Register $(MSBuildProjectDirectory)\$(OutputPath)Appx\AppxManifest.xml"
ContinueOnError="false" />
</Target>

<Import Project="$(ReactNativeWindowsDir)\PropertySheets\RequireSolution.targets" />

<Import Project="$(ReactNativeWindowsDir)\PropertySheets\OutputMSBuildProperties.targets" />
</Project>
13 changes: 13 additions & 0 deletions vnext/templates/cs-app/NuGet_Config
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
{{#addReactNativePublicAdoFeed}}
<add key="react-native" value="https://pkgs.dev.azure.com/ms/react-native/_packaging/react-native-public/nuget/v3/index.json" />
{{/addReactNativePublicAdoFeed}}
<add key="Nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>
3 changes: 3 additions & 0 deletions vnext/templates/cs-app/jest.config.windows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const config = {};

module.exports = require('@rnx-kit/jest-preset')('windows', config);
54 changes: 54 additions & 0 deletions vnext/templates/cs-app/metro.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

const fs = require('fs');
const path = require('path');
const exclusionList = require('metro-config/src/defaults/exclusionList');

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 = {
//{{#devMode}} [devMode
watchFolders: [rnwPath, rnwRootNodeModules, rnwPackages],
// devMode]{{/devMode}}
resolver: {
blockList: exclusionList([
// This stops "npx @react-native-community/cli run-windows" from causing the metro server to crash if its already running
new RegExp(
`${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
),
// This prevents "npx @react-native-community/cli 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/,
]),
//{{#devMode}} [devMode
extraNodeModules: {
'react-native-windows': rnwPath,
},
// devMode]{{/devMode}}
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
Loading
Loading