Рендеринг Vue на стороне сервера с ASP.NET Core 2
Я пытаюсь понять использование и ограничения рендеринга на стороне сервера с vuejs при использовании ядра aspnet.
Я использовал этот стартовый комплект для ядра aspnet и vuejs для настройки простого сайта vue, который работает на основе приведенного здесь кода: https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/master
Затем я изменил проект, обновив aspnet-prerendering, и добавил vue-server-renderer, скомпилировав сборку исходных текстов для объединения этого обновления: https://github.com/selaromdotnet/aspnet-vue-ssr-test/tree/ssr
Если я запускаю этот проект, сайт, кажется, загружается нормально, и если я отключаю JavaScript в браузере, я вижу, что действительно получается, что рендеринг на стороне сервера выполнил и заполнил результат html:
однако, поскольку JavaScript отключен, контент не перемещается в DOM, как кажется, он пытается...
Насколько я понимаю, рендеринг на стороне сервера заключается в том, что он полностью заполняет html и предоставляет пользователю заполненную страницу, так что даже если бы JS был отключен, они, по крайней мере, могли видеть страницу (специально для целей SEO). Я не прав?
Теперь я верю, что современные поисковые системы будут выполнять простые скрипты, подобные этой, чтобы получить контент, но я все еще не хочу, чтобы пустая страница отображалась, если js отключен...
Это ограничение рендеринга на стороне сервера, или, возможно, конкретно ssr с ядром vue и / или aspnet?
или я просто где-то пропускаю шаг?
Редактировать: больше информации
Я посмотрел на исходный код того, что, как мне кажется, является методом, который представляет этот раздел здесь: https://github.com/aspnet/JavaScriptServices/blob/dev/src/Microsoft.AspNetCore.SpaServices/Prerendering/PrerenderTagHelper.cs
Линия
output.Content.SetHtmlContent(result.Html);
имеет нулевое значение для result.Html. Однако, когда я вручную редактирую это значение, чтобы поместить тестовое значение, оно также не отображается в выходном HTML, а тег app div все еще пуст...
Если я делаю что-то не так, чтобы заполнить значение result.Html ожидаемым выводом, это одно, и я был бы признателен за помощь в этом, тем более что выходной html, кажется, найден, так как он находится в сценарии, который немедленно следует...
Тем не менее, даже если бы я заполнил его, похоже, что он пропускается, о чем я вручную изменил значение. это ошибка в коде или я неправильно делаю что-то, или, может быть, и то, и другое?
1 ответ
Как вы правильно заметили, для вашего проекта, result.Html
внутри тега помощник равен нулю. Так что эта строка не может быть местом, где генерируется вывод. Поскольку вывод HTML из сценария предварительной визуализации также не включает script
тег, ясно, что что-то должно генерировать это. Единственная другая строка, которая могла бы сделать это, это следующее из PrerenderTagHelper
:
output.PostElement.SetHtmlContent($"<script>{globalsScript}</script>");
Это соответствовало бы наблюдаемому результату, поэтому мы должны выяснить, где globalsScript
происходит от.
Если вы посмотрите на PrerenderTagHelper
реализации, вы можете увидеть, что он будет вызывать Prerenderer.RenderToString
который возвращает RenderToStringResult
, Этот объект результата десериализуется из JSON после вызова скрипта Node.
Таким образом, здесь есть два свойства, представляющих интерес: Html
, а также Globals
, Первый отвечает за содержание вывода HTML, который, в конечном итоге, отображается внутри помощника тега. Последний является объектом JSON, содержащим дополнительные глобальные переменные, которые должны быть установлены на стороне клиента. Это то, что будет отображено внутри script
тег.
Если вы посмотрите на визуализированный HTML из вашего проекта, вы увидите, что есть два глобальных параметра: window.html
а также window.__INITIAL_STATE__
, Так что эти два установлены где-то в вашем коде, хотя html
не должно быть глобальным.
Виновником является renderOnServer.js
файл:
vue_renderer.renderToString(context, (err, _html) => {
if (err) { reject(err.message) }
resolve({
globals: {
html: _html,
__INITIAL_STATE__: context.state
}
})
})
Как вы можете видеть, это разрешит результат, содержащий только globals
объект с обоими html
а также __INITIAL_STATE__
свойства. Вот что визуализируется внутри script
тег.
Но то, что вы хотите сделать, это иметь html
не как часть globals
но на слое выше, так что он будет десериализован в RenderToStringResult.Html
имущество:
resolve({
html: _html,
globals: {
__INITIAL_STATE__: context.state
}
})
Если вы сделаете это так, ваш проект будет правильно выполнять рендеринг на стороне сервера, не требуя JavaScript для начального представления.