Trigger live reload feature after successful builds in VS
This commit is contained in:
parent
5dfa857eab
commit
71a3e31799
|
|
@ -59,10 +59,16 @@
|
|||
-->
|
||||
<Target Name="_BlazorIssueLiveReloadNotification"
|
||||
AfterTargets="Build"
|
||||
Condition="'$(UseBlazorLiveReloading)'=='true' AND '$(_BlazorDidCopyFilesToOutputDirectory)'=='true' AND '$(BuildingInsideVisualStudio)'!='true'">
|
||||
<!-- Touch the signal file to trigger a reload -->
|
||||
<WriteLinesToFile File="$(ProjectDir)$(OutputPath)$(BlazorBuildCompletedSignalPath)" Lines="_" />
|
||||
<Delete Files="$(ProjectDir)$(OutputPath)$(BlazorBuildCompletedSignalPath)" />
|
||||
Condition="'$(UseBlazorLiveReloading)'=='true' AND '$(_BlazorDidCopyFilesToOutputDirectory)'=='true'">
|
||||
<PropertyGroup>
|
||||
<_BlazorBuildCompletedSignalFullPath>$(ProjectDir)$(OutputPath)$(BlazorBuildCompletedSignalPath)</_BlazorBuildCompletedSignalFullPath>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
If this is a command-line build, touch the signal file to trigger a reload.
|
||||
If it's a VS build, then the VS extension will write the signal file instead.
|
||||
-->
|
||||
<WriteLinesToFile Condition="'$(BuildingInsideVisualStudio)'!='true'" File="$(_BlazorBuildCompletedSignalFullPath)" Lines="_" />
|
||||
<Delete Condition="'$(BuildingInsideVisualStudio)'!='true'" Files="$(_BlazorBuildCompletedSignalFullPath)" />
|
||||
</Target>
|
||||
|
||||
<!-- Preparing blazor files for output:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
|
||||
namespace Microsoft.VisualStudio.BlazorExtension
|
||||
{
|
||||
|
|
@ -11,8 +12,24 @@ namespace Microsoft.VisualStudio.BlazorExtension
|
|||
[PackageRegistration(UseManagedResourcesOnly = true)]
|
||||
[AboutDialogInfo(PackageGuidString, "ASP.NET Core Blazor Language Services", "#110", "112")]
|
||||
[Guid(BlazorPackage.PackageGuidString)]
|
||||
[ProvideAutoLoad(UIContextGuids80.SolutionExists)]
|
||||
public sealed class BlazorPackage : Package
|
||||
{
|
||||
public const string PackageGuidString = "d9fe04bc-57a7-4107-915e-3a5c2f9e19fb";
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
RegisterLiveReloadBuildWatcher();
|
||||
}
|
||||
|
||||
private void RegisterLiveReloadBuildWatcher()
|
||||
{
|
||||
// No need to unadvise, as this only happens once anyway
|
||||
ThreadHelper.ThrowIfNotOnUIThread();
|
||||
var buildManager = (IVsSolutionBuildManager)GetService(typeof(SVsSolutionBuildManager));
|
||||
var hr = buildManager.AdviseUpdateSolutionEvents(new LiveReloadBuildWatcher(), out var cookie);
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.VisualStudio.ProjectSystem.Properties;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using Microsoft.VisualStudio.Shell.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.VisualStudio.BlazorExtension
|
||||
{
|
||||
internal class LiveReloadBuildWatcher : IVsUpdateSolutionEvents2
|
||||
{
|
||||
const string BlazorProjectCapability = "Blazor";
|
||||
|
||||
private bool _isListeningForProjectBuilds = false;
|
||||
private List<string> _signalFilePathsToNotify = new List<string>();
|
||||
|
||||
public int UpdateSolution_Begin(ref int pfCancelUpdate)
|
||||
{
|
||||
_signalFilePathsToNotify.Clear();
|
||||
_isListeningForProjectBuilds = true;
|
||||
return VSConstants.S_OK;
|
||||
}
|
||||
|
||||
public int UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand)
|
||||
{
|
||||
_isListeningForProjectBuilds = false;
|
||||
|
||||
foreach (var fullPath in _signalFilePathsToNotify)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(fullPath, string.Empty);
|
||||
File.Delete(fullPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AttemptLogError($"Blazor live reloading was unable to write to the signal " +
|
||||
$"file at {fullPath}. To disable live reloading, set the property " +
|
||||
$"'UseBlazorLiveReloading' to 'false' in your project file." +
|
||||
$"\nThe exception was: {ex.Message}\n{ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
|
||||
return VSConstants.S_OK;
|
||||
}
|
||||
|
||||
private void AttemptLogError(string message)
|
||||
{
|
||||
ThreadHelper.ThrowIfNotOnUIThread();
|
||||
var outputWindow = (IVsOutputWindow)Package.GetGlobalService(typeof(SVsOutputWindow));
|
||||
if (outputWindow != null)
|
||||
{
|
||||
outputWindow.GetPane(VSConstants.OutputWindowPaneGuid.BuildOutputPane_guid, out var pane);
|
||||
if (pane != null)
|
||||
{
|
||||
pane.OutputString(message);
|
||||
pane.Activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int UpdateSolution_StartUpdate(ref int pfCancelUpdate)
|
||||
=> VSConstants.S_OK;
|
||||
|
||||
public int UpdateSolution_Cancel()
|
||||
=> VSConstants.S_OK;
|
||||
|
||||
public int OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy)
|
||||
=> VSConstants.S_OK;
|
||||
|
||||
public int UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel)
|
||||
=> VSConstants.S_OK;
|
||||
|
||||
public int UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel)
|
||||
{
|
||||
if (_isListeningForProjectBuilds
|
||||
&& fSuccess == 1 // i.e., build succeeded
|
||||
&& pHierProj.IsCapabilityMatch(BlazorProjectCapability))
|
||||
{
|
||||
var configuredProject = ((IVsBrowseObjectContext)pCfgProj).ConfiguredProject;
|
||||
var projectLockService = configuredProject
|
||||
.UnconfiguredProject
|
||||
.ProjectService
|
||||
.Services
|
||||
.ProjectLockService;
|
||||
|
||||
ThreadHelper.JoinableTaskFactory.Run(async delegate
|
||||
{
|
||||
using (var access = await projectLockService.ReadLockAsync())
|
||||
{
|
||||
var project = await access.GetProjectAsync(configuredProject);
|
||||
|
||||
// Now we can evaluate MSBuild properties
|
||||
var signalFileFullPath = project.GetPropertyValue("_BlazorBuildCompletedSignalFullPath");
|
||||
if (!string.IsNullOrEmpty(signalFileFullPath))
|
||||
{
|
||||
_signalFilePathsToNotify.Add(signalFileFullPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return VSConstants.S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -275,6 +275,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="AboutDialogInfoAttribute.cs" />
|
||||
<Compile Include="BlazorPackage.cs" />
|
||||
<Compile Include="LiveReloadBuildWatcher.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
|||
Loading…
Reference in New Issue