CnGal / CnGalWebSite.VueTrial

MIT License
5 stars 2 forks source link

疑问:【前后端不分离】 -> 【前后端分离】的动机 #22

Closed wdpm closed 1 year ago

wdpm commented 1 year ago

路过。偶然间发现这样一个关于GAL的百科生态建设网站,类似于VNDB。 目前主站的源码扫了下,是后端template渲染,顺藤摸瓜,见到这个使用Vue 3进行前端解耦的孵化项目。

我想问下前端分离的动机?

无利益的ACGN开源生态项目,加油。

LittleFish-233 commented 1 year ago

很高心能以这样的方式相遇ヾ(•ω•`)o

说起来你可能不信,目前主站也是 前后端分离 的哦~

很奇怪吧,.NetBlazor 框架我第一眼看到也以为是前后端不分离。

但其实,我们现在有两个前端呢,一个是在用户本地运行的 WASM 客户端,一个是通过建立 WebSocket 实时同步渲染页面的 SSR 服务端。

这两个客户端都访问同一套后端API接口获取数据,所以应该算是 前后端分离 吧o((>ω< ))o

小声说一句:这两个前端是共享代码的,不用担心我们写两遍代码哦~


那么,我就私自把标题的疑问改成“【Blazor】->【Vue 3】的动机”咯?

目前主站的代码确实十分混杂,不过都是因为我菜鸡的编程水平,可不是因为 Blazor 框架不行哦。

因为没有美工,几乎所有UI界面都是我自己设计的。对了,现在的前端页面是重构过三次的结果,也只是到了还能看下去的地步。这三次重构下来确实有很多历史遗留问题,但也没到难以维护的地步。

更加丰富的交互行为在 Blazor 框架下面也可以轻松实现,但还是因为我是个菜鸡,没有熟练掌握 Html/CSS ,做不出什么炫酷的特效。


回到正题,为什么开始使用 Vue 3 重构前端?

  1. 有大佬愿意帮忙用 Vue 3 重构前端
  2. BlazorSSR 模式消耗大量服务器资源,WASM 模式消耗大量网络流量
  3. BlazorSSR 模式由于使用 WebSocket 建立实时链接,网络延迟将会造成一些难以解决的bug
  4. 采用 Blazor 开发是因为我只会这一种技术,但是考虑到 Blazor 以及 .Net 未来难以在中国推广流行,也就意味着难以找到继续维护主站代码的人员,不利于资料站的维系。于是需要使用 Vue、React 等流行前端技术重构

    其实后端也是这样,ASP .NET Core 应尽早换成 Spring 等流行后端框架。

综上所述,开始使用 Vue 3 重构前端。


我们会继续加油的,欢迎加入我们一起添砖加瓦呀ヾ(^▽^*)))

wdpm commented 1 year ago

很奇怪吧,.NetBlazor 框架我第一眼看到也以为是前后端不分离。

我之前的言论有误,是我太武断了,抱歉。我决定去调查一下blazor,因为此前我没用过这个东西,.Net生态不熟悉。

我注意到了这个文章: Blazor 应用托管模型

Blazor 应用可以通过以下方式托管:

BlazorWebAssembly 应用使用基于 WebAssembly 的 .NET 运行时在浏览器中直接执行。BlazorWebAssembly 应用的工作方式类似于 Angular 和 React 等前端 JavaScript 框架。 但不是编写 JavaScript,而是编写 C#。 .NET 运行时与应用、应用程序集和任何必需的依赖项一起下载。 无需浏览器插件和扩展。

=> WSAM 客户端

在 Blazor Server 应用中,组件在服务器上运行,而不是在浏览器中的客户端运行。浏览器中发生的 UI 事件通过实时连接发送到服务器。 事件被分派到正确的组件实例。 组件将呈现,计算的 UI 差异被序列化后发送到浏览器并在其中应用于 DOM。

=> 实时连接 websocket


counter示例代码。Blazor

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

这个样例在于控制 @currentCount 值的生成。过于简单,于是我再次查看CnGal的源代码,下面取一个复杂视图的渲染作为例子:

https://github.com/CnGal/CnGalWebSite/blob/master/CnGalWebSite/CnGalWebSite.Shared/AppComponent/Normal/Tabs/TabViewItem.razor

<li class="@("nav-item "+Model.ClassNames)" style=" display: flex; justify-content: center;" role="presentation">
    <a class="@("text-center rounded  tab-"+Model.Type.ToString()+"-color"+(IsSelected?" active ":""))"
       style="cursor:pointer;width:100%"
       id="@("pills"+Model.RandomIndex+"-"+Model.Index.ToString()+"-tab")"
       data-bs-toggle="pill"
       href="@("#pills"+Model.RandomIndex+"-"+Model.Index.ToString())"
       role="tab"
       aria-controls="@("pills"+Model.RandomIndex+"-"+Model.Index.ToString())"
       aria-selected="@(IsSelected.ToString())"
       @onclick="@(()=>Model.OnTabClick.InvokeAsync(Model.Index))">
        @if (Model.Type == TableItemType.Bottom)
        {
            <i class="@("fa fa-fw fa-lg  li-user-space-small-icon "+Model.Icon)"></i>
            <div class="li-user-space-small-text">@Model.Text</div>

        }
        else if (Model.Type == TableItemType.Pivot)
        {
            <div class="li-user-space-small-text">@Model.Text</div>
            <div class="line w-100 mt-2" style="height:2px"></div>
        }
        else
        {
            <div class="line ps-2 pe-2">@Model.Text</div>
        }
    </a>
</li>

@code {
    [Parameter]
    public TabViewItemModel Model { get; set; }

    private bool IsSelected => Model.Index == Model.DefaultIndex;
}

这个例子非常典型:

这些机制和现在的主流前端框架Vue/React/Angular很像,但是API的混杂编写问题依旧得不到改善。就和时代的眼泪ASP,JSP,PHP一样。

微软即使下了一番苦功,即使使用WebAssembly先进的技术,也设计不好简洁的API。这个锅,需要后端渲染来背,谁来都洗不动。

<a class="@("text-center rounded  tab-"+Model.Type.ToString()+"-color"+(IsSelected?" active ":""))"
   style="cursor:pointer;width:100%"
   id="@("pills"+Model.RandomIndex+"-"+Model.Index.ToString()+"-tab")"
   data-bs-toggle="pill"
   href="@("#pills"+Model.RandomIndex+"-"+Model.Index.ToString())"
   role="tab"
   aria-controls="@("pills"+Model.RandomIndex+"-"+Model.Index.ToString())"
   aria-selected="@(IsSelected.ToString())"
   @onclick="@(()=>Model.OnTabClick.InvokeAsync(Model.Index))">
    @if (Model.Type == TableItemType.Bottom)

这种代码维护难度很高,因为代码的可读性差。如果换成前端MVVM框架,情况应该会得到改善。

这也是为何我之前就提出的问题:

更加丰富的交互行为在 Blazor 框架下面也可以轻松实现,但还是因为我没有熟练掌握 Html/CSS ,做不出什么炫酷的特效。

可以实现和[轻松实现/适合用来实现]是不同的,为不同的需求和context,选择最为合适的技术栈,个人认为才是最好的选择。

另外,的确C# .Net 略显苍老,Java/Pyton/Go/Rust/Node 都有非常丰富的Web生态。


另外,早日解耦前后端,和拥抱新的主流技术,可以减少以后的技术债。

开源项目的创建不难,维护才是最难的。

wdpm commented 1 year ago

我们会继续加油的,欢迎加入我们一起添砖加瓦呀ヾ(^▽^*)))

不了,暂时没这个打算,我自己的坑太多了,填不过来。我会偶尔关注你们这个CnGal的项目进展的。

LittleFish-233 commented 1 year ago

非常高兴有人愿意了解 Blazor 具体实现原理,但是好像后文中我写的代码让你产生了一些误会,非常抱歉 ≧ ﹏ ≦

这些误会基本上都是由我水平很低的代码引起的,再次向你道歉 <(_ _)>


这个样例在于控制 @currentCount 值的生成。过于简单,于是我再次查看CnGal的源代码,下面取一个复杂视图的渲染作为例子: https://github.com/CnGal/CnGalWebSite/blob/master/CnGalWebSite/CnGalWebSite.Shared/AppComponent/Normal/Tabs/TabViewItem.razor

就像前文中提到的那样,我们的前端页面布局重构过三次,作为开发者的我并不熟悉 Html/CSS ,没有遵守MVVM模式的开发规范,才写出了这样一个贻笑大方的组件。

CnGalWebSite.Shared/AppComponent/ 目录下是第一次适配移动端并尝试自己写的组件,如你所见十分丑陋。因此我也吸 取了教训:尽量使用组件库,优化代码书写方式。这个目录下面的组件也几乎不再使用了。

CnGalWebSite.Shared/MasaComponent/ 目录下是在此基础上重构的组件,应该会更好一点。

例如下面这段代码作为例子可能比较好: https://github.com/CnGal/CnGalWebSite/blob/master/CnGalWebSite/CnGalWebSite.Shared/MasaComponent/Shared/Editors/Entries/AudioCard.razor


这些机制和现在的主流前端框架Vue/React/Angular很像,但是API的混杂编写问题依旧得不到改善。就和时代的眼泪ASP,JSP,PHP一样。

非常抱歉我写的代码让你觉得是 Blazor 会产生 API的混杂编写问题 ,实际上这是人的问题而不是框架的问题。


微软即使下了一番苦功,即使使用WebAssembly先进的技术,也设计不好简洁的API。这个锅,需要后端渲染来背,谁来都洗不动。

这个锅不应该由微软来背,是我写出这样代码的责任。

Blazor 的设计十分优秀, Blazor 是标准的现代前端框架,Blazor 可以应用MVVM模式,

Blazor 有很多优秀的开源项目,比如我们使用的组件库 : Masa Blazor,开源项目地址:https://github.com/BlazorComponent/MASA.Blazor Bootstrap Blazor,开源项目地址:https://gitee.com/LongbowEnterprise/BootstrapBlazor

如果方便的话可以阅读一下他们的源码,也许你会有一些不一样的感受。

总之,非常抱歉造成了这样的误会 >︿<

wdpm commented 1 year ago

我认为我没有误会你的意思,反而可能你有点误解我的意思了。

我重新梳理了一下我的疑问关键点,我指的API的混杂编写问题是指:

后端和前端逻辑都在在一个文件来写,指的是代码的编写/维护问题。不管它最后怎么渲染,是客户端还是服务端,还是各种hydrate,代码可读性此时是弱于前端和后端完全分离出不同的项目/模块来编写的。

目前这个 CnGalWebSite.VueTrial 看起来就很现代化,渲染关键逻辑都在前端,使用标准JS框架/库来解决就很直接。仅仅需要后端的API,使用AJAX请求来获取数据,然后局部刷新就好。

而 blazor 这类框架企图使用其他语言(这里是C#),对前端视图层的逻辑进行一层抽象,然后利用WSAM编译到浏览器中执行。加一层抽象就加一层复杂度,毕竟浏览器不能直接执行C#,只能直接执行JS。可能他们的出发点是考虑让这个blazor框架能直接接管网站开发的后端逻辑和UI界面,而不再需要另外的独立前端模块。优点和缺点都很明显。

个人觉得稍微复杂一点的网站项目,前后端代码分离还是非常合理的选择。后端只管REST API,返回数据。前端主要管界面渲染,使用AJAX请求和后端API交互。

顺便说一句,blazor来做MVVM,对比成熟火热的Vue/React框架而言,几乎没有优势。

容易维护的代码项目才有未来,不能维护和难以读懂的代码项目,一般会走向衰亡。

这个issue没有进一步讨论的意义了,当初我只是路过问一下。

本质上就是:分离出前端模块/后端模块,让代码更容易维护和可读,保持常绿。

LittleFish-233 commented 1 year ago

嗯嗯,非常感谢,那我就先关闭这个issue了