Can I do a loop in an MSBuild file?

2019-07-01 10:56发布

问题:

Currently, I've got he following code in an MSBuild proj file. It's really simple. Define 4 variables and call my MSBuild Task once-per-variable :

Code please ~~

<ItemGroup><JS_File1 Include="file1.js"/></ItemGroup>
<ItemGroup><JS_File1 Include="file2.js"/></ItemGroup>
<ItemGroup><JS_File1 Include="file3.js"/></ItemGroup>
<ItemGroup><JS_File1 Include="file4.js"/></ItemGroup>

<JavaScriptCompressorTask SourceFiles="@(JS_File1)" OutputFile="@(JS_File1).min"/>
<JavaScriptCompressorTask SourceFiles="@(JS_File2)" OutputFile="@(JS_File2).min"/>
<JavaScriptCompressorTask SourceFiles="@(JS_File3)" OutputFile="@(JS_File3).min"/>
<JavaScriptCompressorTask SourceFiles="@(JS_File4)" OutputFile="@(JS_File4).min"/>

Nothing exciting at all.

I was wondering if this could be refactored to something like this.

Fail-Pseudo-Code ~~

<ItemGroup>
    <JS_File1 Include="file1.js"/>
    <JS_File1 Include="file2.js"/>
    <JS_File1 Include="file3.js"/>
    <JS_File1 Include="file4.js"/>
</ItemGroup>

<!-- now this is the shiz i have no idea about -->
foreach(@(JS_Files))
    <JavaScriptCompressorTask SourceFiles="@(theFile)" OutputFile="@(theFile).min"/>

Is it possible to do this, in MSBuild?

So that task is called once-per-file .. or more to the point, once-per-item-in-the-item-group?

回答1:

You can use item metadata to batch the task (see http://msdn.microsoft.com/en-us/library/ms171474.aspx).

All items have metadata called 'Identity,' which contains the value of the Include attribute. If you use metadata reference syntax %(Identity), that will instruct MSBuild to execute your task for each unique Include value.

<ItemGroup>
    <JS_File1 Include="file1.js"/>
    <JS_File1 Include="file2.js"/>
    <JS_File1 Include="file3.js"/>
    <JS_File1 Include="file4.js"/>
</ItemGroup>

<JavaScriptCompressorTask SourceFiles="@(JS_File1)" OutputFile="%(Identity).min"/>

Note that MSBuild knows that you are referencing the Identity metadata of the JS_File1 item group because you reference it in the task. Otherwise you would need to use the syntax %(JS_File1.Identity).



回答2:

Like this, except use your task not my copy....

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Minifier" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Minifier">
    <ItemGroup>
      <JS_File1 Include="file1.js"/>
      <JS_File1 Include="file2.js"/>
      <JS_File1 Include="file3.js"/>
      <JS_File1 Include="file4.js"/>
    </ItemGroup>

    <Copy SourceFiles="@(JS_File1)" DestinationFiles="@(JS_File1->'%(Filename).min')"/>

  </Target>
</Project>

Hope thats helps.