Как объединить несколько JS приложений с .NET Core (Create React APP + Next JS + .NET Core)

Kate

Administrator
Команда форума
Всем привет! Пару месяцев назад у нас возникла задача запилить лендос для нашего онлайн сервиса. Наш стек - Create React App + .Net Core. Погугля немного, мы решили, что хотим запилить лендос на Next JS, но возник вопрос - как это все вместе подружить.
Мы хотели, что бы приложение открывалось по ссылке: yourdomain.com/app, а все остальные ссылки вели бы на лендос.


Для начала в папке, где у Вас лежит ClientApp нужно создать папку LandingApp куда вы добавите второй проект. (Если что, папки можно назвать, как угодно)

9f7bce8c010a89ed05165ab3b9bc7554.png


После того, как Вы добавите второй проект нужно немного обновить startup.cs, чтобы .Net Core мог "переключать трафик" с одного проекта на другой.

Отключаем endpoint routing в методе ConfigureServices

services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
});
В метод Configure добавляем статичные файлы для CRA

app.UseSpaStaticFiles(new StaticFileOptions() {
RequestPath = "/app"
});
Добавляем маппер, который при переходе по ссылке /app будет открывать наше приложение

app.MapWhen(context => context.Request.Path.Value.StartsWith("/app"), builder =>
{
builder.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
"app",
new { controller = "", action = "app" }
);
});
builder.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";

if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}

});
});
После по дефолту открываем наше Next JS приложение

app.UseSpa(spa =>
{
spa.Options.SourcePath = "LandingApp";
// Для простоты билда, мы забилдили лендос отдельно
// И там скрывается ссылка по типу
// https://yourapp.azurewebsites.net
var url = Configuration.GetSection("urls")["landingUrl"];
if (env.IsDevelopment())
{
url = "http://localhost:3005";
}
spa.UseProxyToSpaDevelopmentServer(url);
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "dev");
}
});
Весь метод Configure
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
_env = env;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// 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.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
await next();
});

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles(new StaticFileOptions() {
RequestPath = "/app"
});

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});

app.MapWhen(context => context.Request.Path.Value.StartsWith("/app"), builder =>
{
builder.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
"app",
new { controller = "", action = "app" }
);
});
builder.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";

if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}

});
});

app.UseSpa(spa =>
{
spa.Options.SourcePath = "LandingApp";
var url = Configuration.GetSection("urls")["landingUrl"];
if (env.IsDevelopment())
{
url = "http://localhost:3005";
}
spa.UseProxyToSpaDevelopmentServer(url);
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "dev");
}
});

}

Далее, нам нужно сказать CRA откуда брать бандл т.к. теперь он находится не в корне, а в /app. Для этого, мы в package.json указываем свойство homepage: "/app/"

de850164dd05099028a83664ba38dfe7.png

Если вы используете библиотеку history то нужно указать еще basename: '/app'

import { connectRouter } from 'connected-react-router';
import { createBrowserHistory } from 'history';

export const history = createBrowserHistory({
basename: '/app',
});

export const routerReducer = connectRouter(history);

И на этом вроде все :)

 
Сверху