Если вы веб-разработчик, то скорее всего, слышали о таком термине как "JAM stack". Нет, он не имеет никакого отношения к тостам с джемом. К тому моменту как вы закончите читать эту статью, вы будете иметь представление о том, что такое JAMstack и какие у него преимущества, а также узнаете как самому сделать сайт на JAMstack. Приступим.
Быстрая навигация
"JAM" в JAMstack означает JavaScript, API и разметка(markup). Архитектура JAMstack делает веб-приложения дешевле в разработке, производительней и безопаснее.
JAMstack не заставляет вас переходить на какую-либо конкретную технологию. Вы можете использовать любую JavaScript библиотеку c которой привыкли работать (TypeScript, Elm, Clojure или WebAssembly), получать данные или отправлять обновления от сторонних или ваших собственных API. Для управления контентом можно выбрать один из множества генераторов статических сайтов, таких как Hugo, GatsbyJS, Jekyll, Next.js, Nuxt.js или VuePress, и писать контент с помощью Markdown или любой другой системы разметки, которая отображает как HTML.
1JAMstack — быстрый, масштабируемый, не дорогой
Традиционные веб-приложения и CMS полагаются на серверный код, который отправляет HTML в ответ на каждый запрос пользователя. Часто подобные системы включают базу данных и тем самым добавляют еще один уровень задержки. Масштабировать традиционную систему с большим количеством серверов — не такая простая задача. Добавьте к этому сложность кэширования и получается настоящая головная боль.
При использовании JAMstack`a каждая страница создается (компилируется) заранее, когда приложение развертывается. Все HTML, JavaScript, CSS и изображения, необходимые для приложения, сразу полностью готовы. Задача состоит в том, чтобы выполнять как можно меньше кода на стороне сервера, поскольку обслуживание статических файлов происходит быстрее и намного проще.
Файлы статических сайтов могут быть дополнительно глобально кэшированы в CDN. В таком случае посетители получат контент с серверов, расположенных ближе всего к ним, что может оказать большое влияние на usability и конверсию.
отличие статических и динамических сайтовJAMstack, к тому же, не имеет проблем с безопасностью, ведь статические файлы доступны только для чтения и не подвержены атакам со стороны. Нет кода для запуска, поэтому нет уязвимостей для использования.
2Создаем JAMstack с генератором статических сайтов Hugo
Начало разработки JAMstack приложений часто начинается с решения о том, как управлять контентом и генерировать статические ресурсы. Есть много вариантов, доступных практически на каждом языке программирования.
- Next.js — язык JavaScript
- Jekyll — язык Ruby
- Hugo — язык Go
- Gatsby — язык JavaScript
- Hexo — язык JavaScript
- Nuxt — язык JavaScript
- GitBook — язык JavaScript
- VuePress — язык JavaScript
- Docusaurus — язык JavaScript
- Pelican — язык Python
- MkDocs — язык Python
- и другие
В этой статье мы будем использовать генератор статических сайтов Hugo. Он очень быстрый и гибкий. Он написан на Go, но вряд ли вам нужно будет выучить язык Go, чтобы настроить его для своих нужд.
Необходимый софт и компоненты:
- В зависимости от вашей операционной системы:
Windows: Chocolatey
macOS: Homebrew
Linux: Linuxbrew - Система контроля версий Git
- Если у вас еще нет любимого редактора кода, установите Visual Studio Code
- Бесплатный Okta Developer Account
Установка Chocolatey в Windows
В меню Пуск найдите PowerShell и откройте его от имени администратора. Затем вставьте следующий сценарий и нажмите Enter.
PowerShell
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Установка Chocolatey окончена, в PowerShell должно быть написано Chocolatey (choco.exe) is now ready.
Устанавливаем Hugo
Первым делом установим Hugo. Hugo - это приложение интерфейса командной строки (CLI), которое запускается в командной строке или терминале. Откроем командную строку от имени администратора.
Chocolatey (Windows)
BASH
choco install hugo -confirm
Homebrew или Linuxbrew
BASH
brew install hugo
Создаем новое Hugo приложение
В командной строке перейдите в папку, в которой вы хотите сохранить свое приложение. К примеру, cd c:\Repository. Затем скопируйте и вставьте строку ниже, нажмите Enter
BASH
hugo new site jamstack-app
Эта команда создаст новую папку с именем jamstack-app
Добавим тему для Hugo используя Git
Существует большое количество прекрасных тем для Hugo, посмотрите сами на https://themes.gohugo.io. В этой статье мы будем использовать Tranquilpeak
BASH
cd jamstack-app
git init
git submodule add https://github.com/kakawait/hugo-tranquilpeak-theme.git themes/hugo-tranquilpeak-theme
Если вы не забыли установить Git, то в каталоге themes появится папка hugo-tranquilpeak-theme с таким содержимым:
Обновляем конфигурацию Hugo
Откройте проект jamstack-app в вашем любимом редакторе кода. В папке /themes/hugo-tranquilpeak-theme/exampleSite откройте файл config.toml и скопируйте все что там находится.
Затем откройте файл /config.toml из корневой папки и вставьте туда ранее скопированный код. Обновите заголовок и имя автора.
Создадим новый пост на сайте
Чтобы создать пост используем Hugo CLI
BASH
hugo new post/hello-world.md
Перейдем в редактор, там уже будет создан наш пост /content/post/hello-world.md. Для управления контентом Hugo использует Markdown. В верхней части MD файла находятся метаданные поста, добавьте какой-нибудь контент под ними и сохраните файл.
MD
---
title: "Hello World"
date: 2019-11-04T14:23:25+03:00
categories:
- category
- subcategory
tags:
- tag1
- tag2
keywords:
- tech
#thumbnailImage: //example.com/image.jpg
---
Привет! Это мой первый пост на Hugo!
Запускаем Hugo сервер
Вернемся в командную строку и запустим веб сервер. Hugo построит сайт и запустит локальный веб сервер, который мы будем использовать для тестирования.
BASH
hugo server -D
Откройте ваш браузер, в адресную строку вставьте url из терминала. По умолчанию он должен быть http://localhost:1313. Вернитесь обратно в редактор, поменяйте что-нибудь в тексте и сохраните файл. Hugo обнаруживает изменения и автоматически обновляет ваш сайт в браузере.
3JavaScript и API
Букву M (Markup) из JAM мы немного разобрали. Теперь поговорим о J (JavaScript) и A (API). Файлы статичны на стороне сервера, но когда будут доставлены на клиент, они будут настолько динамичны, насколько вы этого захотите.
При разработке веб-приложений наибольшую головную боль вызывает управление учетными записями пользователей и контроль доступа к защищенным данным. Такие функции как регистрация пользователей, вход в систему, сброс пароля, управление профилем реализовать самостоятельно не так просто. К счастью есть сторонние приложения, которые можно подключить к своему приложению и избавиться от всех забот.
4Добавляем аутентификацию Okta
С помощью Okta мы сможем добавить аутентификацию, авторизацию в приложение за несколько минут. Первый шаг - зарегистрировать бесплатный аккаунт разработчика.
Создаем приложение Okta
После того, как вы зарегистрировались зайдите в панель управления и нажмите Applications, затем Add Application.
Нажмите Native. Этот параметр поддерживает последний, более безопасный стандарт Proof Key for Code Exchange (PKCE). Затем нажмите Next.
В поле Name запишем имя нашего приложения, а в Login redirect URIs наш url http://localhost:1313. И жмем Done
Скопируем Client ID
Вы окажитесь на странице настроек приложения. Внизу будет раздел Client Credentials. Скопируйте Client ID и сохраните где-нибудь под рукой, он нам еще понадобится.
Добавляем Trusted Origin
Чтобы приложение Hugo могло обмениваться информацией с Okta, нужно добавить в Okta url адрес приложения. Сначала нажмите на вкладку API и выберите Trusted Origins.
Далее нажмите Add Origin, впишите название вашей организации в поле Name. Замените Origin URL вашим http://localhost:1313. Отметьте галочками CROS и Redirect. Нажмите Save.
Включаем Self-Service Registration
Этот пункт необходимо включить, чтобы разрешить пользователям создавать собственные учетные записи. Для этого нажмите на вкладку Users и далее Registration.
Жмем кнопку Enable Registration. В появившейся форме убедимся, что в поле Self-service registration стоит Enabled.
Копируем Organization URL
Осталось только получить только URL организации. Нажмите вкладку Dashboard. Вы увидите его в правой части экрана, также сохраните его под рукой.
5Добавляем Okta Login в Hugo
Теперь, когда Okta настроен, мы можем добавить регистрацию и войти на свой Hugo сайт. Сейчас мы кастомизируем шаблон, создадим страницу входа и добавим Sign-In виджет Okta.
Добавляем настройки Okta в конфигурацию Hugo
Открываем файл /config.toml и найдите раздел # Menu Configuration. После пункта меню About добавьте такую конфигурацию:
TOML
[[menu.main]]
weight = 6
identifier = "login"
name = "Login"
pre = "<i class=\"sidebar-button-icon fa fa-lg fa-lock\"></i>"
url = "/login"
В самом конце файла config.toml, добавьте новую секцию [params.okta] с информацией ниже. Замените {yourOktaClientId} и {yourOktaOrgUrl} на значения, которые вы записали ранее.
TOML
[params.okta]
clientId = "{yourOktaClientId}"
baseUrl = "{yourOktaOrgUrl}"
redirectUri = "http://localhost:1313/login/"
Добавляем файлы JavaScript
В папке /static, создайте новую папку с именем js. В этой папке создайте новый файл с именем okta-login.js и добавьте в него JavaScript, который вы видите ниже. Это JS код будет использован только на странице входа.
JS
// с помощью jQuery дождемся окончания загрузки документа
$(document).ready(function () {
// подхватим конфигурацию Okta из /layouts/partials/script.html
var config = window.okta.config;
// создаем экземпляр виджета Sign-In Okta
var signIn = new OktaSignIn({
clientId: config.clientId, // обязательно
baseUrl: config.baseUrl, // обязательно
redirectUri: config.redirectUri, // обязательно
authParams: {
display: 'page',
responseType: 'code',
grantType: 'authorization_code'
},
features: {
registration: true // разрешаем регистрацию пользователя
}
});
// проверяем не является ли текущий запрос обратным перенаправлением с Okta login
function isRedirect() {
return /((code|state)=)/.test(window.location.hash);
}
// Получаем сессию входа
function getSession() {
return signIn.authClient.session.get()
.then(function (session) {
if (session.status === "ACTIVE") {
return session.user().then(function (user) {
return {
session,
user
}
});
}
return { session, user: {} };
})
.catch(function (err) {
console.error("session error", err);
});
}
function showWelcomeMessage(profile) {
$('#okta-login-firstname').html(profile.firstName)
$('#okta-login-success').show();
}
// функция клика для кнопки выхода
$('#okta-sign-out').click(function() {
signIn.authClient.session.close().then(function() {
location.reload();
});
});
if (isRedirect()) {
// Парсим токен полученный от Okta
signIn.authClient.token.parseFromUrl()
.then(function (res) {
var accessToken = res[0];
var idToken = res[1];
// set tokens for the active session
signIn.authClient.tokenManager.add('accessToken', accessToken);
signIn.authClient.tokenManager.add('idToken', idToken);
// используем Okta API чтобы получить текущего пользователя
return getSession()
.then(function(res) {
// показываем приветственное сообщение
showWelcomeMessage(res.user.profile);
})
.catch(function (err) {
console.error("getSession error", err);
});
})
.catch(function (err) {
console.error("parseFromUrl error", err);
});
} else {
// Пробуем получить сессию
getSession()
.then(function(res) {
if (res.session.status === 'ACTIVE') {
// Показываем приветственное сообщение, если сессия активна
showWelcomeMessage(res.user.profile);
return;
}
// Показываем форму входа, если сессия не активна
signIn.renderEl({ el: '#okta-login-container' });
})
.catch(function(err){
console.error(err);
});
}
});
Добавьте новый файл с именем okta.js в папку /static/js вставьте туда JS, который видите ниже. Этот код будет использоваться на всем сайте, кроме страницы входа.
JS
// с помощью jQuery дождемся окончания загрузки документа
$(document).ready(function () {
// Создать экземпляр Sign-In виджета Okta
var config = window.okta.config;
var signIn = new OktaSignIn({
clientId: config.clientId,
baseUrl: config.baseUrl,
redirectUri: config.redirectUri
});
// функция для получения активной сессии, если такая есть
function getSession() {
return signIn.authClient.session.get()
.then(function (session) {
if (session.status === "ACTIVE") {
return session.user().then(function (user) {
return {
session,
user
}
});
}
return { session, user: {} };
})
.catch(function (err) {
console.error("session error", err);
});
}
function showWelcomeMessage(profile) {
$('#okta-info .firstName').html(profile.firstName);
$('#okta-info').show();
}
// показываем приветственное сообщение, если есть активная сессия
getSession()
.then(function(res) {
if (res.session.status === 'ACTIVE') {
showWelcomeMessage(res.user.profile);
}
})
.catch(function(err){
console.error(err);
});
});
Настраиваем тему
В папке /layouts создадим еще одну папку с именем partials и внутри добавим файл okta-login.html. И внутри вставим следующий HTML:
HTML
<div id="okta-login-container"></div>
<div id="okta-login-success" style="display:none;">
<h2>Welcome, <span id="okta-login-firstname"></span>!</h2>
<p>You are currently logged in.</p>
<p><button id="okta-sign-out">Sign Out</button></p>
</div>
В папке /layouts создайте новую директорию с именем login. И в /layouts/login добавьте новый файл login.html с кодом ниже.
HTML
{{ partial "head.html" . }}
<body>
<div id="blog">
{{ partial "header.html" . }}
{{ partial "sidebar.html" . }}
{{ partial "post/header-cover.html" . }}
<div id="main" data-behavior="{{ .Scratch.Get "sidebarBehavior" }}"
class="{{ with .Params.coverimage }}hasCover{{ end }}
{{ if eq .Params.covermeta "out" }}hasCoverMetaOut{{ else }}hasCoverMetaIn{{ end }}
{{ with .Params.coverCaption }}hasCoverCaption{{ end }}">
<article class="post">
<div class="post-header main-content-wrap {{ if $.Params.metaalignment }}text-{{ $.Params.metaalignment }}{{ else }}text-left{{ end }}">
<h1 class="post-title" itemprop="headline">
{{ $.Title }}
</h1>
{{ partial "okta-login.html" . }}
</div>
{{ partial "footer.html" . }}
</article>
</div>
</div>
{{ partial "foot.html" . }}
По сути это тот же файл шаблона, что и /themes/hugo-tranquilpeak-theme/layouts/_default/single.html, но с измененным кодом внутри, включая $.Title и новый partial "okta-login.html.
Правим шаблон темы
Далее мы сделаем копии еще трех файлов и изменим их. Когда Hugo рендерит сайт, он сначала ищет файлы шаблонов в папке /layouts. Любой файл, найденный в этой папке переопределяет файл с таким же названием из папки /themes/hugo-tranquilpeak-theme/layouts/
Добавьте новый файл в /layouts/partials, назовите его script.html. Откройте исходный файл script.html, расположенный по адресу /themes/hugo-tranquilpeak-theme/layouts/partials/script.html, и скопируйте все содержимое в /layouts/partials/script.html. Затем в самом низу нового файла script.html добавьте следующую разметку.
HTML
{{ if ( isset .Site.Params "okta" ) }}
<script src="https://global.oktacdn.com/okta-signin-widget/3.1.0/js/okta-sign-in.min.js" type="text/javascript"></script>
<script>
window.okta = {
config: {
clientId: '{{ .Site.Params.okta.clientId }}',
baseUrl: '{{ .Site.Params.okta.baseUrl }}',
redirectUri: '{{ .Site.Params.okta.redirectUri }}'
}
}
</script>
{{ if eq ( replace ( .Permalink | relURL ) "/" "" ) "login" }}
<script src="/js/okta-login.js"></script>
{{ else }}
<script src="/js/okta.js"></script>
{{ end }}
{{ end }}
Добавьте новый файл в /layouts/partials, назовите его head.html. Как и в предыдущем шаге, копируем HTML из /themes/hugo-tranquilpeak-theme/layouts/partials/head.html в новый head.html. Добавьте HTML, который вы видите ниже перед тегом {{ partial "head_end.html" . }}.
HTML
{{ if .Site.Params.okta }}
<link href="https://global.oktacdn.com/okta-signin-widget/3.1.0/css/okta-sign-in.min.css" type="text/css" rel="stylesheet"/>
{{ end }}
Создайте новый файл в /layouts/partials с названием footer.html. И добавьте следующий HTML код.
HTML
<footer id="footer" class="main-content-wrap">
<div id="okta-info" style="display: none; text-align: center;">
Hi, <span class="firstName"></span>!
</div>
<span class="copyrights">
© {{ now.Format "2006" }} {{ with .Site.Params.footer.copyright }}{{ . | safeHTML }}{{ else }}{{ with .Site.Author.name }}{{ . }}{{ else }}{{ with .Site.Title }}{{ . }}{{ end }}{{ end }}{{ end }}. {{ i18n "footer.all_rights_reserved" }}
</span>
</footer>
Добавляем Placeholder для страницы входа
В папке /content создайте файл с именем login.html. Добавьте следующую разметку в этот файл.
TOML
---
title: Login
type: login
layout: login
---
Тестируем новую страницу входа
Наконец, мы готовы к тестированию! Запустите сервер Hugo, если еще не сделали этого и перейдите по адресу http://localhost:1313. Если все сделано правильно, слева в меню вы увидите новый пункт Login. Нажмите на него, чтобы увидеть форму входа. Войдите в систему с учетной записью, которую вы регистрировали в Okta. Или попробуйте создать новую учетку с другим email.
После входа в свою учетку вы увидите приветственное сообщение на странице /login.
Вот и все, мы создали статический сайт на Hugo — полноценный блог и немного разобрали разницу между статическими и динамическими сайтами. Больше информации по этой теме ожидайте в следующих статьях.