Blazor我的后端是AspNetCore且很坚定可能这就是生态锁定即使现代前端有了TS加持但毕竟是胶水层且每个框架都或多或少有漏网之鱼这些都影响了强类型的体感和安全感我真得很喜欢RazorPages简单直接但是生态要和JS强绑定。出早了如果晚一些缺脚的交互部分能够使用HTMX和Alpine的理念补上生态建起来说不定都不会有Blazor这种怪咖折腾一圈后让我对如何使用Blazor有新的思考这也是本文的主题2、初看Blazor很香但深度使用后总有尾大不掉之感Blazor是在现代前端框架之后建立起来的所以语法上即有Vue模板语法的简洁又有JSX的灵活Blazor从MVC、RazorPages演化而来天生就有服务端的基因并在.NET8的BlazorWebApp中实现SSR、Server和Wasm的集成。MVC/Razorpages的多年积累使Blazor比之Nuxt/Next等主流前端元框架在服务端领域有着更加精彩的表现但是Blazor先天的缺陷依然在那里1BlazorServer因网络条件引发的交互延迟、断连服务端线路的内存消耗2BlazorWasm首次浏览几十M的负载以及每次在浏览器启动Net运行时的时滞。给人感觉就是给了你解决方案了但问题都没解决干净3Auto估计没人愿意碰这东西BlazorWebApp刚出时社区对Auto是很关注的反而忽略了SSR。但是现在好像很少人谈Auto了SSR则更多的被关注、讨论和实验。这一继承自MVC/RazorPages的SSR在增强式导航加持下成为Blazor生态中最稳的选择而且.NET11还有一大批MVC/RazorPages上的特性将被转移到SSR体感能进一步升级。3、下面是我对如何使用Blazor的新思考和新实践总的原则是将SSR立于主导尽可能缩小Server/Wasm交互的使用范围无论使用哪种交互方式将交互位置设为“每页/每组件”很多人可能用了很久Blazor也不清楚全局交互和每页交互的区别。先说结论这个选择影响非常大它决定了底层浏览器的行为进而影响导航、认证、预渲染等核心功能。交互位置选择“每页/组件”后布局页不要放交互式组件只要放了交互式组件任何页面都要建立SignalR连接或者下载和启动WASM完全失去SSR立于主导这一原则。布局页的客户端交互功能交给CSS和Alpine.js实现如导航栏收起展开、折叠菜单等动态功能。页面首先考虑SSR如果要上客户端交互先考虑Alpine如果要上服务端交互先考虑HTMX。SSRHTMXAlpine的组合应该能解决十之八九的功能需求剩下的复杂交互才交给Server或者WASM并尽量划小到组件范围。对于最多只会有百来个人使用的后台管理可以全部页面开Server交互但交互位置仍然选择为“每页/每组件”因为这会极大的减少认证的复杂性进而提升认证的稳定性。关于预渲染.NET10之前是个大问题但现在不是啥问题了。一是我们以SSR为主导大部分页面是不会有预渲染的二是现在有PersistState基本解决交互页面预渲染带来的问题。但我认为预渲染仍然是一个需要每页斟酌选择的问题比如后台管理页面自然是可以全部关闭的。在此模式下Server交互的内存占用有望砍掉80%在此基础上你的钱带子也有能力集群部署将服务器尽可能的部署到离用户更近的位置近而解决Server交互延迟的问题。而WASM目前这个方案仅可以减少负载而负载从来不是WASM的最大问题希望未来将WASM的运行时切到CoreCLR后能带来真正近JS的体验。4、全局交互和每页交互究竟有啥区别全局交互下1首次请求有预渲染时服务端渲染请求页面为HTML并发给浏览器之后在浏览器水合、建立交互水合过程中会再次执行组件生命周期PersistState就是用于处理这个过程中二次请求数据的问题无预渲染时Server交互会下载一个JS脚本WASM则要下载大负载然后水合、建立交互、渲染页面所以这个过程会有空白Server交互的空白时间短很多。2此后请求在浏览器端被Server或Wasm拦截进行差量更新具体原理大家都懂。但这里有一个关键细节就是之后的导航请求不会再走浏览器到服务器的请求响应了。认证方式中最简单也最安全的认证就是Cookie登陆成功后SetCookie浏览器自动保存之后请求浏览器自动携带。由于不再走这个过程所以就要将认证状态保存到Server的线路中或Wasm的浏览器运行时中给认证带来很大的麻烦需要一大堆辅助工具和抽象。每页交互无论是首次请求还是后续请求无论是SSR还是Server或WASM交互一律都走浏览器到服务器的请求响应心智模式极大降低。比如认证你知道每次都一定会走Cookie认证绝大多数情况下你不再需要考虑SignalR线路或者WASM运行时中保存和使用认证状态的问题。5、如何以SSR为主导SSR页面如何添加交互功能如何集成HTMX和Alpine这是这篇文章的重点也是我的实践核心问题其实就一个如何集成HTMX和Alpine。这是一个完整的解决方案开始大量贴代码。1App.razor引入HTMX、Alpine和胶水代码HTMX和Alpine包直接使用CDN引入因为只有几K到几十KCDN好用点击查看代码2www/htmx-alpine-integration.jsSSRHTMXAlpine的胶水代码。需要胶水代码的主要原因是因为SSR的增强式导航它会对比DOM有变化的才更新这会影响HTMX和Alpine对DOM的监听和挂载。我们要做的是即保留SSR的增强式导航又让HTMX和Alpine对DOM的感知和普通请求响应一样。好在SSR增强式导航提供了增强式导航前、导航后等事件我们可以主动介入HTMX和Alpine的挂载其中HTMX无状态所以比较简单而Alpine会相对复杂些。点击查看代码3MainLayout.razor布局页。我让AI模仿MudBlazor的布局页组件创建了MitLayout、MitDrawer、MitMain、MitMainContent、MitAppBar、、MitContainer、MitNavMenu、MitNavGroup、MitNavLink系列组件但交互功能使用Alpine实现。有几个坑需要注意1将组件状态闭合在组件内Alpine是可以创建全局状态的AI可能会想通过这种方式来实现但这样的话不符合闭合原则组件状态不应该和外部状态耦合。同时这个思路也会受到胶水代码的影响坑会更多2胶水代码中每次增强式导航时MainLayout.razor的Alpine状态会需要被重建这会导致关闭或伸展的菜单恢复原状体验不好这时可以利用HTML的dataset特性来保留数据因为增强式导航时这块DOM是不会重建的所以dataset的状态会被保留。Alpine也有提供persist插件用于将状态持久化到localStorage但这种情况选择dataset是最佳实践3如果使用了MudBlazor注意在布局页只放MudThemeProvider其它几个Provider如Dialog、Snackbar、Popup放到具体需要这些交互功能的页面或组件因为这几个是交互式组件布局页一放就不再走SSR了。点击查看代码4MitNavGroup.razor贴一个集成了Alpine的轻交互组件。这些组件让AI模仿着MudBlazor写的轻交互组件应该都是没有问题的。你用了哪个组件库就让AI模仿这个组件库的相应组件来写HTML和CSS都是可以直接延用的AI改的主要是状态交互部分。所以就只贴一个比较有代表性的组件。Blazor的UI库还是推荐MudBlazor规范性、丰富度、性能、C#优先、生态、费用综合起来是最好的。其中我比较看中表格包括功能、易用性和性能表现大家比较的时候也可以重点看这个。MudBlazor是我体验过的里面最好的一个。有些组件库比如新出的blueprints我是很喜欢的但它的组件交互时总是有顿感、不利索其它很多组件库也有这个毛病大家体验一下表格多选就一清二楚了。我开始以为是Server模式的延迟但blueprints和MudBlazor一样官网组件都是WASM。点击查看代码5HTMX的集成.NET8其实已经提供了一个很好用的组件RazorComponentResult可以在服务端将组件渲染成HTML和HTMX是绝配。然后razor组件有后置代码提供给HTMX调用的MinimalApi正好可以组织在后置代码中。我还安装了一个自动注册MinimalApi的小库MinimalHelpers.Routing/MinimalHelpers.Routing.Analyzers。这一套组合拳下来几乎完美实现HTMX的集成。这不是AI想出来的是我的首创忍不住给自己点个赞。点击查看代码6认证集成我的认证中心使用了ABP并集成了Flurl的请求认证。由于交互位置是每页/每组件集成非常简单对接其它认证中心也是大差不差。对于Blazor项目我是建议将认证分离出来的不要集成IdentityIdentity的集成代码我是啃过的光集成辅助工具就有七八个文件页面代码得有几十个真没必要。一旦集成进来了你就会想搞懂里面的代码逻辑不搞懂总会担心它炸而且你一定会觉得它放置代码的位置不符合你的口味。最后说一下ABP很多人觉得它重其实你分开两边看。如果是纯后端的这块我觉得一点不重很规整了、很省心我曾经自己基于裸的AspNetCore封装过、也折腾过Fastendpoints最后发现还是得ABP尤其是现在业界又开始回归模块化单体免费版的ABP就非常香了。另外一块我是觉得比较重的就是ABP的前端为了集成不同的前端框架ABP搞了很多约定、抽象和代理即复杂、又不灵活搞过一阵后果断放弃了。ABP项目一律推荐NoUI不仅可以使劲撸ABP的免费版还大大提升了前端的性能和灵活性。动态/静态代理不要用将Flurl框架和规则定义好将Swagger给AI一扔啥都写的好好的你的分层项目还少了Http.Client层清爽很多。而商业版的UI现在用AI复现也很简单。但是ABP的RazorPages这块还是要看看因为NoUI的认证中心页面还是使用了RazorPagesABP提供了虚拟文件系统可以很方便的覆盖认证中心自带的登录、注册等页面。
在Vue/Nuxt、React/Next/TanstackStart、RazorPages折腾一圈后,还是回到了Blazor,但这回有SSR+HTMX+Alpine的加持
Blazor我的后端是AspNetCore且很坚定可能这就是生态锁定即使现代前端有了TS加持但毕竟是胶水层且每个框架都或多或少有漏网之鱼这些都影响了强类型的体感和安全感我真得很喜欢RazorPages简单直接但是生态要和JS强绑定。出早了如果晚一些缺脚的交互部分能够使用HTMX和Alpine的理念补上生态建起来说不定都不会有Blazor这种怪咖折腾一圈后让我对如何使用Blazor有新的思考这也是本文的主题2、初看Blazor很香但深度使用后总有尾大不掉之感Blazor是在现代前端框架之后建立起来的所以语法上即有Vue模板语法的简洁又有JSX的灵活Blazor从MVC、RazorPages演化而来天生就有服务端的基因并在.NET8的BlazorWebApp中实现SSR、Server和Wasm的集成。MVC/Razorpages的多年积累使Blazor比之Nuxt/Next等主流前端元框架在服务端领域有着更加精彩的表现但是Blazor先天的缺陷依然在那里1BlazorServer因网络条件引发的交互延迟、断连服务端线路的内存消耗2BlazorWasm首次浏览几十M的负载以及每次在浏览器启动Net运行时的时滞。给人感觉就是给了你解决方案了但问题都没解决干净3Auto估计没人愿意碰这东西BlazorWebApp刚出时社区对Auto是很关注的反而忽略了SSR。但是现在好像很少人谈Auto了SSR则更多的被关注、讨论和实验。这一继承自MVC/RazorPages的SSR在增强式导航加持下成为Blazor生态中最稳的选择而且.NET11还有一大批MVC/RazorPages上的特性将被转移到SSR体感能进一步升级。3、下面是我对如何使用Blazor的新思考和新实践总的原则是将SSR立于主导尽可能缩小Server/Wasm交互的使用范围无论使用哪种交互方式将交互位置设为“每页/每组件”很多人可能用了很久Blazor也不清楚全局交互和每页交互的区别。先说结论这个选择影响非常大它决定了底层浏览器的行为进而影响导航、认证、预渲染等核心功能。交互位置选择“每页/组件”后布局页不要放交互式组件只要放了交互式组件任何页面都要建立SignalR连接或者下载和启动WASM完全失去SSR立于主导这一原则。布局页的客户端交互功能交给CSS和Alpine.js实现如导航栏收起展开、折叠菜单等动态功能。页面首先考虑SSR如果要上客户端交互先考虑Alpine如果要上服务端交互先考虑HTMX。SSRHTMXAlpine的组合应该能解决十之八九的功能需求剩下的复杂交互才交给Server或者WASM并尽量划小到组件范围。对于最多只会有百来个人使用的后台管理可以全部页面开Server交互但交互位置仍然选择为“每页/每组件”因为这会极大的减少认证的复杂性进而提升认证的稳定性。关于预渲染.NET10之前是个大问题但现在不是啥问题了。一是我们以SSR为主导大部分页面是不会有预渲染的二是现在有PersistState基本解决交互页面预渲染带来的问题。但我认为预渲染仍然是一个需要每页斟酌选择的问题比如后台管理页面自然是可以全部关闭的。在此模式下Server交互的内存占用有望砍掉80%在此基础上你的钱带子也有能力集群部署将服务器尽可能的部署到离用户更近的位置近而解决Server交互延迟的问题。而WASM目前这个方案仅可以减少负载而负载从来不是WASM的最大问题希望未来将WASM的运行时切到CoreCLR后能带来真正近JS的体验。4、全局交互和每页交互究竟有啥区别全局交互下1首次请求有预渲染时服务端渲染请求页面为HTML并发给浏览器之后在浏览器水合、建立交互水合过程中会再次执行组件生命周期PersistState就是用于处理这个过程中二次请求数据的问题无预渲染时Server交互会下载一个JS脚本WASM则要下载大负载然后水合、建立交互、渲染页面所以这个过程会有空白Server交互的空白时间短很多。2此后请求在浏览器端被Server或Wasm拦截进行差量更新具体原理大家都懂。但这里有一个关键细节就是之后的导航请求不会再走浏览器到服务器的请求响应了。认证方式中最简单也最安全的认证就是Cookie登陆成功后SetCookie浏览器自动保存之后请求浏览器自动携带。由于不再走这个过程所以就要将认证状态保存到Server的线路中或Wasm的浏览器运行时中给认证带来很大的麻烦需要一大堆辅助工具和抽象。每页交互无论是首次请求还是后续请求无论是SSR还是Server或WASM交互一律都走浏览器到服务器的请求响应心智模式极大降低。比如认证你知道每次都一定会走Cookie认证绝大多数情况下你不再需要考虑SignalR线路或者WASM运行时中保存和使用认证状态的问题。5、如何以SSR为主导SSR页面如何添加交互功能如何集成HTMX和Alpine这是这篇文章的重点也是我的实践核心问题其实就一个如何集成HTMX和Alpine。这是一个完整的解决方案开始大量贴代码。1App.razor引入HTMX、Alpine和胶水代码HTMX和Alpine包直接使用CDN引入因为只有几K到几十KCDN好用点击查看代码2www/htmx-alpine-integration.jsSSRHTMXAlpine的胶水代码。需要胶水代码的主要原因是因为SSR的增强式导航它会对比DOM有变化的才更新这会影响HTMX和Alpine对DOM的监听和挂载。我们要做的是即保留SSR的增强式导航又让HTMX和Alpine对DOM的感知和普通请求响应一样。好在SSR增强式导航提供了增强式导航前、导航后等事件我们可以主动介入HTMX和Alpine的挂载其中HTMX无状态所以比较简单而Alpine会相对复杂些。点击查看代码3MainLayout.razor布局页。我让AI模仿MudBlazor的布局页组件创建了MitLayout、MitDrawer、MitMain、MitMainContent、MitAppBar、、MitContainer、MitNavMenu、MitNavGroup、MitNavLink系列组件但交互功能使用Alpine实现。有几个坑需要注意1将组件状态闭合在组件内Alpine是可以创建全局状态的AI可能会想通过这种方式来实现但这样的话不符合闭合原则组件状态不应该和外部状态耦合。同时这个思路也会受到胶水代码的影响坑会更多2胶水代码中每次增强式导航时MainLayout.razor的Alpine状态会需要被重建这会导致关闭或伸展的菜单恢复原状体验不好这时可以利用HTML的dataset特性来保留数据因为增强式导航时这块DOM是不会重建的所以dataset的状态会被保留。Alpine也有提供persist插件用于将状态持久化到localStorage但这种情况选择dataset是最佳实践3如果使用了MudBlazor注意在布局页只放MudThemeProvider其它几个Provider如Dialog、Snackbar、Popup放到具体需要这些交互功能的页面或组件因为这几个是交互式组件布局页一放就不再走SSR了。点击查看代码4MitNavGroup.razor贴一个集成了Alpine的轻交互组件。这些组件让AI模仿着MudBlazor写的轻交互组件应该都是没有问题的。你用了哪个组件库就让AI模仿这个组件库的相应组件来写HTML和CSS都是可以直接延用的AI改的主要是状态交互部分。所以就只贴一个比较有代表性的组件。Blazor的UI库还是推荐MudBlazor规范性、丰富度、性能、C#优先、生态、费用综合起来是最好的。其中我比较看中表格包括功能、易用性和性能表现大家比较的时候也可以重点看这个。MudBlazor是我体验过的里面最好的一个。有些组件库比如新出的blueprints我是很喜欢的但它的组件交互时总是有顿感、不利索其它很多组件库也有这个毛病大家体验一下表格多选就一清二楚了。我开始以为是Server模式的延迟但blueprints和MudBlazor一样官网组件都是WASM。点击查看代码5HTMX的集成.NET8其实已经提供了一个很好用的组件RazorComponentResult可以在服务端将组件渲染成HTML和HTMX是绝配。然后razor组件有后置代码提供给HTMX调用的MinimalApi正好可以组织在后置代码中。我还安装了一个自动注册MinimalApi的小库MinimalHelpers.Routing/MinimalHelpers.Routing.Analyzers。这一套组合拳下来几乎完美实现HTMX的集成。这不是AI想出来的是我的首创忍不住给自己点个赞。点击查看代码6认证集成我的认证中心使用了ABP并集成了Flurl的请求认证。由于交互位置是每页/每组件集成非常简单对接其它认证中心也是大差不差。对于Blazor项目我是建议将认证分离出来的不要集成IdentityIdentity的集成代码我是啃过的光集成辅助工具就有七八个文件页面代码得有几十个真没必要。一旦集成进来了你就会想搞懂里面的代码逻辑不搞懂总会担心它炸而且你一定会觉得它放置代码的位置不符合你的口味。最后说一下ABP很多人觉得它重其实你分开两边看。如果是纯后端的这块我觉得一点不重很规整了、很省心我曾经自己基于裸的AspNetCore封装过、也折腾过Fastendpoints最后发现还是得ABP尤其是现在业界又开始回归模块化单体免费版的ABP就非常香了。另外一块我是觉得比较重的就是ABP的前端为了集成不同的前端框架ABP搞了很多约定、抽象和代理即复杂、又不灵活搞过一阵后果断放弃了。ABP项目一律推荐NoUI不仅可以使劲撸ABP的免费版还大大提升了前端的性能和灵活性。动态/静态代理不要用将Flurl框架和规则定义好将Swagger给AI一扔啥都写的好好的你的分层项目还少了Http.Client层清爽很多。而商业版的UI现在用AI复现也很简单。但是ABP的RazorPages这块还是要看看因为NoUI的认证中心页面还是使用了RazorPagesABP提供了虚拟文件系统可以很方便的覆盖认证中心自带的登录、注册等页面。