概要
.NET Core 3.0 の Webアプリケーション(API テンプレート)で Vue.jsをフロントエンドにして開発を行う方法。 React や Angular のテンプレートはすでに公式から出ています。(Vue.js もコマンドラインからの作成ならできたはず)
前提条件
- vue-cli ( npm install -g @vue/cli )
- .NET Core 3.0 (https://dotnet.microsoft.com/download/dotnet-core/3.0)
手順
ASP.NET Core Web アプリケーションを作成します。
プロジェクトフォルダに移動し、vue-cli を利用してVuejsのプロジェクトを作成します。
vue create client-app
nuget から Microsoft.AspNetCore.SpaServices.Extensions を追加します。
プロジェクトファイルを以下のように編集します。
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<SpaRoot>client-app\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.0.0" />
</ItemGroup>
<ItemGroup>
<Content Remove="$(SpaRoot)**" />
<None Remove="$(SpaRoot)**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<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>
</Project>
プロジェクトに VueCoreConnections を言う名前でフォルダを作成し、その下に Connection.cs を作成します。
Connection.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.SpaServices;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace WebApplication1.VueCoreConnections
{
public static class Connection
{
private static int Port { get; } = 8080;
private static Uri DevelopmentServerEndpoint { get; } = new Uri($"http://localhost:{Port}");
private static TimeSpan Timeout { get; } = TimeSpan.FromSeconds(60);
private static string DoneMessage { get; } = "DONE Compiled successfully in";
public static void UseVueDevelopmentServer(this ISpaBuilder spa)
{
spa.UseProxyToSpaDevelopmentServer(async () =>
{
var loggerFactory = spa.ApplicationBuilder.ApplicationServices.GetService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Vue");
if (IsRunning())
{
return DevelopmentServerEndpoint;
}
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var processInfo = new ProcessStartInfo
{
FileName = isWindows ? "cmd" : "npm",
Arguments = $"{(isWindows ? "/c npm " : "")}run serve",
WorkingDirectory = "client-app",
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
};
var process = Process.Start(processInfo);
var tcs = new TaskCompletionSource<int>();
_ = Task.Run(() =>
{
try
{
string line;
while ((line = process.StandardOutput.ReadLine()) != null)
{
logger.LogInformation(line);
if (!tcs.Task.IsCompleted && line.Contains(DoneMessage))
{
tcs.SetResult(1);
}
}
}
catch (EndOfStreamException ex)
{
logger.LogError(ex.ToString());
tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex));
}
});
_ = Task.Run(() =>
{
try
{
string line;
while ((line = process.StandardError.ReadLine()) != null)
{
logger.LogError(line);
}
}
catch (EndOfStreamException ex)
{
logger.LogError(ex.ToString());
tcs.SetException(new InvalidOperationException("'npm run serve' failed.", ex));
}
});
var timeout = Task.Delay(Timeout);
if (await Task.WhenAny(timeout, tcs.Task) == timeout)
{
throw new TimeoutException();
}
return DevelopmentServerEndpoint;
});
}
private static bool IsRunning() => IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpListeners()
.Select(x => x.Port)
.Contains(Port);
}
}
Startup.cs を編集します。
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using WebApplication1.VueCoreConnections;
namespace WebApplication1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// connect vue app - middleware
services.AddSpaStaticFiles(options => options.RootPath = "client-app/dist");
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
// use middleware and launch server for Vue
app.UseSpaStaticFiles();
app.UseSpa(spa =>
{
spa.Options.SourcePath = "client-app";
if (env.IsDevelopment())
{
spa.UseVueDevelopmentServer();
}
});
}
}
}
以上です。 F5 でデバック実行しましょう。初回のみ npm install が実行されます。
ヒント
こちらに遷移してしまう場合は プロジェクトのデバック設定を確認してください。