Серверный рендер

Для того чтобы опробовать серверный рендер в действии воспользуйтесь готовым каркасом.

Далее мы будем разбирать его:

Алгоритм серверного рендера

Создание сервера

/build/server/index.js

const createServer = require('vqua-server') const layout = require('./layout') const initRoutes = require('../build/initializers/initRoutes') initRoutes().then(routes => { const app = createServer({ routes, layout, publicPath: './dist', componentPath: './build/containers', }) app.listen(8000) }) process.on('unhandledRejection', error => { console.log('unhandledRejection', error) });

Сервер принимает запрос, и находит соответствующий ему маршрут и контроллер.

Подробнее о создании сервера

Контроллер

/build/controllers/WelcomeController.js

class WelcomeController { index(req, res) { res.send(200, 'WelcomeContainer', { props: {}, context: {} }) } } module.exports = WelcomeController

Контроллер возвращает код ответа, название компонента и его параметры.

После этого сервер находит в папке /build/containers запрашиваемый компонент и создает из него виртуальное дерево. На основе этого дерева он создает html строку, помещает ее в ваш основной шаблон (layout) и отправляет запрос браузеру.

Также вместе с основным шаблоном в теге script#app-cache сервер размещает JSON строку с данными из request.send(). Делается это для того чтобы в браузере не вызывать контроллер лишний раз.

Браузерная навигация

/build/index.js

const { render } = require('vqua') const Navigation = require('vqua-navigation') const initRoutes = require('./initializers/initRoutes') initRoutes().then(routes => { let liveNodes = [] const navigation = new Navigation(routes) navigation.onNavigate(({ path, statusCode, componentName, params }) => { const $app = document.getElementById('app') const Component = require('./containers/' + componentName) const context = Object.assign(params.context, { navigate: navigation.navigate.bind(navigation) }) const templateNodes = [ Component.v(params.props, context) ] liveNodes = render($app, liveNodes, templateNodes, context) }) navigation.onRedirect(({ redirectPath, statusCode, params }) => { window.history.pushState({}, '', redirectPath) navigation.navigate(redirectPath) }) const $cache = document.getElementById('app-cache') const cache = $cache.innerHTML $cache.parentNode.removeChild($cache) navigation.navigate(window.location.pathname, cache) window.onpopstate = (event) => { navigation.navigate(window.location.pathname) } })

Браузер получил ответ от сервера. Теперь нам надо построить два виртуальных дерева.

1-ое дерево мы строим на основе DOM который предоставил нам браузер.

2-ое дерево мы строим на основе JSON кеша контроллера из тега script, упомянутом выше.

Теперь метод render сравнит два дерева и восстановит между ними разницу. А именно, навесит недостающие события, и пройдет полностью по всему жизненному цилку колбеков каждого компонента.

Подробнее о браузерной навигации