C
C#16mo ago
Thinker

✅ Copy files generated by command to build output

During a build, I want to run a command to build a Vue project which outputs its files to a folder, then copy the files from that folder to a wwwroot folder in the project's build output. How would I do this? I know I can use Exec to run the command which works fine, but I don't know how I would copy the files properly while preserving the subfolder structure.
27 Replies
Pobiega
Pobiega16mo ago
we do that in the dockerfile at work. Not an answer to your question, but perhaps an alternative
Thinker
ThinkerOP16mo ago
1. You have a problem 2. Use Docker to solve problem 3. You have two problems
Pobiega
Pobiega16mo ago
😄
Thinker
ThinkerOP16mo ago
I'm not using Docker in this project (yet) so that feels very overkill
Pobiega
Pobiega16mo ago
sure you could check how the dotnet new react project template does it it does it with msbuild
trunksvn
trunksvn16mo ago
harold
Thinker
ThinkerOP16mo ago
yeah at this point idk why this doesn't work
<!-- Build Vue project -->
<Exec Command="npm run build" WorkingDirectory="@(VueProject)" />

<!-- Include Vue output in project output -->
<ItemGroup>
<VueOutput Include="$(ProjectDir)\..\..\..\client\Dist\**" />
</ItemGroup>
<Copy SourceFiles="@(VueOutput)" DestinationFolder="$(OutputDir)\%(RecursiveDir)" />
<!-- Build Vue project -->
<Exec Command="npm run build" WorkingDirectory="@(VueProject)" />

<!-- Include Vue output in project output -->
<ItemGroup>
<VueOutput Include="$(ProjectDir)\..\..\..\client\Dist\**" />
</ItemGroup>
<Copy SourceFiles="@(VueOutput)" DestinationFolder="$(OutputDir)\%(RecursiveDir)" />
reflectronic
reflectronic16mo ago
have you tried looking at a binlog
Thinker
ThinkerOP16mo ago
okay now I'm using this from the React template
<!-- Build Vue project -->
<Exec Command="npm run build" WorkingDirectory="@(VueProject)" />

<!-- Include Vue output in project output -->
<ItemGroup>
<DistFiles Include="$(VueProject)dist\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
<!-- Build Vue project -->
<Exec Command="npm run build" WorkingDirectory="@(VueProject)" />

<!-- Include Vue output in project output -->
<ItemGroup>
<DistFiles Include="$(VueProject)dist\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
...and it's still not working As in, the wwwroot just doesn't appear in the bin/release/net8.0 folder
reflectronic
reflectronic16mo ago
you are sure that npm run build actually happens, right
Thinker
ThinkerOP16mo ago
it absolutely does okay this is the entire target
<Target Name="BuildVueProject" BeforeTargets="Build" Condition="'$(Configuration)'=='Release'" >
<ItemGroup>
<VueProject Include="$(ProjectDir)\..\..\..\client" />
</ItemGroup>

<!-- Ensure Node.js is installed -->
<Exec Command="node --version" EchoOff="true" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)'!='0'" Text="Node.js is required to build project." />

<!-- Build Vue project -->
<Exec Command="npm run build" WorkingDirectory="@(VueProject)" />

<!-- Include Vue output in project output -->
<ItemGroup>
<DistFiles Include="$(VueProject)dist\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
<Target Name="BuildVueProject" BeforeTargets="Build" Condition="'$(Configuration)'=='Release'" >
<ItemGroup>
<VueProject Include="$(ProjectDir)\..\..\..\client" />
</ItemGroup>

<!-- Ensure Node.js is installed -->
<Exec Command="node --version" EchoOff="true" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)'!='0'" Text="Node.js is required to build project." />

<!-- Build Vue project -->
<Exec Command="npm run build" WorkingDirectory="@(VueProject)" />

<!-- Include Vue output in project output -->
<ItemGroup>
<DistFiles Include="$(VueProject)dist\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
Most of this is copied from the React template and I don't get what is wrong I tried changing $(VueProject)dist\** to @(VueProject)dist\** but that caused an error saying The expression "@(VueProject)dist\**" cannot be used in this context. Item lists cannot be concatenated with other strings where an item list is expected. Use a semicolon to separate multiple item lists. Another thing which does not work
<ItemGroup>
<DistFiles Include="$(VueProject)\dist\**" />
</ItemGroup>
<Copy SourceFiles="@(DistFiles)" DestinationFolder="$(OutputDir)\wwwroot\%(RecursiveDir)" />
<ItemGroup>
<DistFiles Include="$(VueProject)\dist\**" />
</ItemGroup>
<Copy SourceFiles="@(DistFiles)" DestinationFolder="$(OutputDir)\wwwroot\%(RecursiveDir)" />
Doesn't do anything either
<Copy SourceFiles="@(DistFiles)" DestinationFiles="$(OutputDir)\wwwroot\**" />
<Copy SourceFiles="@(DistFiles)" DestinationFiles="$(OutputDir)\wwwroot\**" />
And there doesn't seem to be a difference between OutputPath and OutputDir I have no idea what I'm doing wrong Idk how to debug this even
reflectronic
reflectronic16mo ago
looking at the binlog would help
Thinker
ThinkerOP16mo ago
where is that?
reflectronic
reflectronic16mo ago
oh you don't even know https://msbuildlog.com/
Thinker
ThinkerOP16mo ago
odd, there's only one parameter to the copy task
No description
reflectronic
reflectronic16mo ago
do you see any Add Item elements in the target
Thinker
ThinkerOP16mo ago
There's one for VueProject, but none for the DistFiles catthinking
reflectronic
reflectronic16mo ago
can you try "$(VueProject)\dist\**"
Thinker
ThinkerOP16mo ago
For SourceFiles in the copy task, or DistFiles?
reflectronic
reflectronic16mo ago
for DistFiles
Thinker
ThinkerOP16mo ago
no difference afaict okay I think the issue is that $(VueProject)dist doesn't exist it refuses to allow me to concatenate god damn strings catlost just refuses to work
<DistFiles Include="$(VueProject)\dist\**" />
<DistFiles Include="$(VueProject)\dist\**" />
If I do <Message Text="$(VueProject)\dist" Importance="high" /> then it just prints \dist So VueProject doesn't exist??? It lets me do <Message Text="@(VueProject)\dist" Importance="high" /> which prints it properly, but doesn't let me do <DistFiles Include="@(VueProject)\dist\**" /> because it can't concatenate strings?????? why doesn't this work again <DistFiles Include="$(VueProject)\dist\**" /> doesn't even show up in the log like what It's clearly there but it refuses to work
reflectronic
reflectronic16mo ago
oh. VueProject is an item. $(VueProject) does not do anything
Thinker
ThinkerOP16mo ago
catlost feel so dumb
<DistFiles Include="$(ProjectDir)..\..\..\client\dist\**" />
<DistFiles Include="$(ProjectDir)..\..\..\client\dist\**" />
THIS WORKS So if I just don't use VueProject then it's fine, it's just kinda uglier
reflectronic
reflectronic16mo ago
i mean. you can just make VueProject a property instead
Thinker
ThinkerOP16mo ago
yeahhhhh I realized you could do that this entire thread has just been me not knowing anything about msbuild seriously thank you so much @reflectronic on another note, it's 2 am and I need to sleep
reflectronic
reflectronic16mo ago
enjoy

Did you find this page helpful?