Skip to content

Support Incremental Build in Client.Core project in BitBoilerplate template #10533

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

Closed
1 task done
ShahryarSaljoughi opened this issue Apr 22, 2025 · 5 comments · Fixed by #10534
Closed
1 task done

Comments

@ShahryarSaljoughi
Copy link
Contributor

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

Hi. Hope you're all doing well.
Can we design boilerplate project such that it supports incremental build?
As of now, subsequent builds without any changes to source code, do not take advantage of incremental build and try to build the whole project again with the following log:

WARNING: Potential build performance issue in 'bit9.Client.Core.csproj'. The project does not appear up-to-date after a successful build: Input UpToDateCheckInput item 'E:\bit9\bit9\src\Client\bit9.Client.Core\Components\Layout\AppDiagnosticModal.razor.css' is newer (2025-04-22 17:17:24.502) than earliest output 'E:\bit9\bit9\src\Client\bit9.Client.Core\bin\Debug\net9.0\bit9.Client.Core.xml' (2025-04-22 17:16:53.143), not up-to-date. See https://aka.ms/incremental-build-failure.

Describe the solution you'd like

I'm not sure how we can make this happen. Playing with UpToDateCheckBuilt and other related properties didn't help me.

Additional context

No response

@ShahryarSaljoughi
Copy link
Contributor Author

After long hours struggling, I think I found the solution.
Specifying the Input and Outputs of the BuildCssFiles target helps with correct detection of generated css files, such that they won't cause non necessary building of the project.
Here is the csproj of X.Client.Core project with few minor changes:

<Project Sdk="Microsoft.NET.Sdk.Razor">

    <PropertyGroup>
        <TargetFramework>net9.0</TargetFramework>
        <ResolveStaticWebAssetsInputsDependsOn>
            BeforeBuildTasks;
            $(ResolveStaticWebAssetsInputsDependsOn)
        </ResolveStaticWebAssetsInputsDependsOn>
    </PropertyGroup>

    <ItemGroup>
        <SupportedPlatform Include="browser" />

        <Content Remove="compilerconfig.json" />
        <None Include="compilerconfig.json" />
        <Content Remove="appsettings*.json" />
        <EmbeddedResource Include="appsettings*.json" />

        <PackageReference Include="Bit.Butil" />
        <PackageReference Include="Bit.BlazorUI" />
        <PackageReference Include="Bit.BlazorES2019" />
        <PackageReference Include="Bit.BlazorUI.Icons" />
        <PackageReference Include="Bit.BlazorUI.Assets" />
        <PackageReference Include="Fido2.Models" />
        <PackageReference Include="Bit.BlazorUI.Extras" />
        <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" />
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" />
        <PackageReference Include="Microsoft.AspNetCore.Components.Web" />
        <PackageReference Include="Microsoft.Extensions.Logging.Configuration" />
        <PackageReference Include="Microsoft.Extensions.Logging.Debug" />
        <PackageReference Include="Microsoft.Extensions.Logging.Console" />

        <Using Include="System.Net.Http.Json" />
        <Using Include="System.Collections.Concurrent" />
        <Using Include="Microsoft.JSInterop" />
        <Using Include="Microsoft.Extensions.Logging" />
        <Using Include="Microsoft.AspNetCore.Components" />
        <Using Include="Microsoft.AspNetCore.Authorization" />
        <Using Include="Microsoft.AspNetCore.Components.Authorization" />
        <Using Include="Bit.Butil" />
        <Using Include="Bit.BlazorUI" />
        <Using Include="bit9.Shared" />
        <Using Include="bit9.Client.Core.Components.Layout" />
        <Using Include="bit9.Client.Core.Services.Contracts" />
        <Using Include="bit9.Client.Core.Services" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\..\Shared\bit9.Shared.csproj" />
    </ItemGroup>

    <ItemGroup>
        <TypeScriptFiles Include="**\*.ts" />
    </ItemGroup>


    <ItemGroup>
        <ScssFiles Include="Components\**\*.scss" Exclude="**\_*.scss" />
    </ItemGroup>

    <Target Name="BeforeBuildTasks" BeforeTargets="Compile">
        <CallTarget Targets="InstallNodejsDependencies" />
        <CallTarget Targets="BuildJavaScript" />
        <CallTarget Targets="BuildCssFiles" />
    </Target>

    <Target Name="InstallNodejsDependencies" Inputs="package.json" Outputs="node_modules\.package-lock.json">
        <Exec Command="npm install" StandardOutputImportance="high" StandardErrorImportance="high" />
    </Target>

    <Target Name="BuildJavaScript" Inputs="@(TypeScriptFiles);tsconfig.json;package.json" Outputs="wwwroot\scripts\app.js">
        <Exec Command="node_modules/.bin/tsc" StandardOutputImportance="high" StandardErrorImportance="high" />
        <Exec Condition=" '$(Environment)' == 'Production' " Command="node_modules/.bin/esbuild wwwroot/scripts/app.js --minify --outfile=wwwroot/scripts/app.js --allow-overwrite" StandardOutputImportance="high" StandardErrorImportance="high" />
    </Target>

    <Target Name="BuildCssFiles" Inputs="@(ScssFiles)" Outputs="@(ScssFiles->'%(RootDir)%(Directory)\%(Filename).css')">
        <Exec Command="node_modules/.bin/sass .:. Styles/app.scss:wwwroot/styles/app.css --style compressed --load-path=. --silence-deprecation=import" StandardOutputImportance="high" StandardErrorImportance="high" LogStandardErrorAsError="true" />
    </Target>

    <ItemGroup>
        <Content Remove="package*.json" />
        <Content Remove="tsconfig.json" />
        <None Include="package*json" />
        <None Include="tsconfig.json" />
    </ItemGroup>

