您是否存在想在浏览器动态编译razor的组件的想法?

简介: 您是否存在想在浏览器动态编译razor的组件的想法?

不知道是否有人跟我一样想在浏览器上直接可以动态的编译`blazor`的一些组件库?而不是通过引用`NuGet`以后才能查看到效果,并且在使用别人的组件的时候可以在动态的调整组件的一些样式

不说了开始正文:

本文我们将使用`Masa`提供的一个组件实现动态编译[github.com直通车](https://github.com/BlazorComponent/MASA.Blazor.Extensions/tree/main/src/Languages/Masa.Blazor.Extensions.Languages.Razor) ,执行环境将在`WebAssembly`中执行,为什么使用`WebAssembly`而不是`Server`呢?首先我们需要先了解这俩种模式的执行原理


## WebAssembly:


-  `Blazor WebAssembly` 是`Blazor WebAssembly`,用于使用 .NET 生成交互式客户端 Web 应用。 `Blazor WebAssembly` 使用无插件或将代码重新编译为其他语言的开放式 Web 标准。 `Blazor WebAssembly` 适用于所有新式 Web 浏览器,包括移动浏览器。

## Server:

- `Blazor Server`在 `ASP.NET Core` 应用中支持在服务器上托管 Razor 组件。 可通过 [SignalR](https://learn.microsoft.com/zh-cn/aspnet/core/signalr/introduction?view=aspnetcore-7.0) 连接处理 UI 更新。

 运行时停留在服务器上并处理:

 - 执行应用的 C# 代码。

 - 将 UI 事件从浏览器发送到服务器。

 - 将 UI 更新应用于服务器发送回的已呈现的组件。

由于编译是完全可操作的,存在安全问题,在Server的模式下用户编译的环境就是服务器的环境,这样用户就可以通过动态编译代码实现操作侵入安全,问题很严重,如果有心人使用对于安全影响过于严重,不建议在Server中使用动态编译

实现我们来创建一个空的WebAssembly项目

mkdir compileRazor
cd compileRazor
dotnet new blazorwasm-empty

使用vs打开项目添加[Masa.Blazor.Extensions.Languages.Razor](https://github.com/BlazorComponent/MASA.Blazor.Extensions/tree/main/src/Languages/Masa.Blazor.Extensions.Languages.Razor) ,将一下代码添加到项目文件中

<PackageReferenceInclude="Masa.Blazor.Extensions.Languages.Razor"Version="0.0.1"/>

修改`Program.cs`文件的代码

usingMicrosoft.AspNetCore.Components.Web;
usingMicrosoft.AspNetCore.Components.WebAssembly.Hosting;
usingcompileRazor;
usingMasa.Blazor.Extensions.Languages.Razor;
usingMicrosoft.AspNetCore.Razor.Language;
usingMicrosoft.CodeAnalysis;
varbuilder=WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp=>newHttpClient { BaseAddress=newUri(builder.HostEnvironment.BaseAddress) });
varapp=builder.Build();
// 初始化RazorCompileRazorCompile.Initialized(awaitGetReference(app.Services), awaitGetRazorExtension());
awaitapp.RunAsync();
// 添加程序集引用asyncTask<List<PortableExecutableReference>?>GetReference(IServiceProviderservices)
{
#regionWebAsembly// need to add ServicevarhttpClient=services.GetService<HttpClient>();
varportableExecutableReferences=newList<PortableExecutableReference>();
foreach (varassemblyinAppDomain.CurrentDomain.GetAssemblies())
    {
try        {
//你需要通过网络获取程序集,应为无法通过程序集目录获取varstream=awaithttpClient!.GetStreamAsync($"_framework/{assembly.GetName().Name}.dll");
if (stream.Length>0)
            {
portableExecutableReferences?.Add(MetadataReference.CreateFromStream(stream));
            }
        }
catch (Exceptione) // There may be a 404        {
Console.WriteLine(e.Message);
        }
    }
#endregion// 由于WebAssembly和Server返回portableexecutablerreference机制不同,需要分开处理returnportableExecutableReferences;
}
asyncTask<List<RazorExtension>>GetRazorExtension()
{
varrazorExtension=newList<RazorExtension>();
foreach (varasmintypeof(Program).Assembly.GetReferencedAssemblies())
    {
razorExtension.Add(newAssemblyExtension(asm.FullName, AppDomain.CurrentDomain.Load(asm.FullName)));
    }
returnrazorExtension;
}

修改`Pages\Index.razor`的代码

@page "/"
@using Masa.Blazor.Extensions.Languages.Razor;
<buttonclass="button"@onclick="Run">刷新</button><divclass="input-container"><textarea@bind="Code"type="text"class="input-box"placeholder="请输入执行代码"></textarea></div>@if (ComponentType != null)
{
<DynamicComponentType="ComponentType"></DynamicComponent>}
@code{
    private string Code = @"<body><divid='app'><header><h1>Doctor Who&trade; Episode Database</h1></header><nav><ahref='main-list'>Main Episode List</a><ahref='search'>Search</a><ahref='new'>Add Episode</a></nav><h2>Episodes</h2><ul><li>...</li><li>...</li><li>...</li></ul><footer>            Doctor Who is a registered trademark of the BBC.  
           https://www.doctorwho.tv/
</footer></div></body>";
    private Type? ComponentType;
    private void Run()
    {
        ComponentType = RazorCompile.CompileToType(new CompileRazorOptions()
        {
            Code = Code // TODO: 在WebAssembly下保证ConcurrentBuild是false 因为Webassembly不支持多线程
        });
        StateHasChanged();
    }
}
<style>.button{
width: 100%;
font-size: 22px;
background-color: cornflowerblue;
border: 0px;
margin: 5px;
border-radius: 5px;
height: 40px;
    }
.input-container {
width: 500px;
margin: 0auto;
padding: 10px;
border: 1pxsolid#ccc;
border-radius: 5px;
    }  
.input-box {
width: 100%;
height: 100px;
border: 1pxsolid#ccc;
border-radius: 5px;
font-size: 14px;
    }
</style>

然后启动程序效果如图:


动画.gif


首次编译会比较慢,在`WebAssembly`下还可以因为电脑问题造成卡顿,如果是需要提供开发效率可以使用Server调试,在Server调试的话是比`WebAssembly`快很多,而且`WebAssembly`还没有做Aot,性能不会太好

来自token的分享

技术交流群:737776595

推荐一个超级好用的`Blazor UI`组件 Masa Blazor 开源协议 `MIT` 商用完全没问题

目录
相关文章
|
9月前
|
测试技术
【sgUploadTileImage】自定义组件:浏览器端生成瓦片图,并转换为File文件序列上传瓦片图
【sgUploadTileImage】自定义组件:浏览器端生成瓦片图,并转换为File文件序列上传瓦片图
|
7月前
|
JavaScript
vue 组件封装 | 随鼠标移动的信息框 (含监听鼠标移动、移出事件,获取元素的宽高、获取浏览器的宽高)
vue 组件封装 | 随鼠标移动的信息框 (含监听鼠标移动、移出事件,获取元素的宽高、获取浏览器的宽高)
64 1
|
9月前
|
前端开发
elementui的el-dialog组件与el-tabs同时用导致浏览器卡死的原因解决
elementui的el-dialog组件与el-tabs同时用导致浏览器卡死的原因解决
181 0
|
移动开发
华为Mate60钉钉App内置浏览器中使用“@kangc/v-md-editor"组件,功能不正常
华为Mate60钉钉App内置浏览器中使用“@kangc/v-md-editor"组件,功能不正常
321 1
|
JavaScript 前端开发
TypeScript 可以编译成纯 JavaScript,并且可以在任何浏览器上运行,具体应用案例解析
TypeScript 可以编译成纯 JavaScript,并且可以在任何浏览器上运行,具体应用案例解析
176 1
|
开发框架 安全 .NET
您是否也有想在浏览器中实时的编辑代码并且渲染的想法?
您是否也有想在浏览器中实时的编辑代码并且渲染的想法?
101 0
|
Web App开发 iOS开发
element-plus:Message 消息提示组件safari浏览器中显示异常
element-plus:Message 消息提示组件safari浏览器中显示异常
226 0
element-plus:Message 消息提示组件safari浏览器中显示异常
|
存储 JavaScript 前端开发
实现一个 Code Pen:(四)浏览器编译代码
前面的文章中,我们配置好了编辑器,实现了 css、html、js 的编辑,现在我们需要做代码实时运行的功能了,并且可以直接写 less、scss、JavaScript、typescript。
237 0
|
Web App开发 存储 JavaScript
前端百题斩【029】——原来浏览器中存在五类进程
前端百题斩【029】——原来浏览器中存在五类进程
前端百题斩【029】——原来浏览器中存在五类进程
|
前端开发 JavaScript API

热门文章

最新文章

相关实验场景

更多