SPA
單頁面應用已經遍地開花,熟知的三大框架,Angular
、Vue
和React
,其中Angular
與React
均可集成至ASP.NET Core
,且提供了相關了中間件。但是Vue沒有:
As far as I’m aware, we don’t have plans to introduce Vue-specific features. This isn’t because we have anything against Vue, but rather just to limit the growth in the number of frameworks that we’re maintaining support for. The dev team only has a finite capacity for handling third-party concepts, and last year we made the strategic choice to focus on only Angular and React.
本篇將介紹如何集成Vue
。
1.集成的效果
SPA
與ASP.NET Core
集成后。根據需求不同,是可以達到兩種不同效果。
1.1 一鍵開啟
通過Vistual Studio
-->F5
,便可以直接啟動前端應用開發模式和后台api服務,且在用一個端口下。這種方便單人開發運行,調試。
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
//spa.UseReactDevelopmentServer(npmScript: "start");
spa.UseVueCliServer(npmScript: "start");
//spa.UseProxyToSpaDevelopmentServer("http://localhost:8080");
}
});
1.2 獨立運行,減輕依賴
另外就是在典型前后端分離的協同開發,常用調試方式啟動后端api服務,確定api端口號(假設后端端口為3000
),然后去前端配置文件,如vue.config.js
修改代理,如下配置:
module.exports = {
//omit some config..
devServer: {
proxy: 'localhost:3000'
}
}
然后:
- 后端啟動
- 前端啟動
- 然后再去訪問前端
但是集成后,就不必這樣操作,只需要在后端Startup.cs
中指定固定的SPA調試服務器地址。
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
//spa.UseReactDevelopmentServer(npmScript: "start");
//spa.UseVueCliServer(npmScript: "start");
spa.UseProxyToSpaDevelopmentServer("http://localhost:8080");
}
});
這樣后端開發人員需要再看下前端效果,就不必再去單獨看前端,前端一旦啟動,端口一般不會變化,做如上配置,便可直接通過Vistual Studio
-->F5
直接運行。
- 前端啟動
- 后端啟動,直接就反向代理到前端開發服務器,無需再去訪問前端。
2.集成的原理
2.1 啟動前端
通過中間件調用node進程,執行如下命令:
npm start -- --port {dynamic_port}
dynamic_port
是在運行過程中隨機一個端口。npm
命令已經存在在package.json
中配置,它將通過vue-cli-service serve --port
啟動開發服務器。
2.2 代理前端調試服務器
前端調試服務器啟動成功后,中間件將會創建一個HttpClient
代理:將請求一起轉發到前端調試服務器 ,然后將響應復制為自己的響應,上面UseProxyToSpaDevelopmentServer
沒有啟動前端的過程(因為前端已啟動完成),只是把前端請求靜態資源的請求代理到前端調試服務器。
3.集成步驟
3.1 安裝nuget包
Install-Package Garfield.SpaServices.Extensions.Vue -Version 2.0.0
#請安裝最新版本 適用於.net core 3.1
這是博主根據官方庫改寫,正如nuget包的文檔寫點那樣:由於官方沒有支持Vue,看后續是否支持,如支持,此包將歸檔廢棄。
3.2 創建Vue項目
在API項目創建ClientApp
文件,在此文件夾下創建或復制Vue
項目。
保證以下目錄結構即可:
ClientApp/package.json
3.3 修改package.json
適配后端這邊,package.json
要做一些調整,主要是端口由后端啟動時隨機指定可用的。
"scripts": {
"start": "vue-cli-service serve --port", //edit here
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e"
},
3.4 修改Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//omit some code..
app.UseStaticFiles();
//PRODUCTION uses webpack static files
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseVueCliServer(npmScript: "start");
//spa.UseProxyToSpaDevelopmentServer("http://localhost:8080");
}
});
}
4.還原構建-Build
在我們調試之前,一定是構建項目,但是我們的項目現在是一個包含前端Vue
和后端Webapi
的前后端分離項目。后端需要還原各種nuget
包,在那之前,前端也需要還原npm包
,以前博主是執行npm install
這里介紹下使用MSBuild
自動執行,修改csproj
,增加Target
:
<PropertyGroup>
<!--omit some-->
<SpaRoot>ClientApp\</SpaRoot>
</PropertyGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
此時就會在Build ASP.NET WebAPI
項目前,自動還原前端項目,執行npm install
。
5.調試-Debug
從效果上來看,兩種集成方式貌似沒啥大的差別,但是從開發的調試的角度,有各自運用的場景。
5.1 集成調試
保持上面的配置與代碼不變,直接運行ASP.NET Web API
Vue
將會自動構建,並與ASP.NET Core WebAPI
項目將會集成運行,通過訪問localhost:port
便可以調試訪問應用。
5.2 獨立調試
如果后端接口穩定,僅僅是前端問題,那么上面的集成調試時比較方便的。想象一下,每次都要重新啟動,執行npm start
,還是有點費時間。特別是前端已經足夠穩定,后端接口修改頻繁,那么這樣的方式無疑是太慢了,因為每次都需要重新啟動vue
項目,失去了集成的優勢。所以獨立調試后端更符合此類場景。
5.2.1 啟動前端
cd ClientApp
npm start 8080
5.2.2 修改后端
// spa.UseVueCliServer(npmScript: "start"); //替換如下代碼
spa.UseProxyToSpaDevelopmentServer("http://localhost:8080");
當啟動 ASP.NET Core
應用時,它不會啟動 Vue dev 服務器
, 而是使用手動啟動的實例。 這使它能夠更快地啟動和重新啟動。 不再需要每次都等待 Vue CLI
重新生成客戶端應用。
6.發布-Publish
小項目,我們就不需要nginx去放靜態文件,修改配置等等。
以往博主部署這種前后端分離項目,是通過nginx
部署靜態前端文件,反向代理后端接口。這種方式沒問題。但是這里介紹一點新鮮的(至少對博主而言),前端Vue
項目通過npm run build
構建成一系列的靜態文件。這些靜態文件就是我們的SPA
。說白了,就是一個靜態網頁。
所以需要靜態文件中間件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//omit some code..
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
}
然后指定我們靜態文件的路徑:
//Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//omit some code..
services.AddSpaStaticFiles(c=>
{
c.RootPath = "ClientApp/dist";
});
}
這里我們把Vue項目包含在webapi
項目中,文件夾ClientApp
,他構建的文件夾為dist
,當然這個也是可以修改的。
最重要一步來了,發布時讓構建好的靜態文件隨着WebAPI
一起發布,而不需要,單獨執行npm run build
然后手動拷貝,這里還是用到了MSbuild
,所以同樣需要修改csproj
文件,增加publish
的Target
:
<PropertyGroup>
<!--omit some xml..-->
<SpaRoot>ClientApp\</SpaRoot>
</PropertyGroup>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<!--<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />-->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
大概指令:發布時運行webpack
- 如果需要的話執行
npm install
還原(我注釋了) - 執行
npm run build
進行構建 - 拷貝構建好的
dist
文件夾內容到發布文件夾中
這時再通過Visual Studio
后者命令發布時,就會同步構建前端項目,發布后端API且包含前端構建后的dist
文件。便可以不用分開部署,從而融合為同一個程序。
參考鏈接
https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild-well-known-item-metadata?view=vs-2019
https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild?view=vs-2019
https://blog.csdn.net/sinat_36112136/article/details/103039817
https://github.com/dotnet/sdk/issues/795#issuecomment-289782712
作者:Garfield
同步更新至個人博客:http://www.randyfield.cn/
本文版權歸作者所有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系287572291@qq.com