如何创建适用于最新版本(并避免其他问题)的自定义项目文件?

How to create custom project file that works with fast-up-to-date (and avoids other problems)?

我正在尝试创建一个执行几个自定义步骤的项目文件(具体来说,它“包装”了现有的 Angular CLI 项目)。

这是我最好的尝试 (myproject.csproj):

<Project ToolsVersion="Current" DefaultTargets="Build">
  <PropertyGroup>
    <ProjectGuid>{...some-guid...}</ProjectGuid>
    <!-- do not include files by default -->
    <EnableDefaultItems>false</EnableDefaultItems>
    <!-- this removes 'Publish...' menu in VS -->
    <OutputType>Library</OutputType>
    <!-- output directory name -->
    <AngularProject>MyWebFiles</AngularProject>
  </PropertyGroup>
  
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
    <PlatformTarget>x64</PlatformTarget>
    <OutputPath>bin\Debug\</OutputPath>
  </PropertyGroup>
  
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
    <PlatformTarget>x64</PlatformTarget>
    <OutputPath>bin\Release\</OutputPath>
  </PropertyGroup>
  
  <ItemGroup>
    <AngularFile Include="**" Exclude="node_modules\**" />
  </ItemGroup>

  <Target Name="Build" Inputs="@(AngularFile)" Outputs="$(OutputPath)$(AngularProject)\index.html">
    <Exec Command="ng build --no-progress --output-path $(OutputPath)$(AngularProject)\" Condition="'$(Configuration)'=='Debug'" />
    <Exec Command="ng build --no-progress --output-path $(OutputPath)$(AngularProject)\ --prod" Condition="'$(Configuration)'=='Release'" />
  </Target>
  
  <Target Name="Clean">
    <RemoveDir Directories="$(OutputPath)$(AngularProject)\" />
  </Target>
  
  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
</Project>

一切正常,我可以将此项目添加到 VS2019 解决方案中,编译等。但它有问题:

  1. 快速更新检查不起作用。 Related logging 产生这个:
  Build started...
  1>Project 'myproject' is not up to date. Error (0x8000FFFF). 

我试过指定快速更新的文件 manually(通过 UpToDateCheckInput 等),但它没有用(大概是因为它依赖于在您指定 Project 标签的 Sdk 属性)。

  1. VS 配置管理器有空 'Platform' 组合框。我希望能够在其中包含 x64:

很明显 PlatformTarget 被 VS 忽略了。

  1. 在 VS 中打开项目会创建 obj\x64\Debug\TempPE\ 目录(如果当前 ConfigurationDebug)。它不会生成任何东西——最好避免创建它。

是否可以解决这 3 个问题?我怀疑相关子系统期望生成某些 values/properties,我尝试挖掘 VS 附带的 .props/.targets 以试图找到它们,但很快就迷路了。

操作方法如下:

<Project Sdk="Microsoft.Build.NoTargets/3.2.14">
  <ItemGroup>
    <PackageReference Include="Microsoft.Build.NoTargets" Version="3.2.14" />
  </ItemGroup>

  <PropertyGroup>
    <!-- Any target framework you want as long as its compatible with your referenced NuGet packages -->
    <TargetFramework>net462</TargetFramework>
    <Platforms>x64</Platforms>
    <!-- Do not add TargetFramework to OutputPath -->
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
    <!-- Do not expect pdb files to be generated (this is for fast up-to-date check) -->
    <DebugType>None</DebugType>
    <!-- Do not include files by default -->
    <EnableDefaultItems>false</EnableDefaultItems>
    <!-- Output subdir name -->
    <AngularProject>MyWebFiles</AngularProject>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <OutputPath>..\..\Bin\Debug\</OutputPath>
    <BuildCommand>ng build --no-progress --output-path $(OutputPath)$(AngularProject)\</BuildCommand>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <OutputPath>..\..\Bin\Release\</OutputPath>
    <BuildCommand>ng build --no-progress --output-path $(OutputPath)$(AngularProject)\ --prod</BuildCommand>
  </PropertyGroup>

  <ItemGroup>
    <None Include="**" Exclude="node_modules\**;$(BaseIntermediateOutputPath)\**;$(MSBuildProjectFile)" />
    
    <!-- This deals with fast up-to-date checks -->
    <UpToDateCheckBuilt Original="package-lock.json" Include="node_modules/.build" />
    
    <UpToDateCheckInput Include="@(None);$(MSBuildProjectFile)" Set="AngularFiles" />
    <UpToDateCheckOutput Include="$(OutputPath)$(AngularProject)\index.html" Set="AngularFiles" />
  </ItemGroup>

  <Target Name="InitModules" Inputs="package-lock.json" Outputs="node_modules/.build">
    <Exec Command="npm ci --no-progress --no-color" YieldDuringToolExecution="true" />
    <Exec Command="cd . &gt; node_modules/.build" />
  </Target>

  <Target Name="BuildAngular" BeforeTargets="AfterBuild" Inputs="@(None);$(MSBuildProjectFile)" Outputs="$(OutputPath)$(AngularProject)\index.html" DependsOnTargets="InitModules">
    <Exec Command="$(BuildCommand)" YieldDuringToolExecution="true" />
  </Target>

  <Target Name="CleanAngular" BeforeTargets="AfterClean">
    <RemoveDir Directories="$(OutputPath)$(AngularProject)\" />
  </Target>
</Project>

备注:

  • 它仍然会生成额外的本地目录(obj),但可以通过覆盖 IntermediateOutputPath
  • 将其移走