Closed pranavkm closed 4 years ago
Rough overview of how this will work. We can update this as necessary.
We'll add a new IHostingStartup
implementation to the ASP.NET Core shared framework in a new assembly (e.g. Microsoft.AspNetCore.AutoBrowserReload
) that ships in the dotnet watch
location, that when invoked registers an auto-reload middleware in the app early in the pipeline (middleware also in the shared framework).
The middleware detects if the request response type is HTML and if so, injects a block of JavaScript that connects to a WebSocket that will communicate when the browser page should be reloaded.
In its default, non-configured mode, the middleware will also add a WebSocket endpoint to the app (e.g. /__auto_reload) that the injected JavaScript block will connect to, and it starts monitoring the configured web root of the app along with any web roots from dependent projects (e.g. references to Razor class library projects) for changes to relevant static files (e.g. .js, .css, .jpg, .png, .ico) (NOTE: Supporting configuration of which static file types to watch might be desirable and if done should resemble the configuration of watched files for dotnet watch
via MSBuild item attributes)
Any change to these files will be treated as cause to auto-reload the browser window. If the user wishes to enable this, they only need set the required environment variable to enable discovery of the IHostingStartup
and then launching the app via dotnet run
will result in the auto-reload middleware being injected in this mode, where the app watches static files for changes and auto-reloads the browser window when they change (similar to how @RickStrahl's live reload middleware works today but without requiring application code changes).
When dotnet watch
launches the app, it will set the required environment variables to:
IHostingStartup
dotnet watch
itself is hosting, via a configuration value that the IHostingStartup
looks for (e.g. ASPNETCORE_AUTO_RELOAD_WS_ENDPOINT).If this configuration value is set, the auto-reload middleware will not add the in-app WebSocket endpoint or start monitoring for static file changes, but rather configure the JS block to connect to the endpoint address configured and hosted by dotnet watch
, e.g. https://localhost:12345/__auto_reload *
dotnet watch
will launch its own server that hosts a WebSocket endpoint that the JS block emitted by the middleware injected into the app will connect to. (NOTE: dotnet watch
will need to boot this endpoint using the ASP.NET Core HTTPS dev cert so that cross-domain connections are always allowed, might need to be configured for CORS too, not sure).
As dotnet watch
will be coordinating the file watching in this mode, it will need to start watching for relevant static file changes too (which I don't believe it does today). As stated above, The existing MSBuild-based method for configuring the watch file list should be expanded to support setting which static files to watch also.
To trigger the JS block to initiate the browser window refresh, the server (whether in-app or in dotnet watch
or possibly VS in the future) should simply terminate the WebSocket connection. The JS block should treat any disconnection of the WebSocket as indication it needs to perform the browser refresh. In the case of This should only occur after it has been determined that the application server has successfully restarted after the project has been rebuilt and restarted (e.g. by monitoring the console output for the message indicating the web server is now listening, or perhaps a more robust solution would be to have the injected dotnet watch
,IHostingStartup
signal back to dotnet watch
once the app server has finished starting, via another endpoint hosted by dotnet watch
for such coordination).
Additionally, on first launch, dotnet watch
will read the content of the project's launchSettings.json
file to see if the "launchBrowser"
flag is enabled in the profile named after the project (this flag is used today by VS). If so, it will launch the browser after the server has started (see detection discussion above) at the URL configured in the "launchUrl"
property of the same launch profile if set, otherwise at the application URL as configured in the "applicationUrl"
property (NOTE: this property is semi-colon delimited so just the first URL configured should be used).
We'll add a new IHostingStartup implementation to the ASP.NET Core shared framework in a new assembly (e.g. Microsoft.AspNetCore.AutoBrowserReload) that when invoked registers an auto-reload middleware in the app early in the pipeline (middleware also in the shared framework).
Put it in another assembly outside of the shared framework. It can be in an assembly that ships with dotnet watch
and is injected via a startup hook (injected with an environment variable). That same assembly would have the IHostingStartup
in it and dotnet watch
would inject it when it launches the process.
OK, fair. Let's scope it down to the dotnet watch
based scenarios for now and thus avoid any of the in-app WebSocket or file-watching additions. This will be a feature of dotnet watch
and we can revisit other configurations as necessary.
As a start, we'd like for a way to launch a browser, once a server the server is listening. Once we have this, we can start looking at ways to refresh the current tab rather than launching a new instance. @DamianEdwards suggested looking at https://github.com/RickStrahl/Westwind.AspnetCore.LiveReload (cc @RickStrahl)'s middleware to see how that's achieved and if that's something we could incorporate in to dotnet-watch.