Skip to content

Commit

Permalink
Simplify by refreshing all CSS files when any change
Browse files Browse the repository at this point in the history
  • Loading branch information
SteveSandersonMS committed Apr 14, 2022
1 parent 2f2f7c0 commit 5865584
Show file tree
Hide file tree
Showing 8 changed files with 20 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private void StartWebViewCoreIfPossible()
contentRootDir,
hostPageRelativePath);

StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager, WebKitWebViewClient.AppOrigin);
StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager);

VirtualView.BlazorWebViewInitializing(new BlazorWebViewInitializingEventArgs());
VirtualView.BlazorWebViewInitialized(new BlazorWebViewInitializedEventArgs
Expand Down
2 changes: 1 addition & 1 deletion src/BlazorWebView/src/Maui/Android/WebKitWebViewClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class WebKitWebViewClient : WebViewClient
// Using an IP address means that WebView doesn't wait for any DNS resolution,
// making it substantially faster. Note that this isn't real HTTP traffic, since
// we intercept all the requests within this origin.
internal static readonly string AppOrigin = $"https://{BlazorWebView.AppHostAddress}/";
private static readonly string AppOrigin = $"https://{BlazorWebView.AppHostAddress}/";

private static readonly Uri AppOriginUri = new(AppOrigin);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private void StartWebViewCoreIfPossible()
hostPageRelativePath,
this);

StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager, WebView2WebViewManager.AppOrigin);
StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager);

if (RootComponents != null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/BlazorWebView/src/Maui/iOS/BlazorWebViewHandler.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private void StartWebViewCoreIfPossible()
contentRootDir,
hostPageRelativePath);

StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager, AppOrigin);
StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager);

if (RootComponents != null)
{
Expand Down
47 changes: 13 additions & 34 deletions src/BlazorWebView/src/SharedSource/StaticContentHotReloadManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,9 @@ internal static class StaticContentHotReloadManager
private static readonly Dictionary<(string AssemblyName, string RelativePath), (string? ContentType, byte[] Content)> _updatedContent = new()
{
{ (ApplicationAssemblyName, "_framework/static-content-hot-reload.js"), ("text/javascript", Encoding.UTF8.GetBytes(@"
export function notifyContentUpdated(urlWithinOrigin) {
export function notifyCssUpdated() {
const allLinkElems = Array.from(document.querySelectorAll('link[rel=stylesheet]'));
const absoluteUrl = document.location.origin + urlWithinOrigin;
const matchingLinkElems = allLinkElems.filter(x => x.href === absoluteUrl);
// If we can't find a matching link element, that probably means it's a CSS file imported via @import
// from some other CSS file. We can't know which other file imports it, so refresh them all.
const linkElemsToUpdate = matchingLinkElems.length > 0 || !absoluteUrl.endsWith('.css')
? matchingLinkElems
: allLinkElems;
linkElemsToUpdate.forEach(tag => tag.href += '');
allLinkElems.forEach(elem => elem.href += '');
}
")) }
};
Expand All @@ -63,12 +54,11 @@ public static void UpdateContent(string assemblyName, string relativePath, byte[
OnContentUpdated?.Invoke(assemblyName, relativePath);
}

public static void AttachToWebViewManagerIfEnabled(WebViewManager manager, string assemblyName, string contentRoot)
public static void AttachToWebViewManagerIfEnabled(WebViewManager manager)
{
if (MetadataUpdater.IsSupported)
{
var parameters = new Dictionary<string, object?> { { nameof(StaticContentUpdater.ContentRoot), contentRoot } };
manager.AddRootComponentAsync(typeof(StaticContentUpdater), "body::after", ParameterView.FromDictionary(parameters));
manager.AddRootComponentAsync(typeof(StaticContentUpdater), "body::after", ParameterView.Empty);
}
}

Expand Down Expand Up @@ -125,7 +115,6 @@ private sealed class StaticContentUpdater : IComponent, IDisposable

[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
[Inject] private ILoggerFactory LoggerFactory { get; set; } = default!;
[Parameter] public string ContentRoot { get; set; } = default!;

public void Attach(RenderHandle renderHandle)
{
Expand All @@ -150,23 +139,16 @@ private async Task NotifyContentUpdatedAsync(string assemblyName, string relativ
{
await using var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./_framework/static-content-hot-reload.js");

if (string.Equals(assemblyName, ApplicationAssemblyName, StringComparison.Ordinal))
{
if (relativePath.StartsWith(ContentRoot + "/", StringComparison.Ordinal))
{
var pathWithinContentRoot = relativePath.Substring(ContentRoot.Length);
await module.InvokeVoidAsync("notifyContentUpdated", pathWithinContentRoot);
}
}
else
// In the future we might want to hot-reload other content types such as images, but currently the tooling is
// only expected to notify about CSS files. If it notifies us about something else, we'd need different JS logic.
if (string.Equals(".css", Path.GetExtension(relativePath), StringComparison.Ordinal))
{
if (relativePath.StartsWith("wwwroot/", StringComparison.Ordinal))
{
var pathWithinContentRoot = relativePath.Substring("wwwroot/".Length);
await module.InvokeVoidAsync("notifyContentUpdated", $"/_content/{assemblyName}/{pathWithinContentRoot}");
}
// We could try to supply the URL of the modified file, so the JS-side logic could only update the affected
// stylesheet. This would reduce flicker. However, this involves hardcoding further details about URL conventions
// (e.g., _content/AssemblyName/Path) and accounting for configurable content roots. To reduce the chances of
// CSS hot reload being broken by customizations, we'll have the JS-side code refresh all stylesheets.
await module.InvokeVoidAsync("notifyCssUpdated");
}

}
catch (Exception ex)
{
Expand All @@ -175,10 +157,7 @@ private async Task NotifyContentUpdatedAsync(string assemblyName, string relativ
}

public Task SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);
return Task.CompletedTask;
}
=> Task.CompletedTask;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal class WebView2WebViewManager : WebViewManager
/// <summary>
/// Gets the application's base URI. Defaults to <c>https://0.0.0.0/</c>
/// </summary>
protected internal static readonly string AppOrigin = $"https://{AppHostAddress}/";
protected static readonly string AppOrigin = $"https://{AppHostAddress}/";

private static readonly Uri AppOriginUri = new(AppOrigin);

Expand Down
2 changes: 1 addition & 1 deletion src/BlazorWebView/src/WindowsForms/BlazorWebView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ private void StartWebViewCoreIfPossible()
(args) => BlazorWebViewInitializing?.Invoke(this, args),
(args) => BlazorWebViewInitialized?.Invoke(this, args));

StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager, WebView2WebViewManager.AppOrigin, contentRootRelativePath);
StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager);

foreach (var rootComponent in RootComponents)
{
Expand Down
2 changes: 1 addition & 1 deletion src/BlazorWebView/src/Wpf/BlazorWebView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ private void StartWebViewCoreIfPossible()
(args) => BlazorWebViewInitializing?.Invoke(this, args),
(args) => BlazorWebViewInitialized?.Invoke(this, args));

StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager, WebView2WebViewManager.AppOrigin, contentRootDirRelativePath);
StaticContentHotReloadManager.AttachToWebViewManagerIfEnabled(_webviewManager);

foreach (var rootComponent in RootComponents)
{
Expand Down

0 comments on commit 5865584

Please sign in to comment.