Как создать React SPA в старой школе ASP.NET без React.NET с правильным объединением и загрузкой фрагментов

Если вам когда-либо приходилось использовать ASP.NET с современным стеком внешнего интерфейса, вы заметите, что на самом деле невозможно найти какую-либо полезную информацию об этом. Если вы сможете найти что-нибудь для ASP.NET MVC (не ядро), все это будет для React.Net, который страдает от проблем с документацией или старой версии angular. Основная проблема, конечно, заключается в именовании между ASP.NET и ASP.NET Core и невозможности найти что-либо для ASP.NET Classic.

Плохие идеи

Заставлять webpack выводить один гигантский файл bundle.js — ужасная идея. Lighthouse будет ругать вас за большое время начальной загрузки, и по мере роста вашего проекта вам придется включать каждую страницу как часть исходного пакета, который не масштабируется.

Хорошие идеи

Вручную разделить ваш проект на несколько точек входа для каждой страницы, а затем включить его в файл .cshtml. Это утомительно и все же не лучший способ сделать что-то. Вы можете столкнуться с большим начальным временем загрузки

Лучшая идея

Настройте HtmlWebPackPlugin для вывода .cshtml файла, который можно включить в основное представление индекса. Это автоматически сгенерирует частичный файл .cshtml со всеми автоматически сгенерированными кусками javascript и правильно отложенными тегами script, которые будут загружаться при необходимости. Наряду с React Lazy Loading вы можете получить небольшое время начальной загрузки и загрузку фрагментов по требованию.

В том же месте, что и ваш webpack.config.js, создайте файл с именем template (без расширения. Вам нужно будет извлечь приложение create-react-app)

Содержимое файла должно быть

<%= htmlWebpackPlugin.tags.headTags %>

В webpack.config.js сделайте так, чтобы ваш HtmlWebPackPlugin в разделе плагинов выглядел следующим образом

return new HtmlWebPackPlugin({
template: 'template',
inject: false,
minify: false,
filename: `${fileName.replace(path.extname(fileName), '')}.cshtml`,
});

Inject false останавливает плагин от автоматического создания полной html-страницы и вместо этого создает только элемент script со всеми включенными частями Javascript.

template указывает на файл шаблона, который вы создали для создания тегов сценария .cshmtl

minify: false остановит плагин, пытающийся неправильно минимизировать файл, что сломает все.

тег имени файла просто использует существующее имя файла html и добавляет .cshtml. Это создаст файл с именем index.cshtml (при условии, что ваша точка входа index.html). У меня также есть два плагина для веб-пакетов, один из которых выводит .cshtml, а другой выводит традиционный html, когда я хочу разрабатывать с использованием сервера разработки веб-пакетов.

Когда вы создаете свой .cshtml вывод, он должен выглядеть примерно так:

<script defer src="/wwwroot/build/590.478c.js"></script><script defer src="/wwwroot/build/index.478c.js"></script><link href="/wwwroot/build/index.bundle.css" rel="stylesheet">

Теперь перейдите к вашему проекту ASP.NET. Вероятно, у вас есть какой-то контроллер под названием Home Controller, который должен загружать главную страницу вашего проекта asp.net. Перейдите к соответствующему представлению для этого контроллера. В представлении (вероятно, также называемом index.cshtml) просто включите вызов RenderPage в ваш построенный проект реагирования вместе с div, называемым корневым элементом.

@{
/**/
ViewBag.Title = "Home Page";
}
<div id="root"></div>
@{
@RenderPage("~/wwwroot/build/index.cshtml")
}

В общем представлении мой выглядит просто так

<!DOCTYPE html>
<html>
<head lang="en" translate="no">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>

Маршрутизация на стороне клиента

Если вы используете маршрутизацию на стороне клиента, вы заметите, что если вы сойдете с основного маршрута и обновите ASP.NET, он не будет знать, что загружать.

Просто создайте универсальный маршрут в своем RouteConfig.cs

Это выглядит как

routes.MapRoute(
name: "Everything",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" });
}

Теперь вся ваша маршрутизация может быть выполнена на стороне клиента, к лучшему или к худшему, и при перезагрузке она приведет вас к тому же месту.

Оттуда я сохраняю свой HomeController только с одной функцией для загрузки главной страницы. Затем оттуда я помещаю все маршруты API для внешнего интерфейса в ApiController со всем в `/api/‹action›`.

Это своего рода мои наспех написанные мысли о том, как это сделать, если у вас есть какие-либо вопросы, не стесняйтесь, напишите мне по адресу [email protected]