johan-v-r / LibSassBuilder

Sass builder for .NET projects
MIT License
99 stars 14 forks source link

How to use with Hot Reload? #31

Open kabforks opened 2 years ago

kabforks commented 2 years ago

Hello, and thanks for this wonderful tool.

Currently, I'm working with a lot of SCSS files, and after each edit I ALT+TAB out to my Terminal and enter lsb. Then lsb transforms all my .scss files into .css. dotnet will pick up these file changes, and then the gui is refreshed with new and fancy styles.

Is it possible to watch for changes in *.scss files and run lsb upon save (a change in scss-file)? It's getting tedious to run lsb upon each edit...

I'm using 6.0.0-rc.1.21452.15.

mikart143 commented 2 years ago

This would be great feature for Blazor

johan-v-r commented 2 years ago

Hi there - yes the *.scss files are watched by default with this NuGet package installed in your .NET project.

You shouldn't have to use (or even install) the CLI tool for this purpose.

mikart143 commented 2 years ago

@johan-v-r I do not know if I understood you correctly. I can run my app, edit sass/scss file and this wil be automatically converted to css ? I tried this with blazor server on .Net 5 and It was not working.

johan-v-r commented 2 years ago

If you run your app with dotnet watch then yes it will rebuild when you save a Sass file. If you don't come right, could you create a sample project so I can replicate & test?

Socolin commented 2 years ago

@johan-v-r Hello, on my side with dotnet watch it's working but it do a full rebuild on each change on .scss files is that normal ? if yes I would be nice to to get it to avoid rebuild each time.

watch : File changed: /xxxxxx/Component.razor.scss.
watch : Exited
watch : Building...
<PackageReference Include="LibSassBuilder" Version="1.6.4" />
nanocortex commented 2 years ago

Has someone managed to use dotnet watch with this plugin, without full rebuild on each change?

SacredSkull commented 2 years ago

Struggling to get this working as well.

Just in case you're not aware @johan-v-r this is Hot Reload we're talking about (not auto-builds) - specifically .NET/Blazor Watch's handling of Browser resource hot reloads:

info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/.../Personal Projects/BlazorTutorial/
watch : File changed: /Users/.../Personal Projects/BlazorTutorial/Shared/NavMenu.razor.css.
watch : Hot reload of scoped css succeeded

That is what happens if you change a single CSS file and is what is referred to as a hot-reload - the resource/content file is updated on the server and re-sent to the browser without any full project build occuring.

On the otherhand, here is what happens if I do the same to a SCSS file:

info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/.../Personal Projects/BlazorTutorial/
watch : File changed: /Users/.../Personal Projects/BlazorTutorial/Shared/MainLayout.razor.scss.
watch : Do you want to restart your app - Yes (y) / No (n) / Always (a) / Never (v)?

It seems like your plugin enforces some strict watch rules because ignoring changes to SCSS files does not work (same output as above):

<ItemGroup>
  <None Include="**/*.scss" />
</ItemGroup>

I don't know too much about MSBuild and its targets but is it possible to trigger this package's build without requiring a full watch/build on SCSS files?

bachratyg commented 2 years ago

As far as I can tell when hot reload (dotnet watch without args) detects a file change the following happens:

All of this is more or less hardwired in dotnet-watch, adding sass as Watch items simply won't work, a change is always considered a rude edit. However a separate dotnet-watch instance can be configured to handle sass like this:

Add this to your main csproj:

<ItemGroup>
    <!-- exclude sass files from main dotnet watch -->
    <SassFile Update="@(SassFile)" Watch="false" />
</ItemGroup>
<!-- expose sass source files to helper project -->
<Target Name="CollectSassItems" Outputs="@(SassFile)" />

Create a new proj file e.g. Sass.proj next to your csproj or sln or wherever. This is a helper project that configures dotnet-watch to handle sass only. Unfortunately dotnet-watch cannot handle different project configurations, a separate project is needed.

<Project DefaultTargets="SassBuild">
    <PropertyGroup>
        <CustomCollectWatchItems>$(CustomCollectWatchItems);SassCollectWatchItems</CustomCollectWatchItems>
        <!-- this is needed or else the watch process fails with NRE -->
        <TargetFramework>net6.0</TargetFramework>
        <!-- Path to your project here with the sass files to compile -->
        <SassProject>Path\To\YourProjectThatHasSassToBuild.csproj</SassProject>
    </PropertyGroup>

    <!-- collect sass files from main project -->
    <Target Name="SassCollectWatchItems">
        <MSBuild Projects="$(SassProject)" Targets="CollectSassItems" BuildInParallel="true">
            <Output TaskParameter="TargetOutputs" ItemName="Watch" />
        </MSBuild>
    </Target>

    <!-- invoke sass compilation in the main project -->
    <Target Name="SassBuild">
        <MSBuild Projects="$(SassProject)" Targets="LibSass_DetermineBuildNeeded;LibSass_BuildArgsFromFileList;LibSass_Build" BuildInParallel="true" />
    </Target>

    <Import Project="$(MSBuildExtensionsPath)\Microsoft.Common.targets"/>
</Project>

then finally run

dotnet watch --project Sass.proj msbuild

This will run the LibSass pipeline for every changed sass, then the main dotnet watch will pick up the changed sass output.

warappa commented 2 years ago

I tried @bachratyg's workaround, but dotnet watch still reloaded my whole application on each scss-file change.

To make dotnet watch really ignore scss-file changes, not only you must use

<ItemGroup>
    <!-- exclude sass files from main dotnet watch -->
    <SassFile Update="@(SassFile)" Watch="false" />
</ItemGroup>

but also add the same for Content elements. So the resulting edit is:

<ItemGroup>
    <!-- exclude sass files from main dotnet watch -->
    <SassFile Update="@(SassFile)" Watch="false" />
        <!-- tell main dotnet watch to really ignore scss files -->
    <Content Update="@(SassFile)" Watch="false" />
</ItemGroup>

Info

LibSassBuilder: 2.0.1 .NET: 6.0

bachratyg commented 2 years ago

@warappa you may have scss under wwwroot that gets picked up as Content and triggers a browser refresh on change. Since you probably don't want them published you can simply exclude them:

<Content Remove="wwwroot/**/*.scss" />
warappa commented 2 years ago

@bachratyg You're right, excluding them is actually better 👍

dawiduniec commented 1 year ago

My VS is picking changes in css files automatically, but build of sass files happen only on run, is there a way to force it to compile on save?