Серверный рендеринг (SSR, Server-Side Rendering) позволяет генерировать HTML на сервере до передачи его клиенту. В контексте Element Plus SSR особенно актуален для улучшения SEO, ускорения первой загрузки страницы и уменьшения «мерцания» интерфейса при инициализации компонентов.
Элемент, требующий внимания при SSR, — динамические компоненты и стили, так как Element Plus использует глобальные стили, компоненты с динамическим состоянием и JavaScript для интерактивности.
Для работы с SSR в Vue 3 и Element Plus необходимо:
npm install vue@next vue-router@4 vuex@4
npm install element-plus
vite или
webpack для SSR. В случае Vite рекомендуется использовать
vite-ssr или vite-ssr-plugin для
автоматической сборки и гидратации.Для SSR не рекомендуется глобально импортировать все компоненты, так как это увеличивает размер серверного бандла и время рендеринга. Лучше использовать on-demand import:
import { ElButton, ElInput } from 'element-plus';
import 'element-plus/es/components/button/style/css';
import 'element-plus/es/components/input/style/css';
export default {
components: {
ElButton,
ElInput
}
}
При таком подходе сервер будет рендерить только нужные компоненты с их стилями, что ускоряет генерацию HTML.
Element Plus использует CSS-in-JS и scoped стили для компонентов. Для корректного SSR необходимо:
renderStyles() (если используется Nuxt или
Vite SSR) для внедрения стилей в HTML.Пример настройки в Nuxt 3:
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(ElementPlus)
})
При SSR важно, чтобы все данные для компонентов были доступны до рендеринга. Для этого используется комбинация async setup и suspense:
<template>
<el-table :data="users" v-if="users.length">
<el-table-column prop="name" label="Имя" />
<el-table-column prop="email" label="Email" />
</el-table>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { ElTable, ElTableColumn } from 'element-plus';
const users = ref([]);
onMounted(async () => {
const res = await fetch('https://api.example.com/users');
users.value = await res.json();
});
</script>
Для SSR требуется использовать серверный API для предварительной
загрузки данных, чтобы users уже имел значение на момент
генерации HTML.
После передачи сгенерированного на сервере HTML, Element Plus
компоненты должны быть гидратированы на клиенте для
интерактивности. Это выполняется через обычный
createApp:
import { createSSRApp, h } from 'vue';
import App from './App.vue';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
export function createApp() {
const app = createSSRApp({
render: () => h(App)
});
app.use(ElementPlus);
return { app };
}
Важно учитывать, что все компоненты должны быть идентичны серверной разметке, иначе Vue выдаст предупреждения о несоответствии DOM.
Element Plus использует портал (Teleport) для
компонентов вроде ElDialog, ElPopover. Для
SSR:
v-if или v-show для
управления видимостью после гидратации.client-only
в Nuxt или аналогичные обертки для Vite SSR.Element Plus использует отдельные пакеты локализации
(element-plus/es/locale/lang). Для SSR необходимо:
import { createApp } from 'vue';
import ElementPlus from 'element-plus';
import en from 'element-plus/es/locale/lang/en';
const app = createApp(App);
app.use(ElementPlus, { locale: en });
Локаль должна быть заранее определена на сервере, чтобы компоненты сразу отобразили нужные тексты без перерендера на клиенте.
В Nuxt 3 достаточно подключить Element Plus через плагин и настроить ssr: true, чтобы компоненты корректно рендерились на сервере и гидратировались на клиенте:
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(ElementPlus, { ssr: true });
});
Для Vite SSR нужно убедиться, что все зависимости правильно бандлятся
для сервера, а CSS импортируется через
import 'element-plus/dist/index.css' в серверном
бандле.
Такой подход к серверному рендерингу позволяет Element Plus использовать преимущества SSR без потери интерактивности компонентов, обеспечивая быструю первую загрузку и корректное отображение интерфейса.