Нам не нужно никакого дорожного движения, Нам не нужно никакого SEO, В вашей сети нет обмена ссылками, Спамеры! оставь нас всех в покое.Теги: #Next.js #react.js #node.js #Universal #изоморфное #веб-приложение #SEO #SEO #учебник #Разработка веб-сайтов #JavaScript #node.js #react.js #поисковая оптимизацияАнна Филина
Немного истории
Еще в 2013 году Спайк Брем из Airbnb опубликовал программное обеспечение статья , в которой он проанализировал недостатки SPA-приложений (Single Page Application) и в качестве альтернативы предложил модель изоморфных веб-приложений.В настоящее время чаще используется термин универсальное веб-приложение (см.
обсуждение ).
В универсальном веб-приложении каждая страница может генерироваться как веб-сервером, так и JavaScript на стороне веб-браузера.
При этом исходный код программ, исполняемых веб-сервером и веб-браузером, должен быть единообразным (универсальным), чтобы исключить несогласованность и увеличение затрат на разработку.
История с инициатором идеи Спайком Бремом из Airbnb сейчас завершилась полной победой, причем недавно, 7 декабря 2017 года.
в твоем Твиттере он сообщил, что веб-сайт Airbnb перешел на серверный рендеринг SPA-приложений.
Критика приложений SPA
Что не так со SPA-приложениями? А какие проблемы возникают при разработке универсальных приложений? Приложения SPA критикуются в первую очередь за их низкий рейтинг в поисковых системах (SEO), скорость и доступность.(Это относится к доступности, как она понимается в документе https://www.w3.org/Translations/WCAG20-ru .
Есть интеллект что приложения React могут быть недоступны для программ чтения с экрана.
) Частично вопрос с SEO SPA-приложений решает Prerender — сервер с «безголовым» веб-браузером, который реализован с помощью chrome-remote-interface (ранее использовался phantomjs).
Вы можете развернуть свой собственный сервер с помощью Prerender или связаться Государственная служба .
В последнем случае доступ будет бесплатным с ограничением количества страниц.
Процесс генерации страницы с помощью Prerender занимает много времени — обычно более 3 секунд, а это значит, что поисковые системы посчитают такой сервис не оптимизированным по скорости, и его рейтинг все равно будет низким.
Проблемы с производительностью могут не проявиться в процессе разработки и стать заметными при работе с низкоскоростным Интернетом или на маломощном мобильном устройстве (например, телефоне или планшете с 1 ГБ оперативной памяти и частотой процессора 1,2 ГГц).
В этом случае «летающая» страница может загружаться неожиданно долго.
Например, одна минута.
Причин такой медленной загрузки больше, чем обычно приводятся.
Для начала разберемся, как приложение загружает JavaScript. Если скриптов много (что было характерно при использовании модулей require.js и amd), то время загрузки увеличивается из-за накладных расходов на подключение к серверу для каждого из запрошенных файлов.
Решение было очевидным: объединить все модули в один файл (с помощью rjs, webpack или другого компоновщика).
Это создало новую проблему: для веб-приложения с богатым интерфейсом и логикой при загрузке первой страницы загружался весь код JavaScript, объединенный в один файл.
Таким образом, современная тенденция разделение кода .
Мы вернемся к этому вопросу, когда будем рассматривать необходимый функционал для создания универсальных веб-приложений.
Вопрос не в том, что это невозможно или сложно сделать.
Вопрос в том, что желательно иметь инструменты, которые делают это оптимально и без дополнительных усилий со стороны разработчика.
И наконец, когда весь код JavaScript загружен и интерпретирован, начинается построение DOM документа и.
наконец начинается загрузка изображений.
Библиотеки для создания универсальных приложений
На github.com сейчас можно найти большое количество проектов, реализующих идею универсального веб-приложения.Однако все эти проекты имеют общие недостатки:
Первым успешным решением стала библиотека Next.js, которая по состоянию на 14 января 2018 года имеет 338 участников и 21 137 «звездочек» на github.com. Чтобы оценить преимущества этой библиотеки, давайте рассмотрим, какой конкретно функционал необходимо обеспечить для работы универсального веб-приложения.
- небольшое количество участников проекта
- это шаблоны проектов для быстрого старта, а не библиотеки
- проекты не обновлялись при выпуске новых версий act.js
- проекты реализуют лишь часть функционала, необходимого для разработки универсального приложения.
Серверный рендеринг
Такие библиотеки, как act.js, vue.js, angular.js, riot.js и другие, поддерживают рендеринг на стороне сервера.Серверный рендеринг обычно работает синхронно.
Это значит, что асинхронные запросы API в событиях жизненного цикла будут выполняться, но их результат будет утерян.
(Ограниченная поддержка асинхронного серверного рендеринга обеспечивается Riot.js)
Асинхронная загрузка данных
Чтобы гарантировать получение результатов асинхронных запросов до начала рендеринга сервера, Next.js реализует специальный тип компонента страницы, который имеет асинхронное событие жизненного цикла.статический асинхронный getInitialProps({req}) .
Передача состояния компонента сервера клиенту
Когда компонент отображается на сервере, HTML-документ отправляется клиенту, но состояние компонента теряется.Для передачи состояния компонента обычно веб-сервер генерирует скрипт для веб-браузера, который записывает состояние серверного компонента в глобальную переменную JavaScript.
Создание компонента на стороне веб-браузера и привязка его к HTML-документу.
HTML-документ, полученный в результате рендеринга компонента на стороне сервера, содержит текст и не содержит компонентов (объектов JavaScript).
Компоненты необходимо воссоздать в веб-браузере и «связать» с документом без повторного рендеринга.
В реакции.
js для этого используется метод гидрат().
Похожий по функциям метод доступен в библиотеке vue.js.
Маршрутизация
Маршрутизация на сервере и на клиенте также должна быть универсальной.То есть одно и то же определение маршрутизации должно работать как для серверного, так и для клиентского кода.
Разделение кода
Для каждой страницы следует загружать только необходимый код JavaScript, а не все приложение.При переходе на следующую страницу недостающий код должен быть загружен — без повторной загрузки тех же модулей и без ненужных модулей.
Все эти задачи успешно решает библиотека Next.js. Эта библиотека основана на очень простой идее.
Предлагается ввести новый тип компонента — «страница», имеющий асинхронный метод static async getInitialProps({req}).
Компонент страницы — это обычный компонент React. Вы можете думать об этом типе компонента как о новом типе в серии: «компонент», «контейнер», «страница».
Рабочий пример
Для работы нам понадобится node.js и менеджер пакетов npm. Если они еще не установлены, проще всего это сделать с помощью nvm (Node Version Manager), который устанавливается из командной строки и не требует доступа sudo:После установки обязательно закройте и снова откройте терминал, чтобы установить переменную среды PATH. Команда отображает список всех доступных версий:curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
nvm ls-remote
Загрузите необходимую версию node.js и совместимую версию менеджера пакетов npm с помощью команды:nvm install 8.9.4
Создайте новый каталог (папку) и запустите в нем команду:npm init
В результате будет создан файл пакет.json .Загрузите и добавьте необходимые пакеты в зависимости проекта:
npm install --save axios next next-redux-wrapper react react-dom react-redux redux redux-logger
В корневом каталоге проекта создайте каталог страницы .Этот каталог будет содержать компоненты типа страницы.
Путь к файлам внутри каталога страницы соответствует URL , по которому эти компоненты будут доступны.
Как обычно, «волшебное имя» index.js отображается на URL /индекс И / .
Более сложные правила для URL с подстановочным знаком также возможны.
Создать файл страницы/index.js :
import React from 'react' export default class extends React.Component { static async getInitialProps({ req }) { const userAgent = req ? req.headers['user-agent'] : navigator.userAgent return { userAgent } } render() { return ( <div> Hello World {this.props.userAgent} </div> ) } }
Этот простой компонент использует основные возможности Next.js:В файл пакет.json Добавьте в атрибут «scripts» три команды:
- Синтаксис es7 (импорт, экспорт, асинхронный, класс) доступен «из коробки».
- Горячая перезагрузка также работает «из коробки».
- Функция статический асинхронный getInitialProps({req}) будет выполняться асинхронно перед рендерингом компонента на сервере или клиенте — и только один раз.
Если компонент отображается на сервере, ему передается параметр требование .
Функция вызывается только для компонентов типа «страница» и не вызывается для вложенных компонентов.
"scripts": { "dev": "next", "build": "next build", "start": "next start" }
Запустите сервер разработки командой:npm run dev
Чтобы реализовать переход на другую страницу без загрузки страницы с сервера, ссылки оборачиваются специальным компонентом.Связь .
добавить в страница/index.js зависимость:
import Link from 'next/link'
и компонент Link:<Link href="/time"> <a>Click me</a> </Link>
При нажатии на ссылку откроется страница с ошибкой 404. Скопируйте файл страницы/index.js подать страницы/time.js .В новом компоненте time.js мы будем отображать текущее время, полученное асинхронно с сервера.
А пока измените ссылку в этом компоненте, чтобы она вела на главную страницу:
<Link href="/"> <a>Back</a> </Link>
Попробуйте перезагрузить каждую страницу с сервера несколько раз, а затем перейти с одной страницы на другую и вернуться обратно.Во всех случаях загрузка с сервера будет выполняться с помощью рендеринга на стороне сервера, а все последующие переходы будут выполняться с помощью рендеринга на стороне веб-браузера.
На странице страницы/time.js Разместим таймер, показывающий текущее время, полученное с сервера.
Это позволит вам познакомиться с асинхронной загрузкой данных при серверном рендеринге — то, что отличает Next.js от других библиотек.
Чтобы хранить данные в магазин давайте использовать сокращение .
Асинхронные действия в сокращение выполняется с использованием промежуточного программного обеспечения Redux-thunk .
Обычно (но не всегда) одно асинхронное действие имеет три состояния: СТАРТ, УСПЕХ, НЕУДАЧА .
Поэтому код определения асинхронного действия часто выглядит (по крайней мере, для меня) сложным.
В одном номере библиотеки редукс-thunk обсуждалась упрощенная версия промежуточного программного обеспечения, позволяющая определить все три состояния в одной строке.
К сожалению, эта опция так и не была скомпилирована в библиотеку, поэтому мы включим ее в наш проект как модуль.
Создать новый каталог сокращение в корневом каталоге приложения, а в нем - файл сокращение/обещанныйMiddlewate.js :
export default (.
args) => ({ dispatch, getState }) => (next) => (action) => { const { promise, promised, types, .
rest } = action; if (!promised) { return next(action); } if (typeof promise !== 'undefined') { throw new Error('In promised middleware you mast not use "action".
"promise"'); } if (typeof promised !== 'function') { throw new Error('In promised middleware type of "action".
"promised" must be "function"'); } const [REQUEST, SUCCESS, FAILURE] = types; next({ .
rest, type: REQUEST }); action.promise = promised() .
then( data => next({ .
rest, data, type: SUCCESS }), ).
catch( error => next({ .
rest, error, type: FAILURE }) ); };
Несколько пояснений о том, как работает эта функция.функция промежуточного программного обеспечения сокращение есть подпись (сохранить) => (следующий) => (действие) .
Индикатором того, что действие асинхронно и его должна обрабатывать именно эта функция, является свойство обещал .
Если это свойство не определено, то обработка заканчивается и управление передается следующему промежуточному программному обеспечению: вернуться дальше (действие) .
В собственности действие.
обещание ссылка на объект сохраняется Обещать , что позволяет «держать» асинхронную функцию статический асинхронный getInitialProps({req, store}) пока асинхронное действие не завершится.
Все, что связано с хранением данных, мы поместим в файл.
сокращение/store.js :
import { createStore, applyMiddleware } from 'redux'; import logger from 'redux-logger'; import axios from 'axios'; import promisedMiddleware from '.
/promisedMiddleware'; const promised = promisedMiddleware(axios); export const initStore = (initialState = {}) => { const store = createStore(reducer, {.
initialState}, applyMiddleware(promised, logger)); store.dispatchPromised = function(action) { this.dispatch(action); return action.promise; } return store; } export function getTime(){ return { promised: () => axios.get(' http://time.jsontest.com/ '), types: ['START', 'SUCCESS', 'FAILURE'], }; } export const reducer = (state = {}, action) => { switch (action.type) { case 'START': return state case 'SUCCESS': return {.
state, .
action.data.data} case 'FAILURE': return Object.assign({}, state, {error: true} ) default: return state } }
Действие getTime() будет обработан обещанное промежуточное ПО() .Для этого в свойстве обещал задана функция, которая возвращает Обещать , и в собственности типы - массив из трех элементов, содержащих константы «СТАРТ», «УСПЕХ», «НЕУДАЧА» .
Значения констант могут быть произвольными; их порядок в списке важен.
Теперь осталось только применить эти действия в компоненте страницы/time.js :
import React from 'react'; import {bindActionCreators} from 'redux'; import Link from 'next/link'; import { initStore, getTime } from '.
/redux/store'; import withRedux from 'next-redux-wrapper'; function mapStateToProps(state) { return state; } function mapDispatchToProps(dispatch) { return { getTime: bindActionCreators(getTime, dispatch), }; } class Page extends React.Component { static async getInitialProps({ req, store }) { await store.dispatchPromised(getTime()); return; } componentDidMount() { this.intervalHandle = setInterval(() => this.props.getTime(), 3000); } componentWillUnmount() { clearInterval(this.intervalHandle); } render() { return ( <div> <div>{this.props.time}</div> <div> <Link href="/"> <a>Return</a> </Link> </div> </div> ) } } export default withRedux(initStore, mapStateToProps, mapDispatchToProps)(Page);
Обратите внимание, что здесь используется метод сРедуксом() из библиотеки следующая-редуцированная-обертка .Все остальные библиотеки являются общими для реакции.
js и не требуют адаптации к Next.js. Когда я впервые познакомился с библиотекой Next.js, она меня не очень впечатлила из-за довольно примитивной маршрутизации из коробки.
Мне показалось, что применимость этой библиотеки не выше сайтов-визиток.
Сейчас я уже так не думаю и планировал рассказать о библиотеке в этой же статье.
следующие маршруты , что существенно расширяет возможности маршрутизации.
Но теперь я понимаю, что этот материал лучше вынести в отдельный пост. А еще мы планируем поговорить о библиотеке реакция-i18next , который - внимание! — не имеет прямого отношения к Next.js, но очень хорошо подходит для совместного использования.
[email protected] 14 января 2018 г.
-
Как Легко Конвертировать Dvd Во Flash-Видео
19 Oct, 24 -
Разбивка Стоимости Веб-Хостинга
19 Oct, 24 -
Атомный Планшет Odeon Tpc-10, Часть Вторая
19 Oct, 24 -
Дизайнеры Apple Подождут
19 Oct, 24