diff --git a/README.md b/README.md index e1ac95d54..d2d4e0781 100644 --- a/README.md +++ b/README.md @@ -144,18 +144,22 @@ existing surveyed tools - [.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) - [Node.js 22.13.1 (LTS)](https://nodejs.org/en/blog/release/v22.13.1) -## Live Reload Markdown files in the `docs` folder: -```shell -dotnet run --project src/docs-builder -- serve -``` -## Automatically rebuild changes to `src/Elastic.Markdown/Assets` JS and CSS files: +## Continuously build all assets during development. + ```shell -cd src/Elastic.Markdown -npm ci -npm run watch +./build.sh watch ``` +This will monitor code, cshtml template files & static files and reload the application +if any changes. + +Web assets are reloaded through `parcel watch` and don't require a recompilation. + +Markdown files are refreshed automatically through livereload + +Code or layout changes will relaunch the server automatically + # Release Process This section outlines the process for releasing a new version of this project. diff --git a/build/CommandLine.fs b/build/CommandLine.fs index faf15f82f..9af384bd5 100644 --- a/build/CommandLine.fs +++ b/build/CommandLine.fs @@ -17,7 +17,8 @@ type Build = | [] Test | [] Format - + | [] Watch + | [] Lint | [] PristineCheck | [] ValidateLicenses @@ -46,7 +47,9 @@ with | Release -> "runs build, tests, and create and validates the packages shy of publishing them" | Publish -> "Publishes artifacts" | Format -> "runs dotnet format" - + + | Watch -> "runs dotnet watch to continuous build code/templates and web assets on the fly" + // steps | Lint | PristineCheck diff --git a/build/Targets.fs b/build/Targets.fs index 88d32b137..61055a6b4 100644 --- a/build/Targets.fs +++ b/build/Targets.fs @@ -35,6 +35,8 @@ let private version _ = let private format _ = exec { run "dotnet" "format" "--verbosity" "quiet" } +let private watch _ = exec { run "dotnet" "watch" "--project" "src/docs-builder" "--no-hot-reload" "--" "serve" } + let private lint _ = match exec { exit_code_of "dotnet" "format" "--verify-no-changes" @@ -167,6 +169,7 @@ let Setup (parsed:ParseResults) = release | Format -> Build.Step format + | Watch -> Build.Step watch // steps | Lint -> Build.Step lint diff --git a/src/Elastic.Markdown/Assets/styles.css b/src/Elastic.Markdown/Assets/styles.css index ef9a0f7ba..bd36c718c 100644 --- a/src/Elastic.Markdown/Assets/styles.css +++ b/src/Elastic.Markdown/Assets/styles.css @@ -5,4 +5,4 @@ @import "legacy/togglebutton.css"; @import "legacy/sphinx-design.min.css"; @import "legacy/custom.css"; -@import "legacy/atom-one-light.css"; \ No newline at end of file +@import "legacy/atom-one-light.css"; diff --git a/src/Elastic.Markdown/Elastic.Markdown.csproj b/src/Elastic.Markdown/Elastic.Markdown.csproj index 608dc8946..5bd99ca68 100644 --- a/src/Elastic.Markdown/Elastic.Markdown.csproj +++ b/src/Elastic.Markdown/Elastic.Markdown.csproj @@ -22,7 +22,7 @@ Documentation: https://learn.microsoft.com/en-us/visualstudio/msbuild/incremental-builds?WT.mc_id=DT-MVP-5003978 --> - + @@ -33,15 +33,17 @@ MSBuild runs NpmInstall before this task because of the DependsOnTargets attribute. --> - + + + - - - - + + + + @@ -58,4 +60,5 @@ + diff --git a/src/docs-builder/Http/DocumentationWebHost.cs b/src/docs-builder/Http/DocumentationWebHost.cs index 82549bbf5..ee5711d9e 100644 --- a/src/docs-builder/Http/DocumentationWebHost.cs +++ b/src/docs-builder/Http/DocumentationWebHost.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using System.Diagnostics.CodeAnalysis; using System.IO.Abstractions; +using System.Reflection; using Documentation.Builder.Diagnostics; using Documentation.Builder.Diagnostics.Console; using Documentation.Builder.Diagnostics.LiveMode; @@ -28,9 +29,11 @@ public class DocumentationWebHost private readonly WebApplication _webApplication; private readonly BuildContext _context; + private readonly ILogger _logger; public DocumentationWebHost(string? path, int port, ILoggerFactory logger, IFileSystem fileSystem) { + _logger = logger.CreateLogger(); var builder = WebApplication.CreateSlimBuilder(); builder.Logging.ClearProviders(); @@ -52,8 +55,8 @@ public DocumentationWebHost(string? path, int port, ILoggerFactory logger, IFile }); builder.Services.AddSingleton(_ => new ReloadableGeneratorState(_context.SourcePath, null, _context, logger)); builder.Services.AddHostedService(); - - //builder.Services.AddSingleton(logger); + if (IsDotNetWatchBuild()) + builder.Services.AddHostedService(); builder.WebHost.UseUrls($"http://localhost:{port}"); @@ -61,6 +64,8 @@ public DocumentationWebHost(string? path, int port, ILoggerFactory logger, IFile SetUpRoutes(); } + private bool IsDotNetWatchBuild() => + Environment.GetEnvironmentVariable("DOTNET_WATCH") is not null; public async Task RunAsync(Cancel ctx) { diff --git a/src/docs-builder/Http/ParcelWatchService.cs b/src/docs-builder/Http/ParcelWatchService.cs new file mode 100644 index 000000000..d942a50a8 --- /dev/null +++ b/src/docs-builder/Http/ParcelWatchService.cs @@ -0,0 +1,44 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Diagnostics; +using Elastic.Markdown.IO; +using Microsoft.Extensions.Hosting; + +namespace Documentation.Builder.Http; + +public class ParcelWatchService : IHostedService +{ + private Process? _process; + + public Task StartAsync(CancellationToken cancellationToken) + { + _process = Process.Start(new ProcessStartInfo + { + FileName = "npm", + Arguments = "run watch", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = Path.Combine(Paths.Root.FullName, "src", "Elastic.Markdown") + })!; + + _process.EnableRaisingEvents = true; + _process.OutputDataReceived += (_, e) => Console.WriteLine($"[npm run watch]: {e.Data}"); + _process.ErrorDataReceived += (_, e) => Console.WriteLine($"[npm run watch]: {e.Data}"); + + _process.BeginOutputReadLine(); + _process.BeginErrorReadLine(); + + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _process?.Kill(entireProcessTree: true); + _process?.Kill(); + return Task.CompletedTask; + } +}