Если вы прочитали все статьи серии про создание статичного сайта Svelte на Yandex Cloud и выполнили все инструкции, которые там были, то вероятно у вас уже есть готовый сайт на своем домене, работающий по протоколу https, файлы которого вы выгружаете в объектное хранилище с помощью удобного графического S3-клиента.

В последнем материале мы как раз настраивали синхронизацию в программе S3 Browser. Синхронизация позволит нам тратить меньше времени на перекидывание сайта в Облако, а также контролировать, чтобы только обновленные и новые файлы и папки оказывались в бакете, а старые файлы удалялись.

Порядок работы

Опишу еще раз процесс от момента, когда у вас создается билд проекта на локальном компьютере, до его выгрузки в Облако.

  1. Итак, вы написали новую статью, изменили кое-где код или добавили новую функцию. Сохранили все изменения локально, отправили их в свой репозиторий на гитхабе (последнее не обязательно, так как у нас нет связи гита и Облака)
  2. Вы делаете билд проекта, то есть выполняете команду вроде npm run build.
  3. В папке вашего проекта создается, или заменяется новыми файлами, папка build.
  4. Вы открываете свой S3 Browser, заходите там в Tools > Folder Sync Tool.
  5. Если у вас там сохранено несколько заданий синхронизаций, то вы выбираете то, что отправит все файлы с локального компьютера в бакет. Идеально когда в этом задании у вас в качестве источника уже выбрана папка build, которая всегда имеет постоянный локальный адрес на вашем компьютере. В этом случае вам не придется постоянно выбирать новую папку.
  6. Вы нажимаете сначала кнопку Analyze, а потом Synchronize, после чего за несколько секунд ваш сайт в Yandex Cloud получит все обновления.
  7. Готово.

Это весьма нехитрая и несложная схема, которую может настроить любой пользователь. Наш сайт работает, обновляется, что еще нужно? Ответ на это вопрос банален и вынесен в заголовок статьи. Нам нужно исправить ошибку 404.

Ошибка 404

Вы спросите, зачем исправлять ошибку 404, ведь это обычная для всех сайтов ошибка, которая показывается, если в url введен адрес, которого на сайте нет. Это правда. Но при сочетании статичного сайта, созданного на JS-фреймворке, вроде Svelte, и хостинга на объектном хранилище, эта ошибка может возникнуть в совершенно неожиданном месте.

Ваша статика, если это не обыкновенный набор html-файлов, а современный продукт, созданный с помощью фреймворка, с большой долей вероятности, является SPA, то есть Single Page Application, или одностраничным приложением. Такой сайт использует единственный HTML-документ как оболочку для всех веб-страниц, а остальные страницы как-бы подгружаются динамически вместе со стилями, разметкой и скриптами, асинхронно, с помощью AJAX-подобных технологий.

Если на таком сайте, в неподготовленной среде, например, такой как наше Объектное хранилище в Облаке, перезагрузить любую страницу, кроме главной, то по умолчанию мы получим с вами ошибку 404. Допустим мы находимся на странице koltan.dev/blog, нажимаем кнопку обновить страницу в браузере и видим, что url в адресной строке остался таким же, но сама страница не загрузилась. Вы увидите ошибку 404, потому что в момент когда вы делаете рефреш страницы, у вас отключается динамический роутинг, и ваше статичное SPA-приложение не может получить страницу blog.html c того места, где она хранится.

Такой ошибки не возникнет, если мы перезагрузимся на главной странице. Вспомните, когда мы создавали наш бакет, указывали в разделе Веб-сайт два файла - Главная страница(index.html) и Страница ошибки(error.html). Бакет в данном случае точно знает, где у него находятся только две страницы.

Выгружаем статичный сайт Svelte на Yandex Cloud и решаем проблему 404 при перезагрузке страницы

При синхронизации локального билда и Облака, эти страницы у вас должны были удалиться, либо вы их сами предварительно удалили. Тем не менее, наш сайт Svelte имеет такую же главную страницу под названием index.html. Файла error.html у вас может не быть, либо вы могли его создать, либо назвать его другим именем (например, 404.html) и указать его в качестве Страницы ошибки в бакете. Но это все, конечно, не исправит проблему ошибки при перезагрузке.

Начало решения

Я долго и тщательно гуглил, и множество вариантов решения проблемы нашел. Я и менял опцию prerender в своем корневом макете, и менял adapter и даже вставлял кучу JS-кода в файл app.html своего сайта. Ничего не работало. Самый популярный совет в интернете: просто в настройках Веб-сайта в бакете в качестве страницы ошибки прописать ту же главную страницу, то есть index.html.

Что это даст? По крайней мере, позволит не шокировать человека, который случайно или намеренно перезагрузит любую страницу вашего сайта у себя в браузере. Вместо страницы с ошибкой 404, он увидит главную страницу. Однако нужно учесть при этом, что в адресной строке браузера останется url искомой страницы, в результате чего он не сможет воспользоваться кнопкой Назад, чтобы вернуться туда, где он был до перезагрузки. В общем, не самый лучший метод, хотя уже что-то.

Конечно хочется чтобы твой сайт был идеальным или почти идеальным, а такая проблема выбивает из колеи. Хоть отказывайся от SPA. И пока я колесил по стадиям принятия неизбежного от «отрицания» к «депрессии», через «гнев» и «торг», вспомнил, что у программистов, вместо последней стадии «принятия» часто встречается стадия «чтения документации». И я обратился к странице, где авторы Sveltekit рассказывают об одностраничном приложении, созданном на их инструментарии.

Почти победа

Ребята призывали в конфигурационном файле Sveltekit в параметре fallback прописать страницу, загружающую наше приложение и отправляющее его по нужному маршруту. Эта страница будет обрабатывать любые запросы, которые не соответствуют объектам в нашем хранилище. В моем случае, этой страницей является наша главная страница index.html.

Итак, первое, что я сделал, чтобы победить проблему 404, это убедился, что в моем бакете в настройке веб-сайта в качестве страницы ошибки указан тот же файл, что и в качестве главной страницы index.html.

Выгружаем статичный сайт Svelte на Yandex Cloud и решаем проблему 404 при перезагрузке страницы

Затем я исправил свой файл конфигурации Svelte, добавив к адаптеру опцию fallback.

svelte.config.js
import adapter from '@sveltejs/adapter-static';

const config = {
	kit: {
		adapter: adapter(
            {
                fallback: 'index.html' // вот она родимая
            }
        )
	},
};

После выгрузки билда своего сайта на Облако я получил нужный результат. Теперь при перезагрузке страницы я не оказывался на странице ошибки или на главной странице, а оставался на той же странице, где и был до перезагрузке. Остается только удивляться своей глупости и предусмотрительности разработчиков SvelteKit. А я еще не верил документации, где было написано, что в Svelte есть все, что позволит развернуть сайт на этом фреймворке на любой платформе.

Ложка дёгтя

Вышеописанными действиями мы справлись с проблемой 404 ошибки, при перезагрузке страницы нашего статичного SPA-сайта для пользователей. Он не будет удивлен, когда увидит не то, что планировал увидеть. Однако для тех, кто уважает SEO у меня плохие новости. Несмотря на то, что визуально все работает как нужно, браузер в консоли будет ловить ошибку 404, указывающую на отсутствие страницы после ее рефреша. Для SEO - это плохо. Я пока не нашел как решить эту проблему, возможно решение есть, но пока еще не пришло мне в голову или не попалось на глаза. На всякий случай пойду почитаю документацию, а если вы знаете, как найти решить эту проблему, то напишите мне в тг-бот.