Всем привет! Пару месяцев назад у нас возникла задача запилить лендос для нашего онлайн сервиса. Наш стек - Create React App + .Net Core. Погугля немного, мы решили, что хотим запилить лендос на Next JS, но возник вопрос - как это все вместе подружить.
Мы хотели, что бы приложение открывалось по ссылке: yourdomain.com/app
, а все остальные ссылки вели бы на лендос.
Для начала в папке, где у Вас лежит ClientApp нужно создать папку LandingApp куда вы добавите второй проект. (Если что, папки можно назвать, как угодно)
После того, как Вы добавите второй проект нужно немного обновить 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/"
Если вы используете библиотеку history то нужно указать еще basename: '/app'
import { connectRouter } from 'connected-react-router';
import { createBrowserHistory } from 'history';
export const history = createBrowserHistory({
basename: '/app',
});
export const routerReducer = connectRouter(history);
И на этом вроде все :)
Sm1le291
Не совсем понятно что вы пытались сделать. Понял только что какой то лендос. Обычно в компаниях разводят js и. Net core, потому что над ними работают работают разные команды в разных редакторах, да и деплоят их отдельно.
Вы бы лучше написали как их развести, а развести их очень просто, нужно создать в iis два разных веб сайта и деплоить на них отдельно фронт и бэк, при этом они могут быть на одном урле с разными портами.
А сведенные они и так по дефолту, когда вы создаете шаблонное приложение в VS, React или Angular
Antek-ESD Автор
Мы не только пытались, но и сделали) Представьте у Вас есть домен: https://yourdomain.com.
Вы хотите что бы когда пользователь заходит на https://yourdomain.com открывалась страница сделанная на Next JS (LandingApp). Но при переходе на https://yourdomain.com/app открывалось приложение на Create React App (ClientApp). Надеюсь так понятнее будет :)
K1aidy
В последнее время модно называть это микрофронтендами. Ваш метод приведет к минусам монолитов, если приложение разрастется.
Antek-ESD Автор
Тут все зависит от дальнейшей организации и от задачи. У нас, на пример, несколько бэкендов которые отвечают за разные вещи.
navferty
К слову, в IIS можно и на одном порту два приложения развернуть (например, чтобы избежать проблему с CORS'ами). Правой кнопкой мыши по сайту -> "новое приложение", тогда оно будет доступно на том же хосте, но по соответствующему имени приложения пути: например,
localhost:7777/appName
xTuMoHx
Почему такая привязка к IIS, dotnet давно кроссплатформенный, я бы лично через nginx разбирал урл по алиасам
Antek-ESD Автор
Не знаю, если билдить через azure app service, на пример, то там ни к портам ни к nginx доступа нет, так что выбор решения зависит от хостинга и конфигурации сервера.
IVANS0N
Это потому что у Azure свой gateway с балансировщиком есть, в котором можно настроить все эти правила для апсервисов