LibSassBuilder icon indicating copy to clipboard operation
LibSassBuilder copied to clipboard

How to use with Hot Reload?

Open kabforks opened this issue 3 years ago • 12 comments

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.

kabforks avatar Sep 17 '21 11:09 kabforks

This would be great feature for Blazor

mikart143 avatar Sep 25 '21 17:09 mikart143

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.

johan-v-r avatar Sep 27 '21 10:09 johan-v-r

@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.

mikart143 avatar Oct 01 '21 20:10 mikart143

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?

johan-v-r avatar Oct 02 '21 08:10 johan-v-r

@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" />

Socolin avatar Nov 15 '21 05:11 Socolin

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

nanocortex avatar Feb 09 '22 20:02 nanocortex

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?

SacredSkull avatar Mar 25 '22 17:03 SacredSkull

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

  • if the file is a static file (the Watch item has a StaticWebAssetPath metadata, e.g. all Content files under wwwroot/) then reload the browser window
  • if the file extension is .razor.css or .cshtml.css then rebuild scoped css and apply changes without restarting the app
  • if the file extension is .cs or .razor or .cshtml then use Edit&Continue on the c# source to apply changes (if it's a supported edit)
  • everything else is considered a "rude" edit (i.e. prompt to restart the entire app)

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.

bachratyg avatar May 06 '22 14:05 bachratyg

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

warappa avatar Jun 18 '22 23:06 warappa

@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" />

bachratyg avatar Jun 19 '22 08:06 bachratyg

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

warappa avatar Jun 19 '22 09:06 warappa

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?

dawiduniec avatar Nov 30 '22 13:11 dawiduniec