</Project>

@ShahryarSaljoughi
Copy link
Contributor Author

Here are the changed parts:

  1. Added the ScssFiles :
    <ItemGroup>
        <ScssFiles Include="Components\**\*.scss" Exclude="**\_*.scss" />
    </ItemGroup>
  1. Used it to define inputs and outputs of building scss files:
    <Target Name="BuildCssFiles" Inputs="@(ScssFiles)" Outputs="@(ScssFiles->'%(RootDir)%(Directory)\%(Filename).css')">

@ysmoradi
Copy link
Member

Consider a file like _bit-css-variables.scss, whose values can be reused across multiple razor.scss files.

Anyway, assuming we address this issue, what benefits would we gain? Would the build process become faster? Are the app's styles failing to reflect the latest changes? I'm struggling to identify the problem!

The only issue I see is that BuildCssFiles runs every time, regardless of whether SCSS files have changed. However, during my tests months before, this task was fast enough.

@msynk
Copy link
Member

msynk commented Apr 23, 2025

as @ysmoradi mentioned, the time of scss files compilation can be considered negligible compared to Blazor stuff. is this optimization even noticeable?

@ShahryarSaljoughi
Copy link
Contributor Author

ShahryarSaljoughi commented Apr 23, 2025

Hi.
Here is some more context on the problem:
The pain is in the development process and debugging process, where I tend to stop and start the app frequently. Each time it takes a few minutes to build the app again which is annoying.

Even if the build time of the whole Client.Core project is nothing, the fact that its build is not skipped and is not considred up-to-date causes all other projects depending on this project considered not up-to-date and make them build again without being necessary. So what we gain if this is solved, is not the time of scss compilation but the time of compiling the whole Client.Core and also projects depending on it.

Visual Studio has its own mechanism to see if it needs to use MSBuild to build a project or not. Maybe the optimization is occurring in that step (VS), not in the actual MSBuild operation.
The difference I see, is not in the first build, but in the subsequent builds. For the single project (Client.Core) the odds are 10s without this optimization and on the other hand, it is a few milli seconds when build is actually skipped because it is assumed up to date.

As I tested, when a project is not considered up-to-date, because of a compiled css file being assumed a changed compile input file, not only the scss compilation step is performed but also the whole project gets compiled from scratch. Is there any way to make it just do the needed steps of build process? maybe just compile the scss files and skip processing cs files?

I'll come up to this issue tonight and provide a few numbers and odds about how much difference we see when these changes applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants