toddams / RazorLight

Template engine based on Microsoft's Razor parsing engine for .NET Core
Apache License 2.0
1.5k stars 259 forks source link

MSBuild Razor Compiler #333

Open robdmoore opened 4 years ago

robdmoore commented 4 years ago

Is your feature request related to a problem? Please describe. No.

Describe the solution you'd like Automatically compile all .cshtml files into .cs files in-place so you can interact with them statically and not need to worry about compilation performance, runtime compilation errors, caching, etc.

I need it to replace the existing similar functionality I used RazorGenerator for with my ChameleonForms library, which I'm currently converting to .NET Core 3.1. We used Razor Generator to create the template files we used e.g. https://github.com/MRCollective/ChameleonForms/tree/master/ChameleonForms/Templates/Default.

Additional context I've implemented an Open Source library here: https://github.com/MRCollective/MSBuildRazorCompiler that wraps parts of RazorLight. When you install the NuGet package for my library into your project it adds an MSBuild task that compiles all of your .cshtml files just before CoreCompile. I also provide an extension method on top of ITemplatePage that then allows you to render a result with a model / viewbag.

The reason why I'm raising this issue is so we can have an open discussion about it. I'd love to know your thoughts on the library I've built. There are also a couple of places where I think some well placed PRs into RazorLight will make the code in MSBuildRazorCompiler much easier to write, particularly:

I'd also love to get advice on a better way to do this: https://github.com/MRCollective/MSBuildRazorCompiler/blob/master/MSBuildRazorCompiler/Program.cs#L62.

Thanks!

cc @mattdavies

jzabroski commented 4 years ago

@robdmoore @mattdavies I'm all for joining forces and creating one Razor project that:

  1. Doesn't require the whole ASP.NET Runtime FrameworkReference to work
  2. Doesn't require an ASP.NET Core Runtime Host environment, e.g., can be run in something lightweight like a Bullseye executable that launches targets, where the targets are things like email campaigns powered by RazorLight templates.
  3. Can support build-time compilation
  4. Has more than one active contributor

I'm curious who your largest customers are right now - I tried to look it up on nuget.org and didn't see anything under GitHub Usage. RazorLight's largest customer is probably a site that books discount auto travel, followed by the GitHub project FluentEmail. I use RazorLight internally on my own projects to provide type-safe email templates.

A generally useful overview of .NET Core Razor was given by Dave Glick here: https://daveaglick.com/posts/the-bleeding-edge-of-razor - Dave is a bit uncomfortable with how often ASP.NET Tooling team changes the API surface of Razor. He runs the Statiq and Wyam.io projects for static site generation.

I'd also love to get advice on a better way to do this: https://github.com/MRCollective/MSBuildRazorCompiler/blob/master/MSBuildRazorCompiler/Program.cs#L62.

I'm not 100% sure what you want to do better here, or what you're asking about. I think you're asking about #304 , but you might also be asking about how to statically resolve embedded resources in a clean manner? For the latter, I created an internal utility at work that reverses the path name and searches for the longest common subsequence between what the user provided and what embeddedresources were available in the shipped dll. This allows me to throw a more useful error message than just "oops, can't find it", and instead say something like, "The closest matches were: {0}" where {0} is a string.Join of all the partial matches. Could be further improved by using Levenshtein distance to check for basic character transposition typos.

In the spirit of feedback: I'd also love feedback on how to cut down on issues related to .NET assembly link-load errors. This is by far the most common error users experience. I don't know about you, but, for me, it has taken me ~3 years of .NET Core development to wrap my head around all the pitfalls around post-assemblyBindingRedirect world (not that assemblyBindingRedirect-era .NET was any easier). I still think there might be some scenarios I have not thought through or understood. Maintaining this project and FluentMigrator, I run into these support questions a lot and it took me a long time to troubleshoot them. Some of the bugs related to link-load are just plain nasty: For example, one customer of FluentMigrator ran into a silent failure where they ran FluentMigrator.MSBuild 3.2.1 task against a FluentMigrator migration assembly linked to FluentMigrator 3.2.6. While this can't be supported, I am wondering if there is something I could check for to call Environment.FailFast? Or maybe something like throw new DidYouReadTheFaqException(ex, "Check the FAQ, yo!");? The issue really comes up for any application that uses reflection to discover what classes to load/use, so I'm somewhat surprised other OSS projects don't seem to be complaining about this usability issue. Either I'm missing an obvious solution "everyone knows about", or people have stopped using Attributes altogether precisely for these stupid link-load issues, or some other thing I'm not considering.

jzabroski commented 4 years ago

Additionally, before I volunteered to help with this project @toddams was working on RazorLight.Precompile, but it's never been pushed as a nuget package. You can see one intrepid user trying to use it on their own, here: https://github.com/toddams/RazorLight/issues/144#issue-290989610

The intrepid user's suggestions are sound, and might make your lift in MSBuildRazorGenerator a lot lighter, but I haven't studied this area of the project too closely since its not on any support. As part of helping Ivan out, my strategy was to first breath life into old issues and try to keep the community interested in what we've published so far. Holding a user base is vital to sharing the workload amongst contributors, as long-term it raises the visibility of the project and adds contributions from outside the core dev team.

robdmoore commented 4 years ago

(btw - I did get this and will reply :), just knee deep in this epic PR atm: https://github.com/MRCollective/ChameleonForms/pull/162)

jzabroski commented 4 years ago

No worries. I'm not measuring responses with a Timex.

jzabroski commented 4 years ago

@robdmoore Just a nudge. I am slowly getting around to improving RazorLight more. I just pushed 2.0.0-beta8. It fixes the annoying section issue